Skip to content

Commit

Permalink
BREAKING CHANGE: fix the implementation of Axon Tries (#1580)
Browse files Browse the repository at this point in the history
* fix: add rlp encode for some key and value

* Update core/executor/src/adapter/backend/apply.rs

Co-authored-by: Flouse <1297478+Flouse@users.noreply.github.com>

---------

Co-authored-by: Flouse <1297478+Flouse@users.noreply.github.com>
  • Loading branch information
driftluo and Flouse authored Nov 27, 2023
1 parent 6ab0ae9 commit 527ccdf
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 133 deletions.
110 changes: 66 additions & 44 deletions core/api/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use protocol::types::{
Proposal, Receipt, SignedTransaction, TxResp, H160, H256, MAX_BLOCK_GAS_LIMIT, NIL_DATA,
RLP_NULL, U256,
};
use protocol::{async_trait, codec::ProtocolCodec, trie, ProtocolError, ProtocolResult};
use protocol::{async_trait, codec::ProtocolCodec, trie, ProtocolResult};

use core_executor::{
system_contract::metadata::MetadataHandle, AxonExecutor, AxonExecutorReadOnlyAdapter, MPTTrie,
Expand Down Expand Up @@ -239,10 +239,11 @@ where
let storage_mpt_tree = MPTTrie::from_root(account.storage_root, Arc::clone(&self.trie_db))?;

let hash: Hash = BigEndianHash::from_uint(&position);
storage_mpt_tree
let value: H256 = storage_mpt_tree
.get(hash.as_bytes())?
.map(Into::into)
.ok_or_else(|| APIError::Adapter("Can't find this position".to_string()).into())
.map(|v| BigEndianHash::from_uint(&U256::decode(v).unwrap()))
.unwrap_or(H256::zero());
Ok(Bytes::from(value.0.to_vec()))
}

async fn get_proof(
Expand All @@ -253,51 +254,72 @@ where
state_root: Hash,
) -> ProtocolResult<EthAccountProof> {
let state_mpt_tree = MPTTrie::from_root(state_root, Arc::clone(&self.trie_db))?;
let raw_account = state_mpt_tree
.get(address.as_bytes())?
.ok_or_else(|| APIError::Adapter("Can't find this address".to_string()))?;

let account = Account::decode(raw_account).unwrap();

let account_proof = state_mpt_tree
let account_proof: Vec<Hex> = state_mpt_tree
.get_proof(address.as_bytes())?
.into_iter()
.map(Hex::encode)
.collect();

let storage_mpt_tree = MPTTrie::from_root(account.storage_root, Arc::clone(&self.trie_db))?;

let mut storage_proofs = Vec::with_capacity(storage_position.len());

for h in storage_position {
let hash: Hash = BigEndianHash::from_uint(&h);
let proof = EthStorageProof {
key: hash,
value: storage_mpt_tree
.get(hash.as_bytes())?
.map(|v| H256::from_slice(&v))
.ok_or_else(|| {
Into::<ProtocolError>::into(APIError::Adapter(
"Can't find this position".to_string(),
))
})?,
proof: storage_mpt_tree
.get_proof(hash.as_bytes())?
.into_iter()
.map(Hex::encode)
.collect(),
};
storage_proofs.push(proof);
match state_mpt_tree.get(address.as_bytes())? {
Some(raw_account) => {
let account = Account::decode(raw_account).unwrap();

let storage_mpt_tree =
MPTTrie::from_root(account.storage_root, Arc::clone(&self.trie_db))?;

let mut storage_proofs = Vec::with_capacity(storage_position.len());

for h in storage_position {
let hash: Hash = BigEndianHash::from_uint(&h);
let storage_proof = storage_mpt_tree
.get_proof(hash.as_bytes())?
.into_iter()
.map(Hex::encode)
.collect();
let proof = match storage_mpt_tree.get(hash.as_bytes())? {
Some(v) => EthStorageProof {
key: h,
value: U256::decode(&v).unwrap(),
proof: storage_proof,
},
// key is not exist
None => EthStorageProof {
key: h,
value: U256::zero(),
proof: storage_proof,
},
};
storage_proofs.push(proof);
}
Ok(EthAccountProof {
address,
balance: account.balance,
code_hash: account.code_hash,
nonce: account.nonce,
storage_hash: account.storage_root,
account_proof,
storage_proof: storage_proofs,
})
}
None => {
// account is not exist
Ok(EthAccountProof {
address,
balance: U256::zero(),
code_hash: H256::zero(),
nonce: U256::zero(),
storage_hash: H256::zero(),
account_proof,
storage_proof: storage_position
.into_iter()
.map(|h| EthStorageProof {
key: h,
value: U256::zero(),
proof: Vec::new(),
})
.collect(),
})
}
}

Ok(EthAccountProof {
balance: account.balance,
code_hash: account.code_hash,
nonce: account.nonce,
storage_hash: account.storage_root,
account_proof,
storage_proof: storage_proofs,
})
}

async fn get_metadata_by_number(
Expand Down
20 changes: 19 additions & 1 deletion core/executor/src/adapter/backend/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,25 @@ where
};

storage.into_iter().for_each(|(k, v)| {
let _ = storage_trie.insert(k.as_bytes().to_vec(), v.as_bytes().to_vec());
// https://github.com/ethereum/go-ethereum/blob/ad16f11f841ab3a5fdedc8ddfc602f0717a34dd0/core/state/state_object.go#L306-L311
// if value is zero, delete it's key
if v == H256::zero() {
storage_trie
.remove(k.as_bytes())
.expect("Failed to remove entry with zero value from storage trie");
} else {
storage_trie
.insert(
k.as_bytes().to_vec(),
// https://github.com/ethereum/go-ethereum/blob/ad16f11f841ab3a5fdedc8ddfc602f0717a34dd0/core/state/state_object.go#L314
// Trim left zeroes and then rlp
U256::from_big_endian(v.as_bytes())
.encode()
.unwrap()
.to_vec(),
)
.expect("trie tree insert fail");
}
});

let storage_root = storage_trie
Expand Down
8 changes: 6 additions & 2 deletions core/executor/src/adapter/backend/read_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use evm::backend::Basic;
use protocol::traits::{Backend, Context, ExecutorReadOnlyAdapter, ReadOnlyStorage};
use protocol::trie::Trie as _;
use protocol::types::{
Account, Bytes, ExecutorContext, MerkleRoot, H160, H256, NIL_DATA, RLP_NULL, U256,
Account, BigEndianHash, Bytes, ExecutorContext, MerkleRoot, H160, H256, NIL_DATA, RLP_NULL,
U256,
};
use protocol::{codec::ProtocolCodec, trie, ProtocolResult};

Expand Down Expand Up @@ -172,7 +173,10 @@ where
} else {
MPTTrie::from_root(storage_root, Arc::clone(&self.db)).map(
|trie| match trie.get(index.as_bytes()) {
Ok(Some(res)) => H256::from_slice(res.as_ref()),
Ok(Some(res)) => {
let value = U256::decode(res).unwrap();
BigEndianHash::from_uint(&value)
}
_ => H256::default(),
},
)
Expand Down
15 changes: 8 additions & 7 deletions core/executor/src/adapter/trie/wrapped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,34 @@ use std::sync::Arc;
use hasher::HasherKeccak;

use protocol::trie::{PatriciaTrie, Trie, TrieError, DB as TrieDB};
use protocol::types::MerkleRoot;
use protocol::types::{Hasher, MerkleRoot};
use protocol::ProtocolResult;

pub struct MPTTrie<DB: TrieDB>(PatriciaTrie<DB, HasherKeccak>);

impl<DB: TrieDB> Trie<DB, HasherKeccak> for MPTTrie<DB> {
fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, TrieError> {
self.0.get(key)
self.0.get(&Hasher::digest(key).0)
}

fn contains(&self, key: &[u8]) -> Result<bool, TrieError> {
self.0.contains(key)
self.0.contains(&Hasher::digest(key).0)
}

fn insert(&mut self, key: Vec<u8>, value: Vec<u8>) -> Result<(), TrieError> {
self.0.insert(key, value)
self.0.insert(Hasher::digest(key).0.to_vec(), value)
}

fn remove(&mut self, key: &[u8]) -> Result<bool, TrieError> {
self.0.remove(key)
self.0.remove(&Hasher::digest(key).0)
}

fn root(&mut self) -> Result<Vec<u8>, TrieError> {
self.0.root()
}

fn get_proof(&self, key: &[u8]) -> Result<Vec<Vec<u8>>, TrieError> {
self.0.get_proof(key)
self.0.get_proof(&Hasher::digest(key).0)
}

fn verify_proof(
Expand All @@ -39,7 +39,8 @@ impl<DB: TrieDB> Trie<DB, HasherKeccak> for MPTTrie<DB> {
key: &[u8],
proof: Vec<Vec<u8>>,
) -> Result<Option<Vec<u8>>, TrieError> {
self.0.verify_proof(root_hash, key, proof)
self.0
.verify_proof(root_hash, &Hasher::digest(key).0, proof)
}
}

Expand Down
61 changes: 0 additions & 61 deletions core/executor/src/tests/system_script/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,64 +250,3 @@ fn test_set_ckb_related_info() {
assert_ne!(new_metadata_root, old_metadata_root);
});
}

// #[tokio::test]
// async fn update_consensus_config() {
// let config:
// crate::system_contract::metadata::metadata_abi::ConsensusConfig =
// ConsensusConfig { gas_limit: 0x3e7fffffc18,
// interval: 0xbb8,
// propose_ratio: 0xf,
// prevote_ratio: 0xa,
// precommit_ratio: 0xa,
// brake_ratio: 0xa,
// tx_num_limit: 0x4e20,
// max_tx_size: 0x186a0000,
// max_contract_limit: 0x8000u64,
// }
// .into();

// let tx_data =
// crate::system_contract::metadata::metadata_abi::UpdateConsensusConfigCall { config }
// .encode();

// send_eth_tx("http://127.0.0.1:8000", tx_data, METADATA_CONTRACT_ADDRESS).await
// }
// use ethers::prelude::*;
// use ethers::signers::{LocalWallet, Signer};
// use ethers::types::transaction::eip2718::TypedTransaction::Legacy;
// use ethers::types::{Address, TransactionRequest};

// const ADDRESS: &str = "0x8ab0CF264DF99D83525e9E11c7e4db01558AE1b1";
// const PRIVATE_KEY: &str =
// "37aa0f893d05914a4def0460c0a984d3611546cfb26924d7a7ca6e0db9950a2d"; pub async
// fn send_eth_tx(axon_url: &str, data: Vec<u8>, to: Address) { let provider
// = Provider::<Http>::try_from(axon_url).unwrap();

// let from: Address = ADDRESS.parse().unwrap();
// let nonce = provider.get_transaction_count(from, None).await.unwrap();

// let transaction_request = TransactionRequest::new()
// .chain_id(0x41786f6e)
// .to(to)
// .data(data)
// .from(from)
// .gas_price(1)
// .gas(21000)
// .nonce(nonce);

// let wallet = LocalWallet::from_str(PRIVATE_KEY).expect(
// "failed to create
// wallet",
// );
// let tx = Legacy(transaction_request);
// let signature: Signature = wallet.sign_transaction(&tx).await.unwrap();

// provider
// .send_raw_transaction(tx.rlp_signed(&signature))
// .await
// .unwrap()
// .await
// .unwrap()
// .expect("failed to send eth tx");
// }
Loading

0 comments on commit 527ccdf

Please sign in to comment.