Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XRPL Multisig Prover #227

Draft
wants to merge 83 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
e62e2ab
copy voting-verifier to xrpl-voting-verifier contract
abresas Dec 18, 2023
fe07d1c
xrpl-voting-verifier: verify message status
abresas Dec 18, 2023
7379b5e
xrpl-voting-verifier: confirm ccid status instead of message status
abresas Dec 18, 2023
ccf929d
xrpl-voting-verifier: fix "message" instead of "cc_id" typo
k4m4 Dec 18, 2023
6f850a0
xrpl-multisig-prover
abresas Dec 19, 2023
d2ec76f
xrpl serialiation for ticket create and signerlistset
abresas Dec 29, 2023
772b243
xrpl serialization all tests pass
abresas Jan 2, 2024
e07f8a0
xrpl fix accidentally broken signed payment tx test
abresas Jan 2, 2024
7eff148
xrpl-{multisig-prover,voting-verifier}: add integration tests & make …
k4m4 Jan 3, 2024
decab21
xrpl: cleanup xrpl_multisig module, register next worker set
abresas Jan 3, 2024
4dd3cca
xrpl-multisig-prover: Add GetWorkerSet query & write UpdateWorkerSet …
k4m4 Jan 3, 2024
0925066
xrpl-multisig-prover: separate TicketCreate & Payment integration tests
k4m4 Jan 3, 2024
66434b2
xrpl-multisig-prover: relocate UpdateWorkerSet integration test asser…
k4m4 Jan 3, 2024
d8aa0c0
xrpl: fix serializing token payments and enable tests
abresas Jan 3, 2024
fa8111d
xrpl: remove commented out code
abresas Jan 3, 2024
1033d2f
xrpl: minor fix remove unwrap function call
abresas Jan 3, 2024
fd63575
wip: xrpl memo
abresas Jan 12, 2024
25908e4
xrpl multisig in memo
abresas Jan 23, 2024
257da09
xrpl serialization tests
abresas Jan 30, 2024
b47d38d
rename cc_id to message_id
abresas Jan 31, 2024
d8a9e6e
xrpl improve coin amount handling
abresas Jan 31, 2024
1ee8ad0
xrpl separate message interface to msg.rs
abresas Feb 7, 2024
1cdcdb9
xrpl message verification function
abresas Feb 7, 2024
198808e
xrpl: sort signers in multisig transactions and support ed25519 publi…
abresas Feb 8, 2024
1509841
xrpl message id is tx_id without event index
abresas Feb 8, 2024
6d459bc
xrpl remove obsolete todo
abresas Feb 8, 2024
3ed191b
xrpl remove obsolete function
abresas Feb 8, 2024
0f1ce94
xrpl remove obsolete import
abresas Feb 8, 2024
f21179e
Revert "xrpl message id is tx_id without event index"
k4m4 Feb 8, 2024
92836ab
Revert "xrpl remove obsolete import"
k4m4 Feb 8, 2024
4678211
xrpl-multisig-prover: remove finalize_proof & modify update_tx_status
k4m4 Feb 8, 2024
c5539bf
xrpl-multisig-prover: restore signed_xrp_payment_transaction serlizat…
k4m4 Feb 8, 2024
5069f58
Merge remote-tracking branch 'axelar/main' into xrpl-without-custom-v…
k4m4 Feb 12, 2024
c571ff8
ampd xrpl signing started event
abresas Feb 13, 2024
2d5740c
multisig: add expires_at attribute to Multisig type
k4m4 Feb 13, 2024
a9146d3
xrpl-multisig-prover: allow one multisig session per payment
k4m4 Feb 13, 2024
9862500
xrpl-multisig-prover: remove redundant param from make_xrpl_signed_tx
k4m4 Feb 13, 2024
26498e0
xrpl-multisig-prover: remove redundant imports
k4m4 Feb 13, 2024
46a9b98
xrpl multisig prover signing started event
abresas Feb 13, 2024
8681da3
xrpl-multisig-prover: fix incorrect integration test xrpl multisig ad…
k4m4 Feb 13, 2024
bf1cbf1
xrpl-multisig-prover: remove redundant prints from integration tests
k4m4 Feb 13, 2024
b0c5bd0
xrpl integration tests use unsigned_tx instead of session id for sign…
abresas Feb 13, 2024
8985a3c
xrpl-multisig-prover: uncomment reward integration test assertions
k4m4 Feb 14, 2024
74d34aa
xrpl-multisig-prover: only governance can register token
k4m4 Feb 14, 2024
51524d5
xrpl-multisig-prover: create get_next_multisig_session_id query function
k4m4 Feb 14, 2024
8f72e94
xrpl-multisig-prover: include multisig_session_id in memo & modify to…
k4m4 Feb 14, 2024
6165a46
xrpl-multisig-prover: relocate query in update_tx_status
k4m4 Feb 14, 2024
ce3c164
xrpl-multisig-prover: move make_xrpl_signed_tx to xrpl_multisig
k4m4 Feb 14, 2024
c740e60
wip: remove unwraps and clones
abresas Feb 16, 2024
c8fdb54
xrpl: remove bigdecimal/bigint dependency
abresas Feb 17, 2024
dc90b25
xrpl: custom decimal type
abresas Feb 17, 2024
e1f231f
xrpl: token amount type instead of decimal
abresas Feb 17, 2024
58a22dc
xrpl: accountid type for addresses
abresas Feb 18, 2024
3392a95
xrpl: remove unnecessary imports
abresas Feb 18, 2024
5bf2c82
xrpl: separate serialization logic to separate module
abresas Feb 18, 2024
4ec6936
xrpl: statically typed fields to improve code clarity
abresas Feb 19, 2024
1e30082
xrpl multisig prover: improver code structure
abresas Feb 19, 2024
6d8bed5
xrpl: add missing import
abresas Feb 19, 2024
8495fc2
xrpl multisig prover: SerializedField struct, from/to_json, code clarity
abresas Feb 20, 2024
63f07ae
xrpl multisig prover: improve code quality on serialization
abresas Feb 20, 2024
f97b3cb
xrpl multisig prover: use parse_message_id from voting verifier and o…
abresas Feb 20, 2024
4802b93
xrpl multisig prover: code quality improvements
abresas Feb 21, 2024
dfe0170
xrpl: xrpl_serialize parameter not a reference
abresas Feb 29, 2024
650f606
add message_provider option on multisig handler
abresas Feb 9, 2024
ddfebf2
ampd: xrpl msg verifier
abresas Feb 11, 2024
ee23777
ampd xrpl verification logic: separate multisig generated txs and dep…
abresas Feb 12, 2024
4a66bdd
Revert "add message_provider option on multisig handler"
abresas Feb 13, 2024
7e7c94c
ampd xrpl add missing xrpl types file
abresas Feb 13, 2024
25d0e90
ampd: xrpl memo payload handling with fee, relayer, amount, currencyg
abresas Feb 16, 2024
a05b652
xrpl multisig prover: add compatibility with relayer
k4m4 Apr 18, 2024
280df17
ampd xrpl: update config & verify ABI-encoded payload hash
k4m4 Apr 18, 2024
b4da970
Revert "xrpl-multisig-prover: create get_next_multisig_session_id que…
k4m4 Apr 18, 2024
d732049
Merge remote-tracking branch 'axelar/main' into xrpl-multisig-prover
k4m4 Apr 20, 2024
c1c58e6
Implement sig_verifier VerifyMessage query
k4m4 Apr 20, 2024
ca760ac
Merge remote-tracking branch 'axelar/main' into xrpl-multisig-prover
k4m4 Apr 20, 2024
dba8b70
ampd: skip XRPL `PollStartedEvent`s & fix XRPL payload_hash verification
k4m4 Apr 22, 2024
d521c6b
improve type conversions
abresas May 6, 2024
09b32c3
vec handling improvements
abresas May 6, 2024
bfaf2a6
optimize xrpl serialize functions
abresas May 7, 2024
7acea6f
allocation improvements
abresas May 8, 2024
ee9a678
minor clippy improvements
abresas May 9, 2024
6481d67
run cargo fmt
abresas May 9, 2024
4215dc9
Fix off-by-one TicketCreate count
k4m4 Jul 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,866 changes: 1,016 additions & 850 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ axelar-wasm-std = { version = "^0.1.0", path = "packages/axelar-wasm-std" }
axelar-wasm-std-derive = { version = "^0.1.0", path = "packages/axelar-wasm-std-derive" }
itertools = "0.11.0"
voting-verifier = { version = "^0.1.0", path = "contracts/voting-verifier" }
xrpl-voting-verifier = { version = "^0.1.0", path = "contracts/xrpl-voting-verifier" }
xrpl-multisig-prover = { version = "^0.1.0", path = "contracts/xrpl-multisig-prover" }
multisig = { version = "^0.1.0", path = "contracts/multisig" }
multisig-prover = { version = "^0.1.0", path = "contracts/multisig-prover" }
service-registry = { version = "^0.1.0", path = "contracts/service-registry" }
Expand Down
57 changes: 57 additions & 0 deletions contracts/xrpl-multisig-prover/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[package]
name = "xrpl-multisig-prover"
version = "0.1.0"
edition = "2021"
description = "XRPL multisig prover contract"

