Skip to content

Commit

Permalink
Merge branch 'eth-bridge-integration' into james+ray/ethbridge/merge-…
Browse files Browse the repository at this point in the history
…0.9.0

* eth-bridge-integration: (194 commits)
  [c hore]: rebasing
  Update shared/src/types/key/secp256k1.rs
  Update shared/src/types/vote_extensions/validator_set_update.rs
  [fix]: Adding changes from code review
  Update shared/src/types/eth_bridge_pool.rs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [fix]: Removed duplicated code block
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [chore]: rebasing on eth-bridge-integration
  [chore]: Rebase on previous branches
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  rebasing
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [fix]: Removed duplicated code block
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Upgrading to v0.8
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [chore]: rebasing on changes from previous feature prs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  rebasing
  [feat]: Added val set args for relaying to ethereum
  [feat]: Corrected the abi encodings of bridge proofs
  [fix]: Fixed bug that produced proof for values not in the bridge pool and covered with test
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Updated bridge pool vp with the the new merklized storage
  [chore]: Rebased onto PR #573
  [feat]: Changed the bridge pool vp to used the merklized storage
  [feat]: Updated bridge pool vp with the the new merklized storage
  [feat]: Changed the bridge pool vp to used the merklized storage
  [feat]: Updated bridge pool vp with the the new merklized storage
  [chore]: Rebasing on v0.8
  [fix]: Tiny from code review
  [fix]: Some more error logging and formatting
  Update shared/src/ledger/eth_bridge/vp/mod.rs
  [feat]: Added checks the bridge pool vp that erc20 tokens are escrowed to its account
  [feat]: Bridge pool vp now checks that funds to be transferred are escrowed. Needs tests
  [fix]: Tiny from code review
  [fix]: Some more error logging and formatting
  Update shared/src/ledger/eth_bridge/vp/mod.rs
  [feat]: Added a nomralized voting power type
  Update shared/src/types/key/secp256k1.rs
  Update shared/src/types/vote_extensions/validator_set_update.rs
  [fix]: Adding changes from code review
  Update shared/src/types/eth_bridge_pool.rs
  [feat]: Added checks the bridge pool vp that erc20 tokens are escrowed to its account
  Rename fvp to voting_power
  [chore]: Formatting
  [feat]: Bridge pool vp now checks that funds to be transferred are escrowed. Needs tests
  [chore]: Formatting
  [chore]: rebasing on eth-bridge-integration
  Remove TODO item
  [chore]: Rebase on previous branches
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  [feat]: Added recovery ids to secp256k1 signatures
  [chore]: Added unit tests to the queries and fixed bugs it found
  [feat]: Added query end points to get the contents of the eth bridge pool and request merkle proofs
  ...

# Conflicts:
#	Cargo.lock
#	apps/src/lib/node/ledger/rpc.rs
#	apps/src/lib/node/ledger/shell/queries.rs
#	shared/src/ledger/eth_bridge/bridge_pool_vp.rs
#	shared/src/ledger/protocol/transactions/ethereum_events/eth_msgs.rs
#	shared/src/ledger/protocol/transactions/ethereum_events/mod.rs
#	shared/src/ledger/protocol/transactions/votes.rs
#	shared/src/ledger/storage/mod.rs
#	wasm/checksums.json
  • Loading branch information
james-chf committed Nov 4, 2022
2 parents de529b8 + fc1537f commit d2f73e1
Show file tree
Hide file tree
Showing 17 changed files with 1,102 additions and 157 deletions.
372 changes: 371 additions & 1 deletion apps/src/lib/node/ledger/shell/queries.rs

Large diffs are not rendered by default.

429 changes: 362 additions & 67 deletions shared/src/ledger/eth_bridge/bridge_pool_vp.rs

Large diffs are not rendered by default.

93 changes: 72 additions & 21 deletions shared/src/ledger/eth_bridge/storage/bridge_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::collections::BTreeSet;
use std::convert::TryInto;

use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use ethabi::Token;
use eyre::eyre;

use crate::types::address::{Address, InternalAddress};
Expand All @@ -26,10 +27,15 @@ pub struct Error(#[from] eyre::Error);

/// Get the storage key for the transfers in the pool
pub fn get_pending_key(transfer: &PendingTransfer) -> Key {
get_key_from_hash(&transfer.keccak256())
}

/// Get the storage key for the transfers using the hash
pub fn get_key_from_hash(hash: &KeccakHash) -> Key {
Key {
segments: vec![
DbKeySeg::AddressSeg(BRIDGE_POOL_ADDRESS),
transfer.keccak256().to_db_key(),
hash.to_db_key(),
],
}
}
Expand Down Expand Up @@ -88,7 +94,7 @@ impl BridgePoolTree {
let hash = Self::parse_key(key)?;
_ = self.leaves.insert(hash);
self.root = self.compute_root();
Ok(self.root())
Ok(self.root().into())
}

/// Delete a key from storage and update the root
Expand Down Expand Up @@ -119,9 +125,9 @@ impl BridgePoolTree {
}
}

