diff --git a/Cargo.lock b/Cargo.lock index 44f1949205..03a212ca9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,6 +553,20 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backoff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fe17f59a06fe8b87a6fc8bf53bb70b3aba76d7685f432487a68cd5552853625" +dependencies = [ + "futures-core", + "getrandom 0.2.10", + "instant", + "pin-project", + "rand 0.8.5", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.67" @@ -610,6 +624,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "beef" version = "0.5.2" @@ -672,11 +692,51 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitcoin" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e99ff7289b20a7385f66a0feda78af2fc119d28fb56aea8886a9cd0a4abdd75" +dependencies = [ + "bech32", + "bitcoin-private", + "bitcoin_hashes 0.12.0", + "hex_lit", + "secp256k1 0.27.0", + "serde", +] + +[[package]] +name = "bitcoin" +version = "1.1.0" +dependencies = [ + "async-trait", + "backoff", + "bitcoincore-rpc", + "cfg-if", + "clap", + "futures", + "hex", + "hyper", + "log", + "num 0.2.1", + "num-derive", + "num-traits", + "reqwest", + "serde", + "serde_json", + "sha2 0.8.2", + "sp-core", + "thiserror", + "tokio", + "url", +] + [[package]] name = "bitcoin" version = "1.2.0" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.7.6", "frame-support", "hex", "impl-serde 0.3.2", @@ -690,12 +750,52 @@ dependencies = [ "spin 0.7.1", ] +[[package]] +name = "bitcoin-private" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" + [[package]] name = "bitcoin_hashes" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b375d62f341cef9cd9e77793ec8f1db3fc9ce2e4d57e982c8fe697a2c16af3b6" +[[package]] +name = "bitcoin_hashes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +dependencies = [ + "bitcoin-private", + "serde", +] + +[[package]] +name = "bitcoincore-rpc" +version = "0.17.0" +source = "git+https://github.com/rust-bitcoin/rust-bitcoincore-rpc?rev=7bd815f1e1ae721404719ee8e6867064b7c68494#7bd815f1e1ae721404719ee8e6867064b7c68494" +dependencies = [ + "bitcoin-private", + "bitcoincore-rpc-json", + "jsonrpc", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "bitcoincore-rpc-json" +version = "0.17.0" +source = "git+https://github.com/rust-bitcoin/rust-bitcoincore-rpc?rev=7bd815f1e1ae721404719ee8e6867064b7c68494#7bd815f1e1ae721404719ee8e6867064b7c68494" +dependencies = [ + "bitcoin 0.30.1", + "bitcoin-private", + "serde", + "serde_json", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -861,7 +961,7 @@ checksum = "bd769563b4ea2953e2825c9e6b7470a5f55f67e0be00030bf3e390a2a6071f64" name = "btc-relay" version = "1.2.0" dependencies = [ - "bitcoin", + "bitcoin 1.2.0", "frame-benchmarking", "frame-support", "frame-system", @@ -2354,7 +2454,7 @@ dependencies = [ "asn1-rs 0.3.1", "displaydoc", "nom", - "num-bigint", + "num-bigint 0.4.3", "num-traits", "rusticata-macros", ] @@ -2368,7 +2468,7 @@ dependencies = [ "asn1-rs 0.5.2", "displaydoc", "nom", - "num-bigint", + "num-bigint 0.4.3", "num-traits", "rusticata-macros", ] @@ -2819,6 +2919,15 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + [[package]] name = "enum-as-inner" version = "0.5.1" @@ -4401,6 +4510,12 @@ dependencies = [ "proc-macro-hack", ] +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + [[package]] name = "hkdf" version = "0.12.3" @@ -4547,6 +4662,19 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -4751,7 +4879,8 @@ name = "interbtc-parachain" version = "1.2.0" dependencies = [ "async-trait", - "bitcoin", + "bitcoin 1.1.0", + "bitcoin 1.2.0", "btc-relay-rpc-runtime-api", "clap", "cumulus-client-cli", @@ -4784,6 +4913,7 @@ dependencies = [ "frame-support", "frame-system", "futures", + "hex", "hex-literal 0.2.2", "interbtc-primitives", "interbtc-rpc", @@ -4795,6 +4925,7 @@ dependencies = [ "loans-rpc-runtime-api", "log", "oracle-rpc-runtime-api", + "pallet-balances", "pallet-evm", "pallet-transaction-payment", "pallet-transaction-payment-rpc", @@ -4823,6 +4954,7 @@ dependencies = [ "sc-telemetry", "sc-tracing", "sc-transaction-pool", + "sc-transaction-pool-api", "serde", "serde_json", "sp-api", @@ -4844,6 +4976,7 @@ dependencies = [ "substrate-build-script-utils", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", + "tokio", "try-runtime-cli", "vault-registry-rpc-runtime-api", ] @@ -4852,7 +4985,7 @@ dependencies = [ name = "interbtc-primitives" version = "1.2.0" dependencies = [ - "bitcoin", + "bitcoin 1.2.0", "bstringify", "parity-scale-codec", "primitive-types", @@ -4930,7 +5063,7 @@ name = "interlay-runtime-parachain" version = "1.2.0" dependencies = [ "annuity", - "bitcoin", + "bitcoin 1.2.0", "btc-relay", "btc-relay-rpc-runtime-api", "clients-info", @@ -5072,7 +5205,7 @@ dependencies = [ "socket2 0.5.3", "widestring", "windows-sys 0.48.0", - "winreg", + "winreg 0.50.0", ] [[package]] @@ -5097,7 +5230,7 @@ dependencies = [ name = "issue" version = "1.2.0" dependencies = [ - "bitcoin", + "bitcoin 1.2.0", "btc-relay", "currency", "fee", @@ -5182,6 +5315,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpc" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8128f36b47411cd3f044be8c1f5cc0c9e24d1d1bfdc45f0a57897b32513053f2" +dependencies = [ + "base64 0.13.1", + "serde", + "serde_json", +] + [[package]] name = "jsonrpsee" version = "0.16.2" @@ -5353,7 +5497,7 @@ name = "kintsugi-runtime-parachain" version = "1.2.0" dependencies = [ "annuity", - "bitcoin", + "bitcoin 1.2.0", "btc-relay", "btc-relay-rpc-runtime-api", "clients-info", @@ -6543,6 +6687,12 @@ dependencies = [ "thrift", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -6803,8 +6953,8 @@ dependencies = [ "approx", "matrixmultiply", "nalgebra-macros", - "num-complex", - "num-rational", + "num-complex 0.4.3", + "num-rational 0.4.1", "num-traits", "simba", "typenum", @@ -6985,17 +7135,42 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex 0.2.4", + "num-integer", + "num-iter", + "num-rational 0.2.4", + "num-traits", +] + [[package]] name = "num" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ - "num-bigint", - "num-complex", + "num-bigint 0.4.3", + "num-complex 0.4.3", "num-integer", "num-iter", - "num-rational", + "num-rational 0.4.1", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg 1.1.0", + "num-integer", "num-traits", ] @@ -7010,6 +7185,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg 1.1.0", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.3" @@ -7019,6 +7204,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "num-format" version = "0.4.4" @@ -7050,6 +7246,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg 1.1.0", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.1" @@ -7057,7 +7265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg 1.1.0", - "num-bigint", + "num-bigint 0.4.3", "num-integer", "num-traits", ] @@ -7937,7 +8145,7 @@ version = "2.0.0-dev" source = "git+https://github.com/paritytech/frontier?branch=polkadot-v0.9.42#1a718546085be20ce381b70e1f9e4c8b4d4b1f03" dependencies = [ "fp-evm", - "num", + "num 0.4.1", ] [[package]] @@ -8644,7 +8852,7 @@ name = "parachain-tests" version = "1.2.0" dependencies = [ "annuity", - "bitcoin", + "bitcoin 1.2.0", "btc-relay", "btc-relay-rpc-runtime-api", "clients-info", @@ -10896,7 +11104,7 @@ dependencies = [ name = "redeem" version = "1.2.0" dependencies = [ - "bitcoin", + "bitcoin 1.2.0", "btc-relay", "currency", "fee", @@ -11069,7 +11277,7 @@ dependencies = [ name = "replace" version = "1.2.0" dependencies = [ - "bitcoin", + "bitcoin 1.2.0", "btc-relay", "currency", "fee", @@ -11119,6 +11327,43 @@ dependencies = [ "sp-std", ] +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64 0.21.2", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite 0.2.9", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.10.1", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -11888,8 +12133,8 @@ dependencies = [ "fork-tree", "futures", "log", - "num-bigint", - "num-rational", + "num-bigint 0.4.3", + "num-rational 0.4.1", "num-traits", "parity-scale-codec", "parking_lot 0.12.1", @@ -13016,6 +13261,18 @@ dependencies = [ "secp256k1-sys 0.6.1", ] +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "bitcoin_hashes 0.12.0", + "rand 0.8.5", + "secp256k1-sys 0.8.1", + "serde", +] + [[package]] name = "secp256k1-sys" version = "0.4.0" @@ -13033,6 +13290,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -13147,6 +13413,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha-1" version = "0.9.8" @@ -13268,7 +13546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" dependencies = [ "approx", - "num-complex", + "num-complex 0.4.3", "num-traits", "paste", "wide", @@ -14852,6 +15130,16 @@ dependencies = [ "syn 2.0.22", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.23.4" @@ -15094,7 +15382,7 @@ dependencies = [ "impl-trait-for-tuples", "interbtc-primitives", "log", - "num-bigint", + "num-bigint 0.4.3", "num-traits", "parity-scale-codec", "scale-info", @@ -15430,7 +15718,7 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" name = "vault-registry" version = "1.2.0" dependencies = [ - "bitcoin", + "bitcoin 1.2.0", "currency", "fee", "fixed-hash 0.7.0", @@ -15762,7 +16050,7 @@ dependencies = [ "downcast-rs", "libm 0.2.7", "memory_units", - "num-rational", + "num-rational 0.4.1", "num-traits", "region", ] @@ -16597,6 +16885,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/crates/bitcoin/src/parser.rs b/crates/bitcoin/src/parser.rs index f57345eda2..44f1ed604f 100644 --- a/crates/bitcoin/src/parser.rs +++ b/crates/bitcoin/src/parser.rs @@ -413,7 +413,7 @@ pub(crate) mod tests { #[test] fn test_parse_block_header() { - let hex_header = sample_block_header(); + let hex_header = "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2002000000"; let parsed_header = BlockHeader::from_hex(&hex_header).unwrap(); assert_eq!(parsed_header.version, 4); assert_eq!(parsed_header.timestamp, 1415239972); diff --git a/crates/btc-relay/src/lib.rs b/crates/btc-relay/src/lib.rs index 9844414331..8c4831afcd 100644 --- a/crates/btc-relay/src/lib.rs +++ b/crates/btc-relay/src/lib.rs @@ -339,7 +339,7 @@ pub mod pallet { /// Stores a mapping from (chain_index, block_height) to block hash #[pallet::storage] - pub(super) type ChainsHashes = + pub type ChainsHashes = StorageDoubleMap<_, Blake2_128Concat, u32, Blake2_128Concat, u32, H256Le, ValueQuery>; /// Store the current blockchain tip @@ -352,7 +352,7 @@ pub mod pallet { /// BTC height when the relay was initialized #[pallet::storage] - pub(super) type StartBlockHeight = StorageValue<_, u32, ValueQuery>; + pub type StartBlockHeight = StorageValue<_, u32, ValueQuery>; /// Increment-only counter used to track new BlockChain entries #[pallet::storage] diff --git a/parachain/Cargo.toml b/parachain/Cargo.toml index 29e46babfc..a9f19b20c7 100644 --- a/parachain/Cargo.toml +++ b/parachain/Cargo.toml @@ -25,13 +25,15 @@ futures = "0.3.15" jsonrpsee = { version = "0.16.2", features = ["server", "macros"] } serde_json = "1.0.68" regex = "1.5.6" +bitcoin_client = { path = "../../polkabtc-clients/bitcoin/", package = "bitcoin", features=["cli"]} +hex = "0.4.2" # Parachain dependencies interlay-runtime = { package = "interlay-runtime-parachain", path = "./runtime/interlay" } kintsugi-runtime = { package = "kintsugi-runtime-parachain", path = "./runtime/kintsugi" } runtime-common = { package = "runtime-common", path = "./runtime/common" } interbtc-rpc = { path = "../rpc" } -bitcoin = { path = "../crates/bitcoin" } +bitcoin = { path = "../crates/bitcoin", features = ["parser"] } loans = { path = "../crates/loans" } primitives = { package = "interbtc-primitives", path = "../primitives" } @@ -58,6 +60,7 @@ sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v sc-service = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.31" } sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.31" } sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.31" } +sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.31" } sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.31" } sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.31" } sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.31" } @@ -124,6 +127,9 @@ fp-evm = { git = "https://github.com/paritytech/frontier", branch = "polkadot-v0 fp-rpc = { git = "https://github.com/paritytech/frontier", branch = "polkadot-v0.9.42" } pallet-evm = { git = "https://github.com/paritytech/frontier", branch = "polkadot-v0.9.42" } +tokio = "1.22.0" +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } + [features] default = [] diff --git a/parachain/runtime/kintsugi/src/lib.rs b/parachain/runtime/kintsugi/src/lib.rs index e283de4d0c..1abf192a88 100644 --- a/parachain/runtime/kintsugi/src/lib.rs +++ b/parachain/runtime/kintsugi/src/lib.rs @@ -75,7 +75,7 @@ pub use sp_runtime::BuildStorage; pub use sp_runtime::{FixedU128, Perbill, Permill}; // interBTC exports -pub use btc_relay::{bitcoin, Call as BtcRelayCall, TARGET_SPACING}; +pub use btc_relay::{self, bitcoin, Call as BtcRelayCall, TARGET_SPACING}; pub use constants::{currency::*, time::*}; pub use oracle_rpc_runtime_api::BalanceWrapper; pub use orml_asset_registry::AssetMetadata; diff --git a/parachain/src/cli.rs b/parachain/src/cli.rs index f6aaad6011..ce9fdb7c8f 100644 --- a/parachain/src/cli.rs +++ b/parachain/src/cli.rs @@ -90,6 +90,10 @@ pub struct Cli { #[clap(flatten)] pub eth: EthConfiguration, + /// Connection settings for Bitcoin Core for relay purposes. + #[clap(flatten)] + pub bitcoin: bitcoin_client::cli::BitcoinOpts, + /// Relaychain arguments #[clap(raw = true)] pub relaychain_args: Vec, diff --git a/parachain/src/command.rs b/parachain/src/command.rs index e3aa51ec4e..1c58bc4607 100644 --- a/parachain/src/command.rs +++ b/parachain/src/command.rs @@ -470,6 +470,9 @@ pub fn run() -> Result<()> { runner .run_node_until_exit(|config| async move { + log::info!("Im here"); + // plan: use pool. + // bitcoin_rpc. if cli.instant_seal { start_instant(cli, config).await } else { @@ -484,7 +487,9 @@ pub fn run() -> Result<()> { async fn start_instant(cli: Cli, config: Configuration) -> sc_service::error::Result { with_runtime_or_err!(config.chain_spec, { { - crate::service::start_instant::(config, cli.eth) + log::info!("starting instant.."); + + crate::service::start_instant::(config, cli.eth, cli.bitcoin) .await .map(|r| r.0) .map_err(Into::into) diff --git a/parachain/src/embedded_relay.rs b/parachain/src/embedded_relay.rs new file mode 100644 index 0000000000..d4b42eccdb --- /dev/null +++ b/parachain/src/embedded_relay.rs @@ -0,0 +1,324 @@ +use crate::service::{FullBackend, FullClient, RuntimeApiCollection}; +use async_trait::async_trait; +use bitcoin_client::RandomDelay; +use bitcoin_client::{ + relay::Issuing, //Error as DirectRelayError, + BitcoinCoreApi, +}; +use cumulus_client_cli::CollatorOptions; +use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; +use cumulus_client_consensus_common::{ParachainBlockImport as TParachainBlockImport, ParachainConsensus}; +use cumulus_client_network::BlockAnnounceValidator; +use cumulus_client_service::{ + prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, +}; +use cumulus_primitives_core::ParaId; +use cumulus_primitives_parachain_inherent::{MockValidationDataInherentDataProvider, MockXcmConfig}; +use cumulus_relay_chain_inprocess_interface::build_inprocess_relay_chain; +use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult}; +use cumulus_relay_chain_minimal_node::build_minimal_relay_chain_node; +use frame_support::{storage::storage_prefix, Blake2_128Concat, StorageHasher}; +use futures::StreamExt; +use polkadot_primitives::BlockId; +use polkadot_service::{Client, CollatorPair}; +use primitives::*; +use sc_client_api::{BlockBackend, HeaderBackend, StateBackendFor}; +use sc_consensus::{ImportQueue, LongestChain}; +use sc_executor::{HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; +use sc_network::NetworkBlock; +use sc_network_sync::SyncingService; +use sc_service::{Configuration, PartialComponents, RpcHandlers, TFullBackend, TFullClient, TaskManager}; +use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sc_transaction_pool::{ChainApi, Pool}; +use sp_api::{ConstructRuntimeApi, Encode, StateBackend}; +use sp_consensus_aura::{ + sr25519::{AuthorityId as AuraId, AuthorityPair as AuraPair}, + SlotDuration, +}; +use sp_core::{Pair, H256}; +use sp_keyring::Sr25519Keyring; +use sp_keystore::KeystorePtr; +use sp_runtime::{ + traits::{BlakeTwo256, Block as BlockT}, + OpaqueExtrinsic, SaturatedConversion, +}; +use std::{sync::Arc, time::Duration}; +use substrate_prometheus_endpoint::Registry; +use tokio::sync::Mutex; + +pub fn create_extrinsic( + client: Arc>>, + nonce: u32, + call: kintsugi_runtime::RuntimeCall, +) -> OpaqueExtrinsic +where + Executor: sc_executor::NativeExecutionDispatch + 'static, +{ + let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + let best_hash = client.chain_info().best_hash; + let best_block = client.chain_info().best_number; + + let period = kintsugi_runtime::BlockHashCount::get() + .checked_next_power_of_two() + .map(|c| c / 2) + .unwrap_or(2) as u64; + + let extra: kintsugi_runtime::SignedExtra = ( + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(sp_runtime::generic::Era::mortal( + period, + best_block.saturated_into(), + )), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + // frame_system::CheckNonZeroSender::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(0), + ); + + /// The payload being signed + type SignedPayload = + sp_runtime::generic::SignedPayload; + + let raw_payload = SignedPayload::from_raw( + call.clone(), + extra.clone(), + ( + kintsugi_runtime::VERSION.spec_version, + kintsugi_runtime::VERSION.transaction_version, + genesis_hash, + best_hash, + (), + (), + (), + ), + ); + let sender = Sr25519Keyring::Alice.pair(); + let signature = raw_payload.using_encoded(|e| sender.sign(e)); + + kintsugi_runtime::UncheckedExtrinsic::new_signed( + call.clone(), + sp_runtime::AccountId32::from(sender.public()).into(), + kintsugi_runtime::Signature::Sr25519(signature.clone()), + extra.clone(), + ) + .into() +} + +/// This is adapted from the substrate code +pub fn storage_map_final_key( + pallet_prefix: &str, + map_name: &str, + key: impl codec::Encode, +) -> Vec { + let key_hashed = H::hash(&key.encode()); + let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes()); + let storage_prefix_hashed = frame_support::Twox128::hash(map_name.as_bytes()); + + let mut final_key = + Vec::with_capacity(pallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len()); + + final_key.extend_from_slice(&pallet_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key +} + +/// This is adapted from the substrate code +pub fn storage_double_map_final_key( + pallet_prefix: &str, + map_name: &str, + key1: impl codec::Encode, + key2: impl codec::Encode, +) -> Vec { + let key1_hashed = H1::hash(&key1.encode()); + let key2_hashed = H2::hash(&key2.encode()); + let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes()); + let storage_prefix_hashed = frame_support::Twox128::hash(map_name.as_bytes()); + + let mut final_key = Vec::with_capacity( + pallet_prefix_hashed.len() + + storage_prefix_hashed.len() + + key1_hashed.as_ref().len() + + key2_hashed.as_ref().len(), + ); + + final_key.extend_from_slice(&pallet_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key1_hashed.as_ref()); + final_key.extend_from_slice(key2_hashed.as_ref()); + + final_key +} + +pub struct DirectIssuer +where + PoolApi: ChainApi + 'static, + Executor: sc_executor::NativeExecutionDispatch + 'static, + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: RuntimeApiCollection>, + RuntimeApi::RuntimeApi: sp_consensus_aura::AuraApi, +{ + pool: Arc>, + client: Arc>, +} + +impl DirectIssuer +where + PoolApi: ChainApi + 'static, + Executor: sc_executor::NativeExecutionDispatch + 'static, + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: RuntimeApiCollection>, + RuntimeApi::RuntimeApi: sp_consensus_aura::AuraApi, +{ + pub async fn new(pool: Arc>, client: Arc>) -> Self { + // system.account(alice) + + Self { pool, client } + } + + fn read_storage(&self, address: &[u8]) -> Option { + let info = self.client.chain_info(); + let state = self.client.state_at(info.best_hash).unwrap().storage(address).unwrap(); + state.map(|x| codec::Decode::decode(&mut &x[..]).unwrap()) + } + + async fn get_nonce(&self) -> u32 { + let alice = Sr25519Keyring::Alice.to_account_id(); + let address = storage_map_final_key::("System", "Account", alice); + + self.read_storage(&address).unwrap_or_default() + } + async fn call(&self, call: kintsugi_runtime::RuntimeCall) { + let info = self.client.chain_info(); + + let nonce = self.get_nonce().await; + + let tx = create_extrinsic(self.client.clone(), nonce, call); + + // todo: wait until inclusion: use submit_and_watch + let watcher = self + .pool + .submit_and_watch( + &BlockId::Hash(info.best_hash), + sp_runtime::transaction_validity::TransactionSource::Local, + tx, + ) + .await + .unwrap(); + let mut stream = watcher.into_stream(); + while let Some(x) = stream.next().await { + log::error!("Status: {:?}", x); + if matches!(x, sc_transaction_pool_api::TransactionStatus::InBlock(_)) { + return; + } + } + panic!("tx failure"); + } +} +#[derive(Clone, Debug)] +pub struct ZeroDelay; + +#[async_trait] +impl RandomDelay for ZeroDelay { + type Error = DirectRelayError; + async fn delay(&self, _seed_data: &[u8; 32]) -> Result<(), DirectRelayError> { + Ok(()) + } +} + +#[derive(Debug)] +pub enum DirectRelayError { + // we could return actual errors but since we don't really expect any and it's + // just for development, we stick with unwrapping for now +} + +#[async_trait] +impl Issuing for DirectIssuer +where + PoolApi: ChainApi + 'static, + Executor: sc_executor::NativeExecutionDispatch + 'static, + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: RuntimeApiCollection>, + RuntimeApi::RuntimeApi: sp_consensus_aura::AuraApi, +{ + type Error = DirectRelayError; + async fn is_initialized(&self) -> Result { + let address = storage_prefix(b"BTCRelay", b"StartBlockHeight"); + Ok(self.read_storage::(&address).is_some()) + } + + async fn initialize(&self, header: Vec, height: u32) -> Result<(), DirectRelayError> { + let block_header = bitcoin::parser::parse_block_header(&header).unwrap(); + + let call = kintsugi_runtime::RuntimeCall::BTCRelay(kintsugi_runtime::btc_relay::Call::initialize { + block_header, + block_height: height, + }); + + log::error!("pre-call"); + self.call(call).await; + log::error!("post-call"); + + Ok(()) + } + + async fn submit_block_header( + &self, + header: Vec, + _random_delay: Arc + Send + Sync>>, + ) -> Result<(), DirectRelayError> { + let block_header = bitcoin::parser::parse_block_header(&header).unwrap(); + + let call = kintsugi_runtime::RuntimeCall::BTCRelay(kintsugi_runtime::btc_relay::Call::store_block_header { + block_header, + fork_bound: 10, + }); + + self.call(call).await; + + Ok(()) + } + + async fn submit_block_header_batch(&self, headers: Vec>) -> Result<(), DirectRelayError> { + for header in headers { + self.submit_block_header(header, Arc::new(Box::new(ZeroDelay))) + .await + .unwrap(); + } + Ok(()) + } + + async fn get_best_height(&self) -> Result { + let address = storage_prefix(b"BTCRelay", b"BestBlockHeight"); + Ok(self.read_storage::(&address).unwrap_or_default()) + } + + async fn get_block_hash(&self, height: u32) -> Result, DirectRelayError> { + let address = storage_double_map_final_key::( + "BTCRelay", + "ChainsHashes", + 0u32, + height, + ); + + let hash = self.read_storage::(&address).unwrap(); + Ok(hex::decode(hash.to_hex_le()).unwrap()) + } + + async fn is_block_stored(&self, hash_le: Vec) -> Result { + let hash = H256Le::from_bytes_le(&hash_le); + let key = storage_map_final_key::("BTCRelay", "BlockHeaders", hash); + + // don't bother decoding, just check if it exists + let state = self + .client + .state_at(self.client.chain_info().best_hash) + .unwrap() + .storage(&key) + .unwrap(); + Ok(state.is_some()) + } +} diff --git a/parachain/src/lib.rs b/parachain/src/lib.rs index 5a048e9d6d..fd6e4f6b0a 100644 --- a/parachain/src/lib.rs +++ b/parachain/src/lib.rs @@ -1,4 +1,5 @@ pub mod chain_spec; +pub mod embedded_relay; pub mod service; mod eth; diff --git a/parachain/src/main.rs b/parachain/src/main.rs index b5e880fa4b..1072d6cf32 100644 --- a/parachain/src/main.rs +++ b/parachain/src/main.rs @@ -5,6 +5,7 @@ mod chain_spec; #[macro_use] mod cli; mod command; +mod embedded_relay; mod eth; mod service; diff --git a/parachain/src/service.rs b/parachain/src/service.rs index 1b02e504f9..65b07b344f 100644 --- a/parachain/src/service.rs +++ b/parachain/src/service.rs @@ -1,3 +1,5 @@ +use crate::embedded_relay::*; + use cumulus_client_cli::CollatorOptions; use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; use cumulus_client_consensus_common::{ParachainBlockImport as TParachainBlockImport, ParachainConsensus}; @@ -10,7 +12,9 @@ use cumulus_primitives_parachain_inherent::{MockValidationDataInherentDataProvid use cumulus_relay_chain_inprocess_interface::build_inprocess_relay_chain; use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult}; use cumulus_relay_chain_minimal_node::build_minimal_relay_chain_node; + use futures::StreamExt; + use polkadot_service::CollatorPair; use primitives::*; use sc_client_api::{HeaderBackend, StateBackendFor}; @@ -20,17 +24,21 @@ use sc_network::NetworkBlock; use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, RpcHandlers, TFullBackend, TFullClient, TaskManager}; use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; -use sp_api::ConstructRuntimeApi; + +use sp_api::{ConstructRuntimeApi, Encode, StateBackend}; use sp_consensus_aura::{ sr25519::{AuthorityId as AuraId, AuthorityPair as AuraPair}, SlotDuration, }; use sp_core::H256; + use sp_keystore::KeystorePtr; use sp_runtime::traits::{BlakeTwo256, Block as BlockT}; use std::{sync::Arc, time::Duration}; use substrate_prometheus_endpoint::Registry; +use bitcoin_client::RandomDelay; + // Frontier imports use crate::eth::{ new_eth_deps, new_frontier_partial, open_frontier_backend, spawn_frontier_tasks, EthCompatRuntimeApiCollection, @@ -686,9 +694,34 @@ where .await } +#[async_trait::async_trait] +trait Q { + fn f(isser: I, x: Arc + Send + Sync + 'static>>) { + } +} + +struct W; +impl Q for W { + fn f(isser: I, x: Arc + Send + Sync + 'static>>) { + } +} +fn f(isser: I, x: Arc + Send + Sync + 'static>>) {} + +/// Runner implements the main loop for the relayer +pub struct Runnerz; + +impl Runnerz { + pub fn new( + issuing: I, + random_delay: Arc + Send + Sync + 'static>>, + ) { + } +} + pub async fn start_instant( mut config: Configuration, eth_config: EthConfiguration, + bitcoin_config: bitcoin_client::cli::BitcoinOpts, ) -> sc_service::error::Result<(TaskManager, RpcHandlers)> where RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, @@ -697,6 +730,8 @@ where Executor: sc_executor::NativeExecutionDispatch + 'static, CT: fp_rpc::ConvertTransaction<::Extrinsic> + Clone + Default + Send + Sync + 'static, { + log::info!("In instant.."); + let sc_service::PartialComponents { client, backend, @@ -839,6 +874,36 @@ where } }; + let moved_pool = transaction_pool.clone(); + let moved_client = client.clone(); + + if matches!(bitcoin_config.bitcoin_rpc_url, Some(ref x) if x != "") { + log::info!("Starting bitcoin relay..."); + + // bitcoin url is set, start relayer + let bitcoin_rpc = bitcoin_config.new_client(Some("alice".into())).await.unwrap(); + + task_manager.spawn_handle().spawn("btc-relay", None, async move { + // todo: without this sleep, sometimes making a call get stuck. The status + // of the tx will be `ready` but won't get to `in_block`. It may be that + // some other tasks needs to finish initializing + tokio::time::sleep(Duration::from_secs(5)).await; + let pool = moved_pool.pool(); + let direct_issuer = DirectIssuer::new(pool.clone(), moved_client.clone()).await; + + let cfg = bitcoin_client::Config { + start_height: None, + max_batch_size: 1, + interval: Some(Duration::from_secs(1)), + btc_confirmations: 1, + }; + let runner = bitcoin_client::Runner::new(bitcoin_rpc, direct_issuer, cfg, Arc::new(Box::new(ZeroDelay))); + loop { + runner.submit_next().await.unwrap(); + } + }); + } + let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { rpc_builder: Box::new(rpc_builder), client: client.clone(),