exclude = [
# Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication.
"contract.wasm",
"hash.txt",
]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib", "rlib"]

[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []

[package.metadata.scripts]
optimize = """docker run --rm -v "$(pwd)":/code \
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/rust-optimizer:0.12.6
"""

[dependencies]
cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true }
axelar-wasm-std = { workspace = true }
axelar-wasm-std-derive = { workspace = true }
cw-storage-plus = { workspace = true }
connection-router = { workspace = true, features = ["library"] }
service-registry = { workspace = true }
multisig = { workspace = true, features = ["library"] }
gateway = { workspace = true }
thiserror = { workspace = true }
error-stack = { workspace = true }
report = { workspace = true }
serde_json = "1.0.89"
sha2 = { version = "0.10.7" }
sha3 = { workspace = true }
cw-utils = "1.0.1"
bs58 = "0.5.0"
ripemd = "0.1.3"
hex = { version = "0.4.3", default-features = false, features = [] }
xrpl-voting-verifier = { workspace = true, features = ["library"] }
k256 = { version = "0.13.1", features = ["ecdsa"] }

[dev-dependencies]
anyhow = "1.0"
cw-multi-test = "0.15.1"
elliptic-curve = "0.13.5"
generic-array = "0.14.7"
203 changes: 203 additions & 0 deletions contracts/xrpl-multisig-prover/src/axelar_workers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
use std::collections::hash_map::RandomState;
use std::collections::{BTreeSet, HashMap};