/// Return the root as a [struct@`Hash`] type.
pub fn root(&self) -> Hash {
self.root.clone().into()
/// Return the root as a [`struct@Hash`] type.
pub fn root(&self) -> KeccakHash {
self.root.clone()
}

/// Get a reference to the backing store
Expand All @@ -140,7 +146,12 @@ impl BridgePoolTree {
// get the leaf hashes
let leaves: BTreeSet<KeccakHash> =
values.iter().map(|v| v.keccak256()).collect();

if !leaves.is_subset(&self.leaves) {
return Err(eyre!(
"Cannot generate proof for values that aren't in the tree"
)
.into());
}
let mut proof_hashes = vec![];
let mut flags = vec![];
let mut hashes: Vec<_> = self
Expand Down Expand Up @@ -324,6 +335,31 @@ impl BridgePoolProof {
}
}

impl Encode<3> for BridgePoolProof {
fn tokenize(&self) -> [Token; 3] {
let BridgePoolProof {
proof,
leaves,
flags,
} = self;
let proof = Token::Array(
proof
.iter()
.map(|hash| Token::FixedBytes(hash.0.to_vec()))
.collect(),
);
let transfers = Token::Array(
leaves
.iter()
.map(|t| Token::FixedArray(t.tokenize().to_vec()))
.collect(),
);
let flags =
Token::Array(flags.iter().map(|flag| Token::Bool(*flag)).collect());
[proof, transfers, flags]
}
}

#[cfg(test)]
mod test_bridge_pool_tree {

Expand All @@ -349,6 +385,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([1; 20]),
sender: bertha_address(),
recipient: EthAddress([2; 20]),
amount: 1.into(),
nonce: 42u64.into(),
Expand All @@ -372,6 +409,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -385,9 +423,8 @@ mod test_bridge_pool_tree {
transfers.push(transfer);
let _ = tree.insert_key(&key).expect("Test failed");
}
let expected: Hash =
hash_pair(transfers[0].keccak256(), transfers[1].keccak256())
.into();
let expected =
hash_pair(transfers[0].keccak256(), transfers[1].keccak256());
assert_eq!(tree.root(), expected);
}

Expand All @@ -400,6 +437,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -422,7 +460,7 @@ mod test_bridge_pool_tree {
hash_pair(transfers[0].keccak256(), transfers[1].keccak256());
let right_hash =
hash_pair(transfers[2].keccak256(), Default::default());
let expected: Hash = hash_pair(left_hash, right_hash).into();
let expected = hash_pair(left_hash, right_hash);
assert_eq!(tree.root(), expected);
}

Expand All @@ -434,6 +472,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([1; 20]),
sender: bertha_address(),
recipient: EthAddress([2; 20]),
amount: 1.into(),
nonce: 42u64.into(),
Expand All @@ -460,6 +499,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -478,9 +518,8 @@ mod test_bridge_pool_tree {
tree.delete_key(&Key::from(&transfers[1]))
.expect("Test failed");

let expected: Hash =
hash_pair(transfers[0].keccak256(), transfers[2].keccak256())
.into();
let expected =
hash_pair(transfers[0].keccak256(), transfers[2].keccak256());
assert_eq!(tree.root(), expected);
}

Expand All @@ -490,6 +529,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([1; 20]),
sender: bertha_address(),
recipient: EthAddress([2; 20]),
amount: 1u64.into(),
nonce: 42u64.into(),
Expand All @@ -513,6 +553,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([1; 20]),
sender: bertha_address(),
recipient: EthAddress([2; 20]),
amount: 1u64.into(),
nonce: 42u64.into(),
Expand Down Expand Up @@ -548,6 +589,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([1; 20]),
sender: bertha_address(),
recipient: EthAddress([2; 20]),
amount: 1.into(),
nonce: 42u64.into(),
Expand All @@ -565,6 +607,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([1; 20]),
sender: bertha_address(),
recipient: EthAddress([0; 20]),
amount: 1u64.into(),
nonce: 42u64.into(),
Expand Down Expand Up @@ -596,6 +639,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([0; 20]),
sender: bertha_address(),
recipient: EthAddress([0; 20]),
amount: 0.into(),
nonce: 0.into(),
Expand All @@ -611,7 +655,7 @@ mod test_bridge_pool_tree {
let proof = tree
.get_membership_proof(vec![transfer])
.expect("Test failed");
assert!(proof.verify(tree.root().into()));
assert!(proof.verify(tree.root()));
}

/// Check proofs for membership of single transfer
Expand All @@ -624,6 +668,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -641,7 +686,7 @@ mod test_bridge_pool_tree {
let proof = tree
.get_membership_proof(vec![transfers.remove(0)])
.expect("Test failed");
assert!(proof.verify(tree.root().into()));
assert!(proof.verify(tree.root()));
}

/// Test that a multiproof works for leaves who are siblings
Expand All @@ -653,6 +698,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -670,7 +716,7 @@ mod test_bridge_pool_tree {
transfers.sort_by_key(|t| t.keccak256());
let values = vec![transfers[0].clone(), transfers[1].clone()];
let proof = tree.get_membership_proof(values).expect("Test failed");
assert!(proof.verify(tree.root().into()));
assert!(proof.verify(tree.root()));
}

/// Test that proving an empty subset of leaves always works
Expand All @@ -682,6 +728,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -697,7 +744,7 @@ mod test_bridge_pool_tree {
}
let values = vec![];
let proof = tree.get_membership_proof(values).expect("Test failed");
assert!(proof.verify(tree.root().into()))
assert!(proof.verify(tree.root()))
}

