diff --git a/contract/Cargo.lock b/contract/Cargo.lock index 87ed2f0d..a0f78ec7 100644 --- a/contract/Cargo.lock +++ b/contract/Cargo.lock @@ -363,7 +363,7 @@ dependencies = [ [[package]] name = "btc-light-client-contract" -version = "0.4.0" +version = "0.4.1" dependencies = [ "bitcoin", "borsh", @@ -376,6 +376,7 @@ dependencies = [ "near-plugins", "near-sdk", "near-workspaces", + "omni-utils", "serde", "serde_json", "tokio", @@ -577,6 +578,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -785,7 +795,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl 2.1.1", ] [[package]] @@ -799,6 +818,20 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case 0.10.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.101", + "unicode-xid", +] + [[package]] name = "digest" version = "0.10.7" @@ -880,9 +913,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", @@ -1573,6 +1606,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1795,7 +1837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879ac02b2e8d6498294adce1de7a2424a5474b35a73e9262c851be39c89d7f92" dependencies = [ "anyhow", - "convert_case", + "convert_case 0.5.0", "near-abi-client-impl", "near-abi-client-macros", "prettyplease 0.1.25", @@ -1838,6 +1880,16 @@ dependencies = [ "serde", ] +[[package]] +name = "near-account-id" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91f75ff8eee73815c247d0e17f3c0b705f0e993922a5548acd2ad377aeb67fca" +dependencies = [ + "borsh", + "serde", +] + [[package]] name = "near-chain-configs" version = "0.30.1" @@ -1847,12 +1899,12 @@ dependencies = [ "anyhow", "bytesize", "chrono", - "derive_more", - "near-config-utils", - "near-crypto", - "near-parameters", - "near-primitives", - "near-time", + "derive_more 1.0.0", + "near-config-utils 0.30.1", + "near-crypto 0.30.1", + "near-parameters 0.30.1", + "near-primitives 0.30.1", + "near-time 0.30.1", "num-rational", "serde", "serde_json", @@ -1874,6 +1926,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "near-config-utils" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2ba8f7129472fc147b867e904e4b8f398aa79f263f54dff6283c4860446ef8" +dependencies = [ + "anyhow", + "json_comments", + "thiserror 2.0.12", + "tracing", +] + [[package]] name = "near-crypto" version = "0.30.1" @@ -1884,13 +1948,13 @@ dependencies = [ "borsh", "bs58 0.4.0", "curve25519-dalek", - "derive_more", + "derive_more 1.0.0", "ed25519-dalek", "hex", - "near-account-id", - "near-config-utils", - "near-schema-checker-lib", - "near-stdx", + "near-account-id 1.1.1", + "near-config-utils 0.30.1", + "near-schema-checker-lib 0.30.1", + "near-stdx 0.30.1", "primitive-types", "rand", "secp256k1 0.27.0", @@ -1900,20 +1964,54 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "near-crypto" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c12a12485f8baafa85d5c413885b795bfa1d7d0ab7fd49b4f7fbe6cd270325b" +dependencies = [ + "blake2", + "borsh", + "bs58 0.4.0", + "curve25519-dalek", + "derive_more 2.1.1", + "ed25519-dalek", + "hex", + "near-account-id 2.5.0", + "near-config-utils 0.34.7", + "near-schema-checker-lib 0.34.7", + "near-stdx 0.34.7", + "primitive-types", + "secp256k1 0.27.0", + "serde", + "serde_json", + "subtle", + "thiserror 2.0.12", +] + [[package]] name = "near-fmt" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64c0e4d846b9c27b30e5f24e788fb8cc55c046f72e2048e2539dbcb04d9a71c4" dependencies = [ - "near-primitives-core", + "near-primitives-core 0.30.1", +] + +[[package]] +name = "near-fmt" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31b6d8fb4146cf0a7dcadf7816bf7b8efd5c081d6d2ca524bc80815b5f86812" +dependencies = [ + "near-primitives-core 0.34.7", ] [[package]] name = "near-gas" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180edcc7dc2fac41f93570d0c7b759c1b6d492f6ad093d749d644a40b4310a97" +checksum = "919d705b6dab5a7c6cc4b9a60e3025ed2f7cf3d4c3c32ad1a47264a4190e6409" dependencies = [ "borsh", "schemars", @@ -1930,9 +2028,9 @@ dependencies = [ "lazy_static", "log", "near-chain-configs", - "near-crypto", + "near-crypto 0.30.1", "near-jsonrpc-primitives", - "near-primitives", + "near-primitives 0.30.1", "reqwest", "serde", "serde_json", @@ -1947,9 +2045,9 @@ checksum = "63ac3e779b1ad979957f05e43c92a79fbe7e1315647ab4d530e2a9a66bc62f5e" dependencies = [ "arbitrary", "near-chain-configs", - "near-crypto", - "near-primitives", - "near-schema-checker-lib", + "near-crypto 0.30.1", + "near-primitives 0.30.1", + "near-schema-checker-lib 0.30.1", "serde", "serde_json", "thiserror 2.0.12", @@ -1964,9 +2062,28 @@ checksum = "4dbb139bec6b7088d6afab0a3662725e5ee82d0ad725b67c1d45447c3d45fe55" dependencies = [ "borsh", "enum-map", - "near-account-id", - "near-primitives-core", - "near-schema-checker-lib", + "near-account-id 1.1.1", + "near-primitives-core 0.30.1", + "near-schema-checker-lib 0.30.1", + "num-rational", + "serde", + "serde_repr", + "serde_yaml", + "strum 0.24.1", + "thiserror 2.0.12", +] + +[[package]] +name = "near-parameters" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a561606a8beb563bf166c8a9ceb7f97058b376d17ea1a9b4b65ebc9bff29ac" +dependencies = [ + "borsh", + "enum-map", + "near-account-id 2.5.0", + "near-primitives-core 0.34.7", + "near-schema-checker-lib 0.34.7", "num-rational", "serde", "serde_repr", @@ -2012,18 +2129,18 @@ dependencies = [ "bytesize", "cfg-if 1.0.0", "chrono", - "derive_more", + "derive_more 1.0.0", "easy-ext", "enum-map", "hex", - "itertools", - "near-crypto", - "near-fmt", - "near-parameters", - "near-primitives-core", - "near-schema-checker-lib", - "near-stdx", - "near-time", + "itertools 0.12.1", + "near-crypto 0.30.1", + "near-fmt 0.30.1", + "near-parameters 0.30.1", + "near-primitives-core 0.30.1", + "near-schema-checker-lib 0.30.1", + "near-stdx 0.30.1", + "near-time 0.30.1", "num-rational", "ordered-float", "primitive-types", @@ -2040,6 +2157,46 @@ dependencies = [ "zstd 0.13.3", ] +[[package]] +name = "near-primitives" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ccddcf4a73e19afd681faaa7e83fc4046ec71f4bbe58c58ff4ae4432f36e3aa" +dependencies = [ + "arbitrary", + "base64 0.21.7", + "bitvec", + "borsh", + "bytes", + "bytesize", + "chrono", + "derive_more 2.1.1", + "easy-ext", + "enum-map", + "hex", + "itertools 0.14.0", + "near-crypto 0.34.7", + "near-fmt 0.34.7", + "near-parameters 0.34.7", + "near-primitives-core 0.34.7", + "near-schema-checker-lib 0.34.7", + "near-stdx 0.34.7", + "near-time 0.34.7", + "num-rational", + "ordered-float", + "primitive-types", + "serde", + "serde_json", + "serde_with", + "sha3", + "smallvec", + "smart-default", + "strum 0.24.1", + "thiserror 2.0.12", + "tracing", + "zstd 0.13.3", +] + [[package]] name = "near-primitives-core" version = "0.30.1" @@ -2050,13 +2207,37 @@ dependencies = [ "base64 0.21.7", "borsh", "bs58 0.4.0", - "derive_more", + "derive_more 1.0.0", + "enum-map", + "near-account-id 1.1.1", + "near-schema-checker-lib 0.30.1", + "num-rational", + "serde", + "serde_repr", + "sha2", + "thiserror 2.0.12", +] + +[[package]] +name = "near-primitives-core" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c93d8c5d6aecfec0aa9d60ab34408c68b13d5c1bfc0f3afeee8c99fa521cdb3" +dependencies = [ + "arbitrary", + "base64 0.21.7", + "borsh", + "bs58 0.4.0", + "derive_more 2.1.1", "enum-map", - "near-account-id", - "near-schema-checker-lib", + "near-account-id 2.5.0", + "near-gas", + "near-schema-checker-lib 0.34.7", + "near-token", "num-rational", "serde", "serde_repr", + "serde_with", "sha2", "thiserror 2.0.12", ] @@ -2080,14 +2261,30 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed1fbfbc3c53b00aa893f8cb64abc5c12601edb8cecb878baf6f8f00e3184d3d" +[[package]] +name = "near-schema-checker-core" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f969a965d1ea04e1f085ee4d6c7273ae1064f578711087f3beaf8d400672cc7e" + [[package]] name = "near-schema-checker-lib" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f424ce08c8d715f529a8f8dcd246f574042f0ed0b393d0aaefdf3cc693d5a9f" dependencies = [ - "near-schema-checker-core", - "near-schema-checker-macro", + "near-schema-checker-core 0.30.1", + "near-schema-checker-macro 0.30.1", +] + +[[package]] +name = "near-schema-checker-lib" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ae7538880de8a8d75e150dd0f4f685211ddd654ab12a339f40458df6d191dd" +dependencies = [ + "near-schema-checker-core 0.34.7", + "near-schema-checker-macro 0.34.7", ] [[package]] @@ -2096,21 +2293,27 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d191936f902770069255b16c95d1fb8edd6f3c3817c9228933a20ec8466737a3" +[[package]] +name = "near-schema-checker-macro" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9eb7d4dc413fe39ffa7fe5591ed4c24bc8139b9de8497689178d0101ae5167" + [[package]] name = "near-sdk" -version = "5.14.0" +version = "5.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1477ca4eb6d4a70a0e5740c5d34c268eedacce936ca557d3450ed5bd873fd06" +checksum = "0f3fa35758aba48e4f13528ba2f603e860dad03233d446e5c65ebd619296b607" dependencies = [ "base64 0.22.1", "borsh", "bs58 0.5.1", - "near-account-id", - "near-crypto", + "near-account-id 2.5.0", + "near-crypto 0.34.7", "near-gas", - "near-parameters", - "near-primitives", - "near-primitives-core", + "near-parameters 0.34.7", + "near-primitives 0.34.7", + "near-primitives-core 0.34.7", "near-sdk-macros", "near-sys", "near-token", @@ -2118,14 +2321,15 @@ dependencies = [ "once_cell", "serde", "serde_json", + "serde_with", "wee_alloc", ] [[package]] name = "near-sdk-macros" -version = "5.14.0" +version = "5.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29fe6d31a827e421d0d3f5c38fe3cc73f9f2a2aae41d2601d37c22d7ec1aae" +checksum = "bb141510850a842d010d706c00bcbf31beba188c706415cc9392ffd62a127e09" dependencies = [ "Inflector", "darling 0.20.11", @@ -2144,11 +2348,17 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f292226fd8f4c7c21cf6b1da1c17e9b484ebc1b9aeb4251d69336d28b7917ace" +[[package]] +name = "near-stdx" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5dc0456309fcb256a0609d829971fd99f343e1a7f3b72f85364e64250a4555" + [[package]] name = "near-sys" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d8e0ba9994e4d54cb4b301cd5fa9f2defcb69851148103512b9640a7e91572" +checksum = "f4ea77bb86969ff09c83faa517b2209c4876928381ed31e29c06cae2de0a216b" [[package]] name = "near-time" @@ -2160,11 +2370,22 @@ dependencies = [ "time", ] +[[package]] +name = "near-time" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9ae070cbd84d16b948fcc335ea82db35919bf856e349f333143ff2894eeafd" +dependencies = [ + "parking_lot", + "serde", + "time", +] + [[package]] name = "near-token" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3e60aa26a74dc514b1b6408fdd06cefe2eb0ff029020956c1c6517594048fd" +checksum = "34de6b54d82d0790b2a56b677e7b4ecb7f021a7e8559f8611065c890d56cfcda" dependencies = [ "borsh", "serde", @@ -2172,9 +2393,9 @@ dependencies = [ [[package]] name = "near-vm-runner" -version = "0.30.1" +version = "0.34.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e44b5b6582676805ab61bc60e65e56eec1460c58a7c951dd662b7a5c677554" +checksum = "3c9b4794d695cf13a1a117d76a3e87b6b660f8f7862f9df1544ba8bbd96634c9" dependencies = [ "blst", "borsh", @@ -2182,18 +2403,18 @@ dependencies = [ "ed25519-dalek", "enum-map", "lru", - "near-crypto", - "near-parameters", - "near-primitives-core", - "near-schema-checker-lib", - "near-stdx", + "near-crypto 0.34.7", + "near-parameters 0.34.7", + "near-primitives-core 0.34.7", + "near-schema-checker-lib 0.34.7", + "near-stdx 0.34.7", "num-rational", + "parking_lot", "rand", "rayon", "ripemd", "rustix", "serde", - "serde_repr", "sha2", "sha3", "strum 0.24.1", @@ -2218,12 +2439,12 @@ dependencies = [ "json-patch", "libc", "near-abi-client", - "near-account-id", - "near-crypto", + "near-account-id 1.1.1", + "near-crypto 0.30.1", "near-gas", "near-jsonrpc-client", "near-jsonrpc-primitives", - "near-primitives", + "near-primitives 0.30.1", "near-sandbox-utils", "near-token", "rand", @@ -2333,6 +2554,27 @@ dependencies = [ "memchr", ] +[[package]] +name = "omni-utils" +version = "0.1.0" +source = "git+https://github.com/near-one/omni-utils?rev=077d09daf7a7b32ad237f0530033c7db804f2c67#077d09daf7a7b32ad237f0530033c7db804f2c67" +dependencies = [ + "near-sdk", + "omni-utils-derive", + "serde", + "serde_json", +] + +[[package]] +name = "omni-utils-derive" +version = "0.1.0" +source = "git+https://github.com/near-one/omni-utils?rev=077d09daf7a7b32ad237f0530033c7db804f2c67#077d09daf7a7b32ad237f0530033c7db804f2c67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -3019,6 +3261,7 @@ version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ + "indexmap 2.9.0", "itoa", "memchr", "ryu", @@ -3666,6 +3909,18 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unsafe-libyaml" version = "0.2.11" diff --git a/contract/Cargo.toml b/contract/Cargo.toml index a0d63d08..9899e3dc 100644 --- a/contract/Cargo.toml +++ b/contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "btc-light-client-contract" description = "Bitcoin Light Client Contract" -version = "0.4.0" +version = "0.4.1" edition = "2021" repository = "https://github.com/Near-One/btc-light-client-contract" @@ -40,8 +40,9 @@ doctest = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -near-sdk = { version = "5.14.0", features = ["legacy"] } +near-sdk = { version = "5.24.1", features = ["legacy"] } near-plugins = { git = "https://github.com/aurora-is-near/near-plugins", tag = "v0.4.1" } +omni-utils = { git = "https://github.com/near-one/omni-utils", rev = "077d09daf7a7b32ad237f0530033c7db804f2c67" } borsh = "1.5.0" serde_json = "1" merkle-tools = { path = "../merkle-tools" } @@ -53,7 +54,7 @@ cfg-if = "1.0.0" hex = "0.4.3" [dev-dependencies] -near-sdk = { version = "5.14.0", features = ["unit-testing"] } +near-sdk = { version = "5.24.1", features = ["unit-testing"] } near-workspaces = { version = "0.20.1", features = ["unstable"] } tokio = { version = "1.12.0", features = ["full"] } serde_json = "1" diff --git a/contract/src/lib.rs b/contract/src/lib.rs index 0566c7d0..060e8f23 100644 --- a/contract/src/lib.rs +++ b/contract/src/lib.rs @@ -13,6 +13,7 @@ use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::collections::LookupMap; use near_sdk::serde::{Deserialize, Serialize}; use near_sdk::{env, log, near, require, NearToken, PanicOnDefault, Promise, PromiseOrValue}; +use omni_utils::macros::trusted_relayer; use crate::utils::BlocksGetter; @@ -67,6 +68,8 @@ pub enum Role { /// Using this pattern grantees of a single role are authorized to call multiple (but not all) /// protected `Upgradable` methods. DurationManager, + /// May manage trusted relayer staking: reject applications and update relayer config. + RelayerManager, } #[derive(BorshSerialize, near_sdk::BorshStorageKey)] enum StorageKey { @@ -114,6 +117,11 @@ pub struct BtcLightClient { network: Network, } +#[trusted_relayer( + bypass_roles(Role::DAO, Role::UnrestrictedSubmitBlocks), + manager_roles(Role::DAO, Role::RelayerManager), + config_roles(Role::DAO) +)] #[near] impl BtcLightClient { /// Recommended initialization parameters: @@ -152,8 +160,12 @@ impl BtcLightClient { contract } + /// This method submits provided headers + /// # Panics + /// Cannot parse headers len as u64 #[payable] - #[pause(except(roles(Role::UnrestrictedSubmitBlocks)))] + #[pause] + #[trusted_relayer] pub fn submit_blocks( &mut self, #[serializer(borsh)] headers: Vec, diff --git a/contract/tests/test_basics.rs b/contract/tests/test_basics.rs index cdc7b2de..ceba049b 100644 --- a/contract/tests/test_basics.rs +++ b/contract/tests/test_basics.rs @@ -35,6 +35,29 @@ mod test_basics { blocks } + /// Grant the `UnrestrictedSubmitBlocks` role to an account so it passes the + /// `#[trusted_relayer]` guard on `submit_blocks`. The contract itself is the + /// super admin (set during `init`), so it can grant any role. + async fn grant_relayer_role( + contract: &Contract, + account: &Account, + ) -> Result<(), Box> { + let outcome = contract + .call("acl_grant_role") + .args_json(json!({ + "role": "UnrestrictedSubmitBlocks", + "account_id": account.id(), + })) + .transact() + .await?; + assert!( + outcome.is_success(), + "Failed to grant role: {:?}", + outcome.failures() + ); + Ok(()) + } + async fn init_contract() -> Result<(Contract, Account), Box> { let sandbox = near_workspaces::sandbox().await?; let contract_wasm = near_workspaces::compile_project("./").await?; @@ -61,6 +84,7 @@ mod test_basics { assert!(outcome.is_success()); let user_account = sandbox.dev_create_account().await?; + grant_relayer_role(&contract, &user_account).await?; Ok((contract, user_account)) } @@ -104,6 +128,7 @@ mod test_basics { assert!(outcome.is_success()); let user_account = sandbox.dev_create_account().await?; + grant_relayer_role(&contract, &user_account).await?; // Return blocks NOT yet submitted (batch[2][5..] onward). let remaining = remaining_after_init(&all_block_headers); @@ -519,6 +544,69 @@ mod test_basics { Ok(()) } + /// A random account without any roles must be rejected by the + /// `#[trusted_relayer]` guard when calling `submit_blocks`. + #[tokio::test] + async fn test_unauthorized_account_cannot_submit_blocks( + ) -> Result<(), Box> { + let sandbox = near_workspaces::sandbox().await?; + let contract_wasm = near_workspaces::compile_project("./").await?; + let contract = sandbox.dev_deploy(&contract_wasm).await?; + + let submit_blocks = make_init_submit_blocks(); + let args = InitArgs { + genesis_block_hash: submit_blocks[0].block_hash(), + genesis_block_height: 0, + skip_pow_verification: true, + gc_threshold: 20, + network: btc_types::network::Network::Mainnet, + submit_blocks, + }; + let outcome = contract + .call("init") + .args_json(json!({ + "args": serde_json::to_value(args).unwrap(), + })) + .transact() + .await?; + assert!(outcome.is_success()); + + // Create an account but do NOT grant any role. + let unauthorized_account = sandbox.dev_create_account().await?; + + let init_blocks = make_init_submit_blocks(); + let fake_0_hash = init_blocks[1].block_hash().to_string(); + let block: Header = serde_json::from_value(json!({ + "version": 1, + "prev_block_hash": fake_0_hash, + "merkle_root": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + "time": 1_231_006_510, + "bits": 486_604_799, + "nonce": 2_083_236_893_u32, + })) + .unwrap(); + + let outcome = unauthorized_account + .call(contract.id(), "submit_blocks") + .args_borsh([block].to_vec()) + .deposit(STORAGE_DEPOSIT_PER_BLOCK) + .transact() + .await?; + + assert!( + !outcome.is_success(), + "Expected submit_blocks to fail for an account without roles, but it succeeded" + ); + + let failure_message = format!("{:?}", outcome.failures()); + assert!( + failure_message.contains("Relayer is not active"), + "Expected failure message to contain 'Relayer is not active', but got: {failure_message}", + ); + + Ok(()) + } + fn genesis_block_header() -> Header { let json_value = serde_json::json!({ "version": 1, diff --git a/contract/tests/test_dogecoin.rs b/contract/tests/test_dogecoin.rs index 363ccc5f..b444ce3d 100644 --- a/contract/tests/test_dogecoin.rs +++ b/contract/tests/test_dogecoin.rs @@ -70,6 +70,29 @@ mod test_dogecoin { blocks } + /// Grant the `UnrestrictedSubmitBlocks` role to an account so it passes the + /// `#[trusted_relayer]` guard on `submit_blocks`. The contract itself is the + /// super admin (set during `init`), so it can grant any role. + async fn grant_relayer_role( + contract: &Contract, + account: &Account, + ) -> Result<(), Box> { + let outcome = contract + .call("acl_grant_role") + .args_json(json!({ + "role": "UnrestrictedSubmitBlocks", + "account_id": account.id(), + })) + .transact() + .await?; + assert!( + outcome.is_success(), + "Failed to grant role: {:?}", + outcome.failures() + ); + Ok(()) + } + async fn init_dogecoin_contract() -> Result<(Contract, Account), Box> { let sandbox = near_workspaces::sandbox().await?; let wasm = compile_dogecoin_wasm().await; @@ -99,6 +122,7 @@ mod test_dogecoin { ); let user_account = sandbox.dev_create_account().await?; + grant_relayer_role(&contract, &user_account).await?; Ok((contract, user_account)) } @@ -326,6 +350,7 @@ mod test_dogecoin { ); let user_account = sandbox.dev_create_account().await?; + grant_relayer_role(&contract, &user_account).await?; // Submit block 5_800_013 with full PoW + AuxPoW verification. let aux_data = build_aux_data_5800013(); diff --git a/contract/tests/test_zcash.rs b/contract/tests/test_zcash.rs index 42ead979..c173512a 100644 --- a/contract/tests/test_zcash.rs +++ b/contract/tests/test_zcash.rs @@ -27,6 +27,29 @@ mod test_zcash { std::fs::read(&file).unwrap() } + /// Grant the `UnrestrictedSubmitBlocks` role to an account so it passes the + /// `#[trusted_relayer]` guard on `submit_blocks`. The contract itself is the + /// super admin (set during `init`), so it can grant any role. + async fn grant_relayer_role( + contract: &Contract, + account: &Account, + ) -> Result<(), Box> { + let outcome = contract + .call("acl_grant_role") + .args_json(json!({ + "role": "UnrestrictedSubmitBlocks", + "account_id": account.id(), + })) + .transact() + .await?; + assert!( + outcome.is_success(), + "Failed to grant role: {:?}", + outcome.failures() + ); + Ok(()) + } + async fn init_zcash_contract() -> Result<(Contract, Account), Box> { let sandbox = near_workspaces::sandbox().await?; let contract_wasm = build_contract().await; @@ -59,6 +82,7 @@ mod test_zcash { assert!(outcome.is_success()); let user_account = sandbox.dev_create_account().await?; + grant_relayer_role(&contract, &user_account).await?; Ok((contract, user_account)) }