use axelar_wasm_std::{Threshold, nonempty};
use axelar_wasm_std::Participant;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{HexBinary, Uint256, Addr, Fraction};
use multisig::key::KeyType;
use service_registry::state::Worker;
use multisig::key::PublicKey;

use crate::querier::Querier;
use crate::error::ContractError;

#[cw_serde]
#[derive(Eq, Ord, PartialOrd)]
pub struct AxelarSigner {
pub address: Addr,
pub weight: u16,
pub pub_key: PublicKey,
}

impl Into<Participant> for AxelarSigner {
fn into(self) -> Participant {
let weight = nonempty::Uint256::try_from(Uint256::from(self.weight as u128)).unwrap();
Participant {
address: self.address,
weight,
}
}
}

#[cw_serde]
pub struct WorkerSet {
pub signers: BTreeSet<AxelarSigner>,
pub quorum: u32,
// for hash uniqueness. The same exact worker set could be in use at two different times,
// and we need to be able to distinguish between the two
pub created_at: u64,
}

impl Into<multisig::worker_set::WorkerSet> for WorkerSet {
fn into(self) -> multisig::worker_set::WorkerSet {
let participants = self.signers.into_iter()
.map(|s| (s.clone().into(), s.pub_key))
.collect();
multisig::worker_set::WorkerSet::new(
participants,
Uint256::from(self.quorum as u128),
self.created_at
)
}
}

impl WorkerSet {
pub fn pub_keys_by_address(&self) -> HashMap<String, (KeyType, HexBinary), RandomState> {
self
.signers
.clone()
.into_iter()
.map(|signer| {
(
signer.address.to_string(),
(KeyType::Ecdsa, signer.pub_key.as_ref().into()),
)
})
.collect()
}
}

fn convert_uint256_to_u16_unsafely(value: Uint256) -> u16 {
let bytes = value.to_le_bytes();
(bytes[0] as u16) | (bytes[1] as u16) << 8
}