/// Test a proof for all the leaves
Expand All @@ -709,6 +756,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -724,7 +772,7 @@ mod test_bridge_pool_tree {
}
transfers.sort_by_key(|t| t.keccak256());
let proof = tree.get_membership_proof(transfers).expect("Test failed");
assert!(proof.verify(tree.root().into()));
assert!(proof.verify(tree.root()));
}

/// Test a proof for all the leaves when the number of leaves is odd
Expand All @@ -736,6 +784,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -751,7 +800,7 @@ mod test_bridge_pool_tree {
}
transfers.sort_by_key(|t| t.keccak256());
let proof = tree.get_membership_proof(transfers).expect("Test failed");
assert!(proof.verify(tree.root().into()));
assert!(proof.verify(tree.root()));
}

/// Test proofs of large trees
Expand All @@ -763,6 +812,7 @@ mod test_bridge_pool_tree {
let transfer = PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress([i; 20]),
sender: bertha_address(),
recipient: EthAddress([i + 1; 20]),
amount: (i as u64).into(),
nonce: 42u64.into(),
Expand All @@ -779,7 +829,7 @@ mod test_bridge_pool_tree {
transfers.sort_by_key(|t| t.keccak256());
let values: Vec<_> = transfers.iter().step_by(2).cloned().collect();
let proof = tree.get_membership_proof(values).expect("Test failed");
assert!(proof.verify(tree.root().into()));
assert!(proof.verify(tree.root()));
}

/// Create a random set of transfers.
Expand All @@ -797,6 +847,7 @@ mod test_bridge_pool_tree {
.map(|(addr, nonce)| PendingTransfer {
transfer: TransferToEthereum {
asset: EthAddress(addr),
sender: bertha_address(),
recipient: EthAddress(addr),
amount: Default::default(),
nonce: nonce.into(),
Expand Down Expand Up @@ -840,7 +891,7 @@ mod test_bridge_pool_tree {

to_prove.sort_by_key(|t| t.keccak256());
let proof = tree.get_membership_proof(to_prove).expect("Test failed");
assert!(proof.verify(tree.root().into()));
assert!(proof.verify(tree.root()));
}
}
}
28 changes: 21 additions & 7 deletions shared/src/ledger/eth_bridge/vp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ where
Some((key_a, key_b)) => (key_a, key_b),
None => return Ok(false),
};
let sender = match check_balance_changes(&self.ctx, key_a, key_b)? {
let (sender, _) = match check_balance_changes(&self.ctx, key_a, key_b)?
{
Some(sender) => sender,
None => return Ok(false),
};
Expand Down Expand Up @@ -152,13 +153,14 @@ fn extract_valid_keys_changed(
/// Checks that the balances at both `key_a` and `key_b` have changed by some
/// amount, and that the changes balance each other out. If the balance changes
/// are invalid, the reason is logged and a `None` is returned. Otherwise,
/// return the `Address` of the owner of the balance which is decreasing, which
/// should be authorizing the balance change.
fn check_balance_changes(
/// return the `Address` of the owner of the balance which is decreasing,
/// and by how much it decreased, which should be authorizing the balance
/// change.
pub(super) fn check_balance_changes(
reader: impl StorageReader,
key_a: wrapped_erc20s::Key,
key_b: wrapped_erc20s::Key,
) -> Result<Option<Address>> {
) -> Result<Option<(Address, Amount)>> {
let (balance_a, balance_b) =
match (key_a.suffix.clone(), key_b.suffix.clone()) {
(
Expand Down Expand Up @@ -264,14 +266,26 @@ fn check_balance_changes(

if balance_a_delta < 0 {
if let wrapped_erc20s::KeyType::Balance { owner } = key_a.suffix {
Ok(Some(owner))
Ok(Some((
owner,
Amount::from(
u64::try_from(balance_b_delta)
.expect("This should not fail"),
),
)))
} else {
unreachable!()
}
} else {
assert!(balance_b_delta < 0);
if let wrapped_erc20s::KeyType::Balance { owner } = key_b.suffix {
Ok(Some(owner))
Ok(Some((
owner,
Amount::from(
u64::try_from(balance_a_delta)
.expect("This should not fail"),
),
)))
} else {
unreachable!()
}
Expand Down
Loading

0 comments on commit d2f73e1

Please sign in to comment.