// Converts a Vec<Uint256> to Vec<u16>, scaling down with precision loss, if necessary.
// We make sure that XRPL multisig and Axelar multisig both use the same scaled down numbers and have the same precision loss
fn convert_or_scale_weights(weights: Vec<Uint256>) -> Vec<u16> {
let max_weight: Option<&Uint256> = weights.iter().max();
match max_weight {
Some(max_weight) => {
let max_u16_as_uint256 = Uint256::from(u16::MAX);
// Scaling down
weights
.clone()
.into_iter()
.map(|weight| {
// multiply_ratio returns a rounded down value
let scaled = weight.multiply_ratio(max_u16_as_uint256, *max_weight);
convert_uint256_to_u16_unsafely(scaled)
})
.collect()
},
None => vec![],
}
}

pub fn get_active_worker_set(
querier: Querier,
signing_threshold: Threshold,
block_height: u64,
) -> Result<WorkerSet, ContractError> {
let workers: Vec<Worker> = querier.get_active_workers()?;

let participants: Vec<Participant> = workers
.into_iter()
.map(|worker| Participant::try_from(worker))
.filter(|result| result.is_ok())
.map(|result| result.unwrap())
.collect();

let weights = convert_or_scale_weights(participants
.clone()
.into_iter()
.map(|participant| Uint256::from(participant.weight))
.collect());

let mut signers: Vec<AxelarSigner> = vec![];
for (i, participant) in participants.iter().enumerate() {
let pub_key: PublicKey = querier.get_public_key(participant.address.clone().to_string())?;
signers.push(AxelarSigner {
address: participant.address.clone(),
weight: weights[i],
pub_key,
});
}

let sum_of_weights: u32 = weights.iter().map(|w| u32::from(*w)).sum();

let quorum = (sum_of_weights as u64)
.checked_mul(signing_threshold.numerator().into())
.unwrap()
.checked_div(signing_threshold.denominator().into())
.unwrap() as u32;

let worker_set = WorkerSet {
signers: signers.into_iter().collect(),
quorum,
created_at: block_height,
};

Ok(worker_set)
}

pub fn should_update_worker_set(
new_workers: &WorkerSet,
cur_workers: &WorkerSet,
max_diff: usize,
) -> bool {
new_workers.signers.difference(&cur_workers.signers).count()
+ cur_workers.signers.difference(&new_workers.signers).count()
> max_diff
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_convert_or_scale_weights() {
let weights = vec![Uint256::from(1u128), Uint256::from(1u128)];
let scaled_weights = convert_or_scale_weights(weights);
assert_eq!(scaled_weights, vec![65535, 65535]);

let weights = vec![Uint256::from(1u128), Uint256::from(2u128), Uint256::from(3u128)];
let scaled_weights = convert_or_scale_weights(weights);
assert_eq!(scaled_weights, vec![21845, 43690, 65535]);

let weights = vec![Uint256::from(1u128), Uint256::from(2u128), Uint256::from(3u128), Uint256::from(4u128)];
let scaled_weights = convert_or_scale_weights(weights);
assert_eq!(scaled_weights, vec![16383, 32767, 49151, 65535]);

let weights = vec![
Uint256::MAX - Uint256::from(3u128),
Uint256::MAX - Uint256::from(2u128),
Uint256::MAX - Uint256::from(1u128),
Uint256::MAX
];
let scaled_weights = convert_or_scale_weights(weights);
assert_eq!(scaled_weights, vec![65534, 65534, 65534, 65535]);

let weights = vec![
Uint256::from(0u128),
Uint256::from(1u128),
Uint256::MAX - Uint256::from(1u128),
Uint256::MAX
];
let scaled_weights = convert_or_scale_weights(weights);
assert_eq!(scaled_weights, vec![0, 0, 65534, 65535]);

let weights = vec![
Uint256::from(100000u128),
Uint256::from(2000000u128),
Uint256::from(30000000u128),
Uint256::from(400000000u128),
Uint256::from(50000000000u128),
];
let scaled_weights = convert_or_scale_weights(weights);
assert_eq!(scaled_weights, vec![0, 2, 39, 524, 65535]);

assert_eq!(convert_or_scale_weights(vec![] as Vec<Uint256>), vec![] as Vec<u16>);
}
}
Loading