diff --git a/Cargo.lock b/Cargo.lock index c66aaa5f8c..44006f5f0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,9 +11,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.15.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ "gimli", ] @@ -44,6 +44,9 @@ name = "ahash" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" +dependencies = [ + "const-random", +] [[package]] name = "ahash" @@ -89,9 +92,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.41" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "arc-swap" @@ -154,12 +157,11 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.59" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" +checksum = "78ed203b9ba68b242c62b3fb7480f589dd49829be1edb3fe8fc8b4ffda2dcb8d" dependencies = [ "addr2line", - "cc", "cfg-if 1.0.0", "libc", "miniz_oxide 0.4.3", @@ -430,7 +432,7 @@ dependencies = [ "ckb-logger", "ckb-spawn", "ckb-stop-handler", - "tokio 1.7.0", + "tokio 1.5.0", ] [[package]] @@ -720,6 +722,7 @@ dependencies = [ name = "ckb-jsonrpc-types" version = "0.44.0-pre" dependencies = [ + "ckb-constant", "ckb-types", "faster-hex", "lazy_static", @@ -903,7 +906,7 @@ dependencies = [ "rand_distr", "serde", "serde_json", - "tokio 1.7.0", + "tokio 1.5.0", "tokio-compat-02", ] @@ -946,7 +949,7 @@ dependencies = [ "snap", "tempfile", "tentacle", - "tokio 1.7.0", + "tokio 1.5.0", "tokio-util 0.6.6", "trust-dns-resolver", ] @@ -1148,7 +1151,7 @@ dependencies = [ "ckb-vm", "ckb-vm-definitions", "faster-hex", - "goblin", + "goblin 0.2.3", "proptest", "serde", "tiny-keccak", @@ -1297,7 +1300,7 @@ dependencies = [ "ckb-channel", "ckb-logger", "parking_lot", - "tokio 1.7.0", + "tokio 1.5.0", ] [[package]] @@ -1344,7 +1347,7 @@ dependencies = [ "ckb-util", "ckb-verification", "ckb-verification-traits", - "dashmap", + "dashmap 4.0.2", "faketime", "faux", "futures", @@ -1414,7 +1417,7 @@ dependencies = [ "ckb-verification", "faketime", "lru", - "tokio 1.7.0", + "tokio 1.5.0", ] [[package]] @@ -1424,6 +1427,7 @@ dependencies = [ "bit-vec", "bytes 1.0.1", "ckb-channel", + "ckb-constant", "ckb-error", "ckb-fixed-hash", "ckb-hash", @@ -1491,7 +1495,7 @@ dependencies = [ "faketime", "rand 0.7.3", "rayon", - "tokio 1.7.0", + "tokio 1.5.0", ] [[package]] @@ -1504,26 +1508,29 @@ dependencies = [ [[package]] name = "ckb-vm" -version = "0.19.4" +version = "0.20.0-alpha2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4b7a3a2f19771d379884030417094c55986ccbc0d5caaaa651f7421ead4bb4" +checksum = "324a45880b65710f2dd5398ec6e941c96cedd764571e85be54b243422f228e75" dependencies = [ "byteorder", "bytes 1.0.1", "cc", "ckb-vm-definitions", "derive_more", - "goblin", + "goblin 0.2.3", + "goblin 0.4.0", "libc", "mapr", + "rand 0.7.3", "scroll", + "serde", ] [[package]] name = "ckb-vm-definitions" -version = "0.19.4" +version = "0.20.0-alpha2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5dd4b68248ffd8283d693a477f9594d195ceac25f6aa7f98e99d1b8f43f9b3e" +checksum = "df4d41afe817d71386d4c8bbbc5ec75d80e53b8a01da7b477c4848000cb13e7d" [[package]] name = "clap" @@ -1565,6 +1572,28 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "const-random" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" +dependencies = [ + "const-random-macro", + "proc-macro-hack", +] + +[[package]] +name = "const-random-macro" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" +dependencies = [ + "getrandom 0.2.0", + "lazy_static", + "proc-macro-hack", + "tiny-keccak", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -1674,8 +1703,8 @@ checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ "cfg-if 0.1.10", "crossbeam-channel 0.4.4", - "crossbeam-deque 0.7.3", - "crossbeam-epoch 0.8.2", + "crossbeam-deque", + "crossbeam-epoch", "crossbeam-queue", "crossbeam-utils 0.7.2", ] @@ -1699,38 +1728,17 @@ dependencies = [ "maybe-uninit", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.4", -] - [[package]] name = "crossbeam-deque" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" dependencies = [ - "crossbeam-epoch 0.8.2", + "crossbeam-epoch", "crossbeam-utils 0.7.2", "maybe-uninit", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch 0.9.4", - "crossbeam-utils 0.8.4", -] - [[package]] name = "crossbeam-epoch" version = "0.8.2" @@ -1742,20 +1750,7 @@ dependencies = [ "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", - "memoffset 0.5.1", - "scopeguard", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.4", - "lazy_static", - "memoffset 0.6.3", + "memoffset", "scopeguard", ] @@ -1791,17 +1786,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "crossbeam-utils" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278" -dependencies = [ - "autocfg 1.0.0", - "cfg-if 1.0.0", - "lazy_static", -] - [[package]] name = "crunchy" version = "0.2.2" @@ -1928,6 +1912,16 @@ dependencies = [ "libc", ] +[[package]] +name = "dashmap" +version = "3.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad86b725566cbbf4c0cb01a17bfd1c9ad1830786a02dfc11c380b21b08f02ed" +dependencies = [ + "ahash 0.3.8", + "cfg-if 0.1.10", +] + [[package]] name = "dashmap" version = "4.0.2" @@ -2077,9 +2071,9 @@ checksum = "b02a61fea82de8484f9d7ce99b698b0e190ef8de71035690a961a43d7b18a2ad" [[package]] name = "faux" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255bae09c55bba9e35b7ab3de3c2b959b7c91b64f3ea68020bb0e805eca8e5ac" +checksum = "40c3668239842a12c1810beec5afa357caa1aca3ee6b7cd9c60514af9787061f" dependencies = [ "faux_macros", "paste 1.0.5", @@ -2338,9 +2332,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.24.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" +checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" [[package]] name = "glob" @@ -2372,21 +2366,31 @@ dependencies = [ "scroll", ] +[[package]] +name = "goblin" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532a09cd3df2c6bbfc795fb0434bff8f22255d1d07328180e918a2e6ce122d4d" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "governor" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c5d2f987ee8f6dff3fa1a352058dc59b990e447e4c7846aa7d804971314f7b" +checksum = "36f302dc68f4035178051bff107a8181379b8baa3354654672c2f1e7134af983" dependencies = [ - "dashmap", + "dashmap 3.11.9", "futures", "futures-timer", "no-std-compat", "nonzero_ext", "parking_lot", "quanta 0.4.1", - "rand 0.8.3", - "smallvec 1.6.1", + "rand 0.7.3", ] [[package]] @@ -3025,9 +3029,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.97" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" [[package]] name = "libm" @@ -3139,15 +3143,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "memoffset" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d" -dependencies = [ - "autocfg 1.0.0", -] - [[package]] name = "merkle-cbt" version = "0.3.0" @@ -3235,7 +3230,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "277619f040719a5a23d75724586d5601286e8fa53451cfaaca3b8c627c2c2378" dependencies = [ - "crossbeam-epoch 0.8.2", + "crossbeam-epoch", "serde", ] @@ -3555,15 +3550,15 @@ dependencies = [ [[package]] name = "object" -version = "0.24.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" -version = "1.8.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "oorandom" @@ -3902,9 +3897,9 @@ checksum = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -3999,18 +3994,6 @@ dependencies = [ "rand_pcg 0.2.1", ] -[[package]] -name = "rand" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" -dependencies = [ - "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", -] - [[package]] name = "rand_chacha" version = "0.1.1" @@ -4031,16 +4014,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.2", -] - [[package]] name = "rand_core" version = "0.3.1" @@ -4065,15 +4038,6 @@ dependencies = [ "getrandom 0.1.6", ] -[[package]] -name = "rand_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" -dependencies = [ - "getrandom 0.2.0", -] - [[package]] name = "rand_distr" version = "0.3.0" @@ -4102,15 +4066,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core 0.6.2", -] - [[package]] name = "rand_isaac" version = "0.1.1" @@ -4175,25 +4130,25 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "dcf6960dc9a5b4ee8d3e4c5787b4a112a8818e0290a42ff664ad60692fdf2032" dependencies = [ "autocfg 1.0.0", - "crossbeam-deque 0.8.0", + "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf" dependencies = [ - "crossbeam-channel 0.5.1", - "crossbeam-deque 0.8.0", - "crossbeam-utils 0.8.4", + "crossbeam-channel 0.4.4", + "crossbeam-deque", + "crossbeam-utils 0.7.2", "lazy_static", "num_cpus", ] @@ -4445,9 +4400,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.126" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" dependencies = [ "serde_derive", ] @@ -4464,9 +4419,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" dependencies = [ "proc-macro2", "quote", @@ -4623,9 +4578,9 @@ checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" [[package]] name = "syn" -version = "1.0.73" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ "proc-macro2", "quote", @@ -4678,7 +4633,7 @@ dependencies = [ "tentacle-multiaddr", "tentacle-secio", "thiserror", - "tokio 1.7.0", + "tokio 1.5.0", "tokio-util 0.6.6", "tokio-yamux", "wasm-bindgen", @@ -4718,7 +4673,7 @@ dependencies = [ "ring", "secp256k1", "sha2", - "tokio 1.7.0", + "tokio 1.5.0", "tokio-util 0.6.6", "unsigned-varint", "x25519-dalek", @@ -4754,18 +4709,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.25" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.25" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", @@ -4842,9 +4797,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.7.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79ba603c337335df6ba6dd6afc38c38a7d5e1b0c871678439ea973cd62a118e" +checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" dependencies = [ "autocfg 1.0.0", "bytes 1.0.1", @@ -4870,7 +4825,7 @@ dependencies = [ "once_cell", "pin-project-lite 0.2.4", "tokio 0.2.25", - "tokio 1.7.0", + "tokio 1.5.0", "tokio-stream", ] @@ -4893,7 +4848,7 @@ checksum = "f8864d706fdb3cc0843a49647ac892720dac98a6eeb818b77190592cf4994066" dependencies = [ "futures-core", "pin-project-lite 0.2.4", - "tokio 1.7.0", + "tokio 1.5.0", ] [[package]] @@ -4931,7 +4886,7 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.2.4", - "tokio 1.7.0", + "tokio 1.5.0", ] [[package]] @@ -4944,7 +4899,7 @@ dependencies = [ "futures", "log", "nohash-hasher", - "tokio 1.7.0", + "tokio 1.5.0", "tokio-util 0.6.6", ] diff --git a/Makefile b/Makefile index c9e91a16b2..f69f6b44a5 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ cov: ## Run code coverage. .PHONY: wasm-build-test wasm-build-test: ## Build core packages for wasm target + cp -f Cargo.lock wasm-build-test/ cd wasm-build-test && cargo build --target=wasm32-unknown-unknown .PHONY: setup-ckb-test diff --git a/benches/benches/benchmarks/util.rs b/benches/benches/benchmarks/util.rs index 0cc77f0eed..27d86b1673 100644 --- a/benches/benches/benchmarks/util.rs +++ b/benches/benches/benchmarks/util.rs @@ -226,7 +226,7 @@ lazy_static! { let script = Script::new_builder() .code_hash(CellOutput::calc_data_hash(&data)) .args(Bytes::from(PUBKEY_HASH.as_bytes()).pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); (cell, data, script) diff --git a/chain/src/tests/block_assembler.rs b/chain/src/tests/block_assembler.rs index b6f97e0b3a..038981198d 100644 --- a/chain/src/tests/block_assembler.rs +++ b/chain/src/tests/block_assembler.rs @@ -34,7 +34,7 @@ fn start_chain(consensus: Option) -> (ChainController, Shared) { let config = BlockAssemblerConfig { code_hash: h256!("0x0"), args: Default::default(), - hash_type: ScriptHashType::Data, + hash_type: ScriptHashType::Data { vm_version: 0 }, message: Default::default(), }; let (shared, mut pack) = builder diff --git a/chain/src/tests/reward.rs b/chain/src/tests/reward.rs index 89318cff80..a41667243d 100644 --- a/chain/src/tests/reward.rs +++ b/chain/src/tests/reward.rs @@ -179,14 +179,14 @@ fn finalize_reward() { let bob = ScriptBuilder::default() .args(bob_args) .code_hash(always_success_script.code_hash()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let alice_args: packed::Bytes = Bytes::from(b"a11ce".to_vec()).pack(); let alice = ScriptBuilder::default() .args(alice_args) .code_hash(always_success_script.code_hash()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); for i in 1..23 { diff --git a/chain/src/tests/util.rs b/chain/src/tests/util.rs index 35d4feedae..90206eddfd 100644 --- a/chain/src/tests/util.rs +++ b/chain/src/tests/util.rs @@ -115,7 +115,7 @@ pub(crate) fn start_chain(consensus: Option) -> (ChainController, Sha let config = BlockAssemblerConfig { code_hash: h256!("0x0"), args: Default::default(), - hash_type: ScriptHashType::Data, + hash_type: ScriptHashType::Data { vm_version: 0 }, message: Default::default(), }; diff --git a/ckb-bin/src/subcommand/init.rs b/ckb-bin/src/subcommand/init.rs index d2b99a79c2..ffe2e3af71 100644 --- a/ckb-bin/src/subcommand/init.rs +++ b/ckb-bin/src/subcommand/init.rs @@ -4,7 +4,7 @@ use std::io::{self, Read}; use crate::helper::prompt; use ckb_app_config::{cli, AppConfig, ExitCode, InitArgs}; use ckb_chain_spec::ChainSpec; -use ckb_jsonrpc_types::ScriptHashType; +use ckb_jsonrpc_types::{ScriptHashTypeKind, VmVersion}; use ckb_resource::{ Resource, TemplateContext, AVAILABLE_SPECS, CKB_CONFIG_FILE_NAME, DB_OPTIONS_FILE_NAME, MINER_CONFIG_FILE_NAME, SPEC_DEV_FILE_NAME, @@ -48,7 +48,6 @@ pub fn init(args: InitArgs) -> Result<(), ExitCode> { let in_block_assembler_code_hash = prompt("code hash: "); let in_args = prompt("args: "); let in_hash_type = prompt("hash_type: "); - let in_message = prompt("message: "); args.block_assembler_code_hash = Some(in_block_assembler_code_hash.trim().to_string()); @@ -58,12 +57,29 @@ pub fn init(args: InitArgs) -> Result<(), ExitCode> { .map(|s| s.to_string()) .collect::>(); - args.block_assembler_message = Some(in_message.trim().to_string()); + args.block_assembler_hash_type_kind = + match serde_plain::from_str::(in_hash_type.trim()).ok() { + Some(hash_type) => hash_type, + None => { + eprintln!("Invalid block assembler hash type"); + return Err(ExitCode::Failure); + } + }; - match serde_plain::from_str::(in_hash_type.trim()).ok() { - Some(hash_type) => args.block_assembler_hash_type = hash_type, - None => eprintln!("Invalid block assembler hash type"), + if args.block_assembler_hash_type_kind == ScriptHashTypeKind::Data { + let in_vm_version = prompt("vm_version: "); + args.block_assembler_hash_type_vm_version = + match serde_plain::from_str::(in_vm_version.trim()).ok() { + Some(vm_version) => Some(vm_version), + None => { + eprintln!("Invalid block assembler vm version"); + return Err(ExitCode::Failure); + } + }; } + + let in_message = prompt("message: "); + args.block_assembler_message = Some(in_message.trim().to_string()); } // Try to find the default secp256k1 from bundled chain spec. @@ -90,11 +106,11 @@ pub fn init(args: InitArgs) -> Result<(), ExitCode> { let block_assembler = match block_assembler_code_hash { Some(hash) => { if let Some(default_code_hash) = &default_code_hash_option { - if ScriptHashType::Type != args.block_assembler_hash_type { + if ScriptHashTypeKind::Type != args.block_assembler_hash_type_kind { eprintln!( "WARN: the default lock should use hash type `{}`, you are using `{}`.\n\ It will require `ckb run --ba-advanced` to enable this block assembler", - DEFAULT_LOCK_SCRIPT_HASH_TYPE, args.block_assembler_hash_type + DEFAULT_LOCK_SCRIPT_HASH_TYPE, args.block_assembler_hash_type_kind ); } else if *default_code_hash != *hash { eprintln!( @@ -111,18 +127,43 @@ pub fn init(args: InitArgs) -> Result<(), ExitCode> { ); } } - format!( - "[block_assembler]\n\ - code_hash = \"{}\"\n\ - args = \"{}\"\n\ - hash_type = \"{}\"\n\ - message = \"{}\"", - hash, - args.block_assembler_args.join("\", \""), - serde_plain::to_string(&args.block_assembler_hash_type).unwrap(), - args.block_assembler_message - .unwrap_or_else(|| "0x".to_string()), - ) + if let Some(vm_version) = &args.block_assembler_hash_type_vm_version { + if ScriptHashTypeKind::Type == args.block_assembler_hash_type_kind { + eprintln!("VM version is not allowed for hash-type \"type\"."); + return Err(ExitCode::Failure); + } + format!( + "[block_assembler]\n\ + code_hash = \"{}\"\n\ + args = \"{}\"\n\ + hash_type.kind = \"{}\"\n\ + hash_type.vm_version = {}\n\ + message = \"{}\"", + hash, + args.block_assembler_args.join("\", \""), + args.block_assembler_hash_type_kind, + vm_version, + args.block_assembler_message + .unwrap_or_else(|| "0x".to_string()), + ) + } else { + if ScriptHashTypeKind::Data == args.block_assembler_hash_type_kind { + eprintln!("VM version should be provided for hash-type \"data\"."); + return Err(ExitCode::Failure); + } + format!( + "[block_assembler]\n\ + code_hash = \"{}\"\n\ + args = \"{}\"\n\ + hash_type.kind = \"{}\"\n\ + message = \"{}\"", + hash, + args.block_assembler_args.join("\", \""), + args.block_assembler_hash_type_kind, + args.block_assembler_message + .unwrap_or_else(|| "0x".to_string()), + ) + } } None => { eprintln!("WARN: mining feature is disabled because of lacking the block assembler config options"); @@ -131,7 +172,7 @@ pub fn init(args: InitArgs) -> Result<(), ExitCode> { # [block_assembler]\n\ # code_hash = \"{}\"\n\ # args = \"ckb-cli util blake2b --prefix-160 \"\n\ - # hash_type = \"{}\"\n\ + # hash_type.kind = \"{}\"\n\ # message = \"A 0x-prefixed hex string\"", default_code_hash_option.unwrap_or_default(), DEFAULT_LOCK_SCRIPT_HASH_TYPE, diff --git a/ckb-bin/src/subcommand/list_hashes.rs b/ckb-bin/src/subcommand/list_hashes.rs index 33fc44ec37..1df6833044 100644 --- a/ckb-bin/src/subcommand/list_hashes.rs +++ b/ckb-bin/src/subcommand/list_hashes.rs @@ -130,7 +130,7 @@ pub fn list_hashes(root_dir: PathBuf, matches: &ArgMatches<'_>) -> Result<(), Ex resource = Resource::bundled_ckb_config(); } - let mut config: CKBAppConfig = toml::from_slice(&resource.get()?)?; + let mut config = CKBAppConfig::load_from_slice(&resource.get()?)?; config.chain.spec.absolutize(&root_dir); let chain_spec = ChainSpec::load_from(&config.chain.spec).map_err(to_config_error)?; let spec_name = chain_spec.name.clone(); diff --git a/devtools/doc/rpc.py b/devtools/doc/rpc.py index 9ce9ab8000..72dcd1e513 100755 --- a/devtools/doc/rpc.py +++ b/devtools/doc/rpc.py @@ -500,7 +500,8 @@ def handle_endtag(self, tag): if self.variant_parser is not None: self.variant_parser.handle_endtag(tag) if self.variant_parser.completed(): - self.variants.append((self.next_variant, self.variant_parser)) + if self.next_variant not in [v[0] for v in self.variants]: + self.variants.append((self.next_variant, self.variant_parser)) self.next_variant = None self.variant_parser = None diff --git a/docs/hashes.toml b/docs/hashes.toml index 2961520da3..f79b825d9f 100644 --- a/docs/hashes.toml +++ b/docs/hashes.toml @@ -134,7 +134,7 @@ index = 1 # Spec: ckb_dev [ckb_dev] -spec_hash = "0xa8d7ab92196638cd091d49aa76849f6f102d8082eb374f089477d9c50a4bd2f1" +spec_hash = "0xc8dc9b41a93c64daf608231fd2061623c5cd73b10d6deb4ed22390324e358cc8" genesis = "0x823b2ff5785b12da8b1363cac9a5cbe566d8b715a4311441b119c39a0367488c" cellbase = "0xa563884b3686078ec7e7677a5f86449b15cf2693f3c1241766c6996f206cc541" diff --git a/resource/ckb-miner.toml b/resource/ckb-miner.toml index a8caf41576..1b8389f83c 100644 --- a/resource/ckb-miner.toml +++ b/resource/ckb-miner.toml @@ -5,6 +5,12 @@ # staging => # Config generated by `ckb init --chain staging` # }} +# Choose the edition, possible values: +# - "2019" +# - "2021" +# The default is "2019", the latest is "2021". +edition = "2021" + data_dir = "data" [chain] diff --git a/resource/ckb.toml b/resource/ckb.toml index ead6aa2c4e..21d427e557 100644 --- a/resource/ckb.toml +++ b/resource/ckb.toml @@ -5,6 +5,12 @@ # staging => # Config generated by `ckb init --chain staging` # }} +# Choose the edition, possible values: +# - "2019" +# - "2021" +# The default is "2019", the latest is "2021". +edition = "2021" + data_dir = "data" [chain] diff --git a/resource/specs/dev.toml b/resource/specs/dev.toml index 9a3801eddb..52e92b36ff 100644 --- a/resource/specs/dev.toml +++ b/resource/specs/dev.toml @@ -1,5 +1,11 @@ name = "ckb_dev" +# Choose the edition, possible values: +# - "2019" +# - "2021" +# The default is "2019", the latest is "2021". +edition = "2021" + [genesis] version = 0 parent_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" @@ -16,7 +22,8 @@ message = "ckb_dev" # {{ [genesis.genesis_cell.lock] code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" args = "0x" -hash_type = "data" +hash_type.kind = "data" +hash_type.vm_version = 0 # An array list paths to system cell files, which is absolute or relative to # the directory containing this config file. @@ -40,7 +47,8 @@ capacity = 100_000_0000_0000 [genesis.system_cells_lock] code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" args = "0x" -hash_type = "data" +hash_type.kind = "data" +hash_type.vm_version = 0 # Dep group cells [[genesis.dep_groups]] @@ -60,28 +68,29 @@ files = [ [genesis.bootstrap_lock] code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" args = "0x" -hash_type = "type" +hash_type.kind = "type" # Burn [[genesis.issued_cells]] capacity = 8_400_000_000_00000000 lock.code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" lock.args = "0x62e907b15cbf27d5425399ebf6f0fb50ebb88f18" -lock.hash_type = "data" +lock.hash_type.kind = "data" +lock.hash_type.vm_version = 0 # issue for random generated private key: d00c06bfd800d27397002dca6fb0993d5ba6399b4238b2f29ee9deb97593d2bc [[genesis.issued_cells]] capacity = 20_000_000_000_00000000 lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" lock.args = "0xc8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" -lock.hash_type = "type" +lock.hash_type.kind = "type" # issue for random generated private key: 63d86723e08f0f813a36ce6aa123bb2289d90680ae1e99d4de8cdb334553f24d [[genesis.issued_cells]] capacity = 5_198_735_037_00000000 lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" -lock.hash_type = "type" +lock.hash_type.kind = "type" [params] initial_primary_epoch_reward = 1_917_808_21917808 @@ -95,5 +104,12 @@ genesis_epoch_length = 1000 # Keep difficulty be permanent if the pow is Dummy. (default: false) permanent_difficulty_in_dummy = true +[params.hardfork] +rfc_pr_0221 = 0 +rfc_pr_0222 = 0 +rfc_pr_0223 = 0 +rfc_pr_0224 = 0 +rfc_pr_0237 = 0 + [pow] func = "Dummy" diff --git a/rpc/README.md b/rpc/README.md index 6458ee45a1..b4880ae3c4 100644 --- a/rpc/README.md +++ b/rpc/README.md @@ -323,7 +323,10 @@ Response "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -439,7 +442,10 @@ Response "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -684,7 +690,10 @@ Response "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -868,7 +877,10 @@ Response "lock": { "args": "0x", "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -1225,7 +1237,10 @@ Response "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -1420,7 +1435,10 @@ Request "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -1572,7 +1590,10 @@ Response "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -1682,7 +1703,10 @@ Request "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -2334,7 +2358,10 @@ Request "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -3164,7 +3191,10 @@ The JSON view of a cell combining the fields in cell output and cell data. "lock": { "args": "0x", "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -3225,7 +3255,10 @@ The fields of an output cell except the cell data. "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -3266,7 +3299,10 @@ The JSON view of a cell with its status information. "lock": { "args": "0x", "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } @@ -4045,7 +4081,10 @@ Describes the lock script and type script for a cell. { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } } ``` @@ -4056,16 +4095,16 @@ Describes the lock script and type script for a cell. * `code_hash`: [`H256`](#type-h256) - The hash used to match the script code. -* `hash_type`: [`ScriptHashType`](#type-scripthashtype) - Specifies how to use the `code_hash` to match the script code. - * `args`: [`JsonBytes`](#type-jsonbytes) - Arguments for script. +* `hash_type`: [`ScriptHashType`](#type-scripthashtype) - Specifies how to use the `code_hash` to match the script code. + ### Type `ScriptHashType` Specifies how the script `code_hash` is used to match the script code. -Allowed values: "data" and "type". +Allowed kinds: "data" and "type". If the kind is "data", the "vm_version" must be provided. If the kind is "type", specifying "vm_version" is not allowed. Refer to the section [Code Locating](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#code-locating) and [Upgradable Script](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0022-transaction-structure/0022-transaction-structure.md#upgradable-script) in the RFC *CKB Transaction Structure*. @@ -4265,7 +4304,10 @@ This structure is serialized into a JSON object with field `hash` and all the fi "lock": { "args": "0x", "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - "hash_type": "data" + "hash_type": { + "kind": "data", + "vm_version": 0 + } }, "type": null } diff --git a/rpc/src/module/chain.rs b/rpc/src/module/chain.rs index aac5f8e5ed..2153b8e110 100644 --- a/rpc/src/module/chain.rs +++ b/rpc/src/module/chain.rs @@ -125,7 +125,10 @@ pub trait ChainRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } @@ -244,7 +247,10 @@ pub trait ChainRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } @@ -502,7 +508,10 @@ pub trait ChainRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } @@ -690,7 +699,10 @@ pub trait ChainRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } @@ -1045,7 +1057,10 @@ pub trait ChainRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } diff --git a/rpc/src/module/experiment.rs b/rpc/src/module/experiment.rs index 72c3809a85..cbf911fd8c 100644 --- a/rpc/src/module/experiment.rs +++ b/rpc/src/module/experiment.rs @@ -75,7 +75,10 @@ pub trait ExperimentRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } diff --git a/rpc/src/module/miner.rs b/rpc/src/module/miner.rs index 1c828607cf..6d123e9a99 100644 --- a/rpc/src/module/miner.rs +++ b/rpc/src/module/miner.rs @@ -79,7 +79,10 @@ pub trait MinerRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } @@ -189,7 +192,10 @@ pub trait MinerRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } diff --git a/rpc/src/module/pool.rs b/rpc/src/module/pool.rs index dcb58201ef..2296c8ba52 100644 --- a/rpc/src/module/pool.rs +++ b/rpc/src/module/pool.rs @@ -3,9 +3,9 @@ use ckb_chain_spec::consensus::Consensus; use ckb_jsonrpc_types::{OutputsValidator, RawTxPool, Transaction, TxPoolInfo}; use ckb_logger::error; use ckb_script::IllTransactionChecker; -use ckb_shared::shared::Shared; +use ckb_shared::{shared::Shared, Snapshot}; use ckb_types::{core, packed, prelude::*, H256}; -use ckb_verification::{Since, SinceMetric}; +use ckb_verification::{Since, SinceMetric, TxVerifyEnv}; use jsonrpc_core::Result; use jsonrpc_derive::rpc; use std::convert::TryInto; @@ -70,7 +70,10 @@ pub trait PoolRpc { /// "lock": { /// "args": "0x", /// "code_hash": "0x28e83a1277d48add8e72fadaa9248559e1b632bab2bd60b27955ebc4c03800a5", - /// "hash_type": "data" + /// "hash_type": { + /// "kind": "data", + /// "vm_version": 0 + /// } /// }, /// "type": null /// } @@ -258,7 +261,13 @@ impl PoolRpc for PoolRpcImpl { } if self.reject_ill_transactions { - if let Err(e) = IllTransactionChecker::new(&tx).check() { + let snapshot: &Snapshot = &self.shared.snapshot(); + let consensus = snapshot.consensus(); + let tx_env = { + let tip_header = snapshot.tip_header(); + TxVerifyEnv::new_submit(&tip_header) + }; + if let Err(e) = IllTransactionChecker::new(&tx, consensus, &tx_env).check() { return Err(RPCError::custom_with_data( RPCError::PoolRejectedTransactionByIllTransactionChecker, "The transaction is rejected by IllTransactionChecker", @@ -496,7 +505,7 @@ mod tests { assert!(validator.validate(&tx).is_err()); // invalid hash type - let tx = build_tx(&type_hash, core::ScriptHashType::Data, vec![1; 20]); + let tx = build_tx(&type_hash, core::ScriptHashType::Data(0), vec![1; 20]); assert!(validator.validate(&tx).is_err()); // invalid code hash @@ -528,7 +537,7 @@ mod tests { assert!(validator.validate(&tx).is_err()); // invalid hash type - let tx = build_tx(&type_hash, core::ScriptHashType::Data, vec![1; 20]); + let tx = build_tx(&type_hash, core::ScriptHashType::Data(0), vec![1; 20]); assert!(validator.validate(&tx).is_err()); // invalid since args format @@ -583,7 +592,7 @@ mod tests { core::ScriptHashType::Type, vec![1; 20], &type_type_hash, - core::ScriptHashType::Data, + core::ScriptHashType::Data(0), ); assert!(validator.validate(&tx).is_err()); diff --git a/script/Cargo.toml b/script/Cargo.toml index 09270ac269..a6aef8014b 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -21,14 +21,14 @@ ckb-traits = { path = "../traits", version = "= 0.44.0-pre" } byteorder = "1.3.1" ckb-types = {path = "../util/types", version = "= 0.44.0-pre"} ckb-hash = {path = "../util/hash", version = "= 0.44.0-pre"} -ckb-vm = { version = "0.19.4", default-features = false } +ckb-vm-definitions = "0.20.0-alpha2" +ckb-vm = { version = "0.20.0-alpha2", default-features = false } faster-hex = "0.6" ckb-logger = { path = "../util/logger", version = "= 0.44.0-pre", optional = true } serde = { version = "1.0", features = ["derive"] } ckb-error = { path = "../error", version = "= 0.44.0-pre" } ckb-chain-spec = { path = "../spec", version = "= 0.44.0-pre" } goblin = "0.2" -ckb-vm-definitions = "0.19.4" [dev-dependencies] proptest = "0.9" diff --git a/script/src/cost_model.rs b/script/src/cost_model.rs index dbcd458aa1..6607496d29 100644 --- a/script/src/cost_model.rs +++ b/script/src/cost_model.rs @@ -10,6 +10,9 @@ use ckb_vm::{ // 0.25 cycles per byte pub const BYTES_PER_CYCLE: u64 = 4; +/// The cost of switching between assembly and rust. +pub const CONTEXT_SWITCH_CYCLE: u64 = 500; + /// Calculates how many cycles spent to load the specified number of bytes. pub fn transferred_byte_cycles(bytes: u64) -> u64 { // Compiler will optimize the divisin here to shifts. @@ -19,6 +22,7 @@ pub fn transferred_byte_cycles(bytes: u64) -> u64 { /// Returns the spent cycles to execute the secific instruction. pub fn instruction_cycles(i: Instruction) -> u64 { match extract_opcode(i) { + // IMC insts::OP_JALR => 3, insts::OP_LD => 2, insts::OP_LW => 3, @@ -37,24 +41,9 @@ pub fn instruction_cycles(i: Instruction) -> u64 { insts::OP_BLT => 3, insts::OP_BLTU => 3, insts::OP_BNE => 3, - insts::OP_EBREAK => 500, - insts::OP_ECALL => 500, + insts::OP_EBREAK => CONTEXT_SWITCH_CYCLE, + insts::OP_ECALL => CONTEXT_SWITCH_CYCLE, insts::OP_JAL => 3, - insts::OP_RVC_LW => 3, - insts::OP_RVC_LD => 2, - insts::OP_RVC_SW => 3, - insts::OP_RVC_SD => 2, - insts::OP_RVC_LWSP => 3, - insts::OP_RVC_LDSP => 2, - insts::OP_RVC_SWSP => 3, - insts::OP_RVC_SDSP => 2, - insts::OP_RVC_BEQZ => 3, - insts::OP_RVC_BNEZ => 3, - insts::OP_RVC_JAL => 3, - insts::OP_RVC_J => 3, - insts::OP_RVC_JR => 3, - insts::OP_RVC_JALR => 3, - insts::OP_RVC_EBREAK => 500, insts::OP_MUL => 5, insts::OP_MULW => 5, insts::OP_MULH => 5, @@ -68,6 +57,52 @@ pub fn instruction_cycles(i: Instruction) -> u64 { insts::OP_REMW => 32, insts::OP_REMU => 32, insts::OP_REMUW => 32, + // B + insts::OP_GREV => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_GREVI => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_GREVW => CONTEXT_SWITCH_CYCLE + 18, + insts::OP_GREVIW => CONTEXT_SWITCH_CYCLE + 18, + insts::OP_SHFL => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_UNSHFL => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_SHFLI => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_UNSHFLI => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_SHFLW => CONTEXT_SWITCH_CYCLE + 18, + insts::OP_UNSHFLW => CONTEXT_SWITCH_CYCLE + 18, + insts::OP_GORC => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_GORCI => CONTEXT_SWITCH_CYCLE + 20, + insts::OP_GORCW => CONTEXT_SWITCH_CYCLE + 18, + insts::OP_GORCIW => CONTEXT_SWITCH_CYCLE + 18, + insts::OP_BFP => CONTEXT_SWITCH_CYCLE + 15, + insts::OP_BFPW => CONTEXT_SWITCH_CYCLE + 15, + insts::OP_BDEP => CONTEXT_SWITCH_CYCLE + 350, + insts::OP_BEXT => CONTEXT_SWITCH_CYCLE + 270, + insts::OP_BDEPW => CONTEXT_SWITCH_CYCLE + 180, + insts::OP_BEXTW => CONTEXT_SWITCH_CYCLE + 140, + insts::OP_CLMUL => CONTEXT_SWITCH_CYCLE + 320, + insts::OP_CLMULR => CONTEXT_SWITCH_CYCLE + 380, + insts::OP_CLMULH => CONTEXT_SWITCH_CYCLE + 400, + insts::OP_CLMULW => CONTEXT_SWITCH_CYCLE + 60, + insts::OP_CLMULRW => CONTEXT_SWITCH_CYCLE + 60, + insts::OP_CLMULHW => CONTEXT_SWITCH_CYCLE + 60, + insts::OP_CRC32B => CONTEXT_SWITCH_CYCLE + 15, + insts::OP_CRC32H => CONTEXT_SWITCH_CYCLE + 30, + insts::OP_CRC32W => CONTEXT_SWITCH_CYCLE + 45, + insts::OP_CRC32D => CONTEXT_SWITCH_CYCLE + 60, + insts::OP_CRC32CB => CONTEXT_SWITCH_CYCLE + 15, + insts::OP_CRC32CH => CONTEXT_SWITCH_CYCLE + 30, + insts::OP_CRC32CW => CONTEXT_SWITCH_CYCLE + 45, + insts::OP_CRC32CD => CONTEXT_SWITCH_CYCLE + 60, + insts::OP_BMATFLIP => CONTEXT_SWITCH_CYCLE + 40, + insts::OP_BMATOR => CONTEXT_SWITCH_CYCLE + 500, + insts::OP_BMATXOR => CONTEXT_SWITCH_CYCLE + 800, + // MOP + insts::OP_WIDE_MUL => 5, + insts::OP_WIDE_MULU => 5, + insts::OP_WIDE_MULSU => 5, + insts::OP_WIDE_DIV => 32, + insts::OP_WIDE_DIVU => 32, + insts::OP_FAR_JUMP_REL => 3, + insts::OP_FAR_JUMP_ABS => 3, _ => 1, } } diff --git a/script/src/error.rs b/script/src/error.rs index 05bd3bdd54..4dd7e70ca5 100644 --- a/script/src/error.rs +++ b/script/src/error.rs @@ -28,6 +28,14 @@ pub enum ScriptError { #[error("Known bugs encountered in output {1}: {0}")] EncounteredKnownBugs(String, usize), + /// InvalidScriptHashType + #[error("InvalidScriptHashType: {0}")] + InvalidScriptHashType(String), + + /// InvalidVmVersion + #[error("Invalid VM Version: {0}")] + InvalidVmVersion(u8), + /// Known bugs are detected in transaction script outputs #[error("VM Internal Error: {0}")] VMInternalError(String), @@ -87,7 +95,7 @@ impl fmt::Display for TransactionScriptError { impl ScriptError { pub(crate) fn validation_failure(script: &Script, exit_code: i8) -> ScriptError { let url_path = match ScriptHashType::try_from(script.hash_type()).expect("checked data") { - ScriptHashType::Data => { + ScriptHashType::Data(_) => { format!("by-data-hash/{:x}", script.code_hash()) } ScriptHashType::Type => { diff --git a/script/src/ill_transaction_checker.rs b/script/src/ill_transaction_checker.rs index bcfceecf6b..2dc8a5d742 100644 --- a/script/src/ill_transaction_checker.rs +++ b/script/src/ill_transaction_checker.rs @@ -1,9 +1,10 @@ -use crate::ScriptError; +use crate::{verify_env::TxVerifyEnv, ScriptError}; use byteorder::{ByteOrder, LittleEndian}; +use ckb_chain_spec::consensus::Consensus; use ckb_types::core::TransactionView; use ckb_vm::{ - instructions::{extract_opcode, i, m, rvc, Instruction, Itype, Stype}, - registers::{RA, ZERO}, + instructions::{extract_opcode, i, m, rvc, Instruction, Itype}, + registers::ZERO, }; use ckb_vm_definitions::instructions as insts; use goblin::elf::{section_header::SHF_EXECINSTR, Elf}; @@ -13,18 +14,30 @@ const CKB_VM_ISSUE_92: &str = "https://github.com/nervosnetwork/ckb-vm/issues/92 /// Ill formed transactions checker. pub struct IllTransactionChecker<'a> { tx: &'a TransactionView, + consensus: &'a Consensus, + tx_env: &'a TxVerifyEnv, } impl<'a> IllTransactionChecker<'a> { /// Creates the checker for a transaction. - pub fn new(tx: &'a TransactionView) -> Self { - IllTransactionChecker { tx } + pub fn new(tx: &'a TransactionView, consensus: &'a Consensus, tx_env: &'a TxVerifyEnv) -> Self { + IllTransactionChecker { + tx, + consensus, + tx_env, + } } /// Checks whether the transaction is ill formed. pub fn check(&self) -> Result<(), ScriptError> { - for (i, data) in self.tx.outputs_data().into_iter().enumerate() { - IllScriptChecker::new(&data.raw_data(), i).check()?; + let proposal_window = self.consensus.tx_proposal_window(); + let epoch_number = self.tx_env.epoch_number(proposal_window); + let hardfork_switch = self.consensus.hardfork_switch(); + // TODO ckb2021 require-confirmation We couldn't known if user run the code in vm v0 or vm v1. + if !hardfork_switch.is_vm_version_1_and_syscalls_2_enabled(epoch_number) { + for (i, data) in self.tx.outputs_data().into_iter().enumerate() { + IllScriptChecker::new(&data.raw_data(), i).check()?; + } } Ok(()) } @@ -56,35 +69,19 @@ impl<'a> IllScriptChecker<'a> { let mut pc = section_header.sh_offset; let end = section_header.sh_offset + section_header.sh_size; while pc < end { - match self.decode_instruction(pc) { - (Some(i), len) => { - match extract_opcode(i) { - insts::OP_JALR => { - let i = Itype(i); - if i.rs1() == i.rd() && i.rd() != ZERO { - return Err(ScriptError::EncounteredKnownBugs( - CKB_VM_ISSUE_92.to_string(), - self.index, - )); - } - } - insts::OP_RVC_JALR => { - let i = Stype(i); - if i.rs1() == RA { - return Err(ScriptError::EncounteredKnownBugs( - CKB_VM_ISSUE_92.to_string(), - self.index, - )); - } - } - _ => (), - }; - pc += len; - } - (None, len) => { - pc += len; - } + let (option_instruction, len) = self.decode_instruction(pc); + if let Some(i) = option_instruction { + if extract_opcode(i) == insts::OP_JALR { + let i = Itype(i); + if i.rs1() == i.rd() && i.rd() != ZERO { + return Err(ScriptError::EncounteredKnownBugs( + CKB_VM_ISSUE_92.to_string(), + self.index, + )); + } + }; } + pc += len; } } } diff --git a/script/src/syscalls/current_cycles.rs b/script/src/syscalls/current_cycles.rs new file mode 100644 index 0000000000..4f80c73d3f --- /dev/null +++ b/script/src/syscalls/current_cycles.rs @@ -0,0 +1,28 @@ +use crate::syscalls::CURRENT_CYCLES; +use ckb_vm::{ + registers::{A0, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; + +#[derive(Debug)] +pub struct CurrentCycles {} + +impl CurrentCycles { + pub fn new() -> Self { + Self {} + } +} + +impl Syscalls for CurrentCycles { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != CURRENT_CYCLES { + return Ok(false); + } + machine.set_register(A0, Mac::REG::from_u64(machine.cycles())); + Ok(true) + } +} diff --git a/script/src/syscalls/exec.rs b/script/src/syscalls/exec.rs new file mode 100644 index 0000000000..b692f9a58f --- /dev/null +++ b/script/src/syscalls/exec.rs @@ -0,0 +1,197 @@ +use crate::cost_model::transferred_byte_cycles; +use crate::syscalls::{Source, SourceEntry, EXEC, INDEX_OUT_OF_BOUND, WRONG_FORMAT}; +use ckb_traits::CellDataProvider; +use ckb_types::core::cell::CellMeta; +use ckb_types::packed::{Bytes as PackedBytes, BytesVec}; +use ckb_vm::Memory; +use ckb_vm::{ + registers::{A0, A1, A2, A3, A4, A5, A7}, + Bytes, Error as VMError, Register, SupportMachine, Syscalls, +}; +use ckb_vm::{DEFAULT_STACK_SIZE, RISCV_MAX_MEMORY}; + +#[derive(Debug)] +pub struct Exec<'a, DL> { + data_loader: &'a DL, + outputs: &'a [CellMeta], + resolved_inputs: &'a [CellMeta], + resolved_cell_deps: &'a [CellMeta], + group_inputs: &'a [usize], + group_outputs: &'a [usize], + witnesses: BytesVec, +} + +impl<'a, DL: CellDataProvider + 'a> Exec<'a, DL> { + pub fn new( + data_loader: &'a DL, + outputs: &'a [CellMeta], + resolved_inputs: &'a [CellMeta], + resolved_cell_deps: &'a [CellMeta], + group_inputs: &'a [usize], + group_outputs: &'a [usize], + witnesses: BytesVec, + ) -> Exec<'a, DL> { + Exec { + data_loader, + outputs, + resolved_inputs, + resolved_cell_deps, + group_inputs, + group_outputs, + witnesses, + } + } + + fn fetch_cell(&self, source: Source, index: usize) -> Result<&'a CellMeta, u8> { + match source { + Source::Transaction(SourceEntry::Input) => { + self.resolved_inputs.get(index).ok_or(INDEX_OUT_OF_BOUND) + } + Source::Transaction(SourceEntry::Output) => { + self.outputs.get(index).ok_or(INDEX_OUT_OF_BOUND) + } + Source::Transaction(SourceEntry::CellDep) => { + self.resolved_cell_deps.get(index).ok_or(INDEX_OUT_OF_BOUND) + } + Source::Transaction(SourceEntry::HeaderDep) => Err(INDEX_OUT_OF_BOUND), + Source::Group(SourceEntry::Input) => self + .group_inputs + .get(index) + .ok_or(INDEX_OUT_OF_BOUND) + .and_then(|actual_index| { + self.resolved_inputs + .get(*actual_index) + .ok_or(INDEX_OUT_OF_BOUND) + }), + Source::Group(SourceEntry::Output) => self + .group_outputs + .get(index) + .ok_or(INDEX_OUT_OF_BOUND) + .and_then(|actual_index| self.outputs.get(*actual_index).ok_or(INDEX_OUT_OF_BOUND)), + Source::Group(SourceEntry::CellDep) => Err(INDEX_OUT_OF_BOUND), + Source::Group(SourceEntry::HeaderDep) => Err(INDEX_OUT_OF_BOUND), + } + } + + fn fetch_witness(&self, source: Source, index: usize) -> Option { + match source { + Source::Group(SourceEntry::Input) => self + .group_inputs + .get(index) + .and_then(|actual_index| self.witnesses.get(*actual_index)), + Source::Group(SourceEntry::Output) => self + .group_outputs + .get(index) + .and_then(|actual_index| self.witnesses.get(*actual_index)), + Source::Transaction(SourceEntry::Input) => self.witnesses.get(index), + Source::Transaction(SourceEntry::Output) => self.witnesses.get(index), + _ => None, + } + } +} + +fn load_c_string(machine: &mut Mac, addr: u64) -> Result { + let mut buffer = Vec::new(); + let mut addr = addr; + + loop { + let byte = machine + .memory_mut() + .load8(&Mac::REG::from_u64(addr))? + .to_u8(); + if byte == 0 { + break; + } + buffer.push(byte); + addr += 1; + } + + Ok(Bytes::from(buffer)) +} + +impl<'a, Mac: SupportMachine, DL: CellDataProvider> Syscalls for Exec<'a, DL> { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != EXEC { + return Ok(false); + } + + let index = machine.registers()[A0].to_u64(); + let source = Source::parse_from_u64(machine.registers()[A1].to_u64())?; + let place = machine.registers()[A2].to_u64(); + let bounds = machine.registers()[A3].to_u64(); + let offset = (bounds >> 32) as usize; + let length = bounds as u32 as usize; + + let data = if place == 0 { + let cell = self.fetch_cell(source, index as usize); + if let Err(err) = cell { + machine.set_register(A0, Mac::REG::from_u8(err)); + return Ok(false); + } + let cell = cell.unwrap(); + self.data_loader + .load_cell_data(cell) + .ok_or(VMError::Unexpected)? + } else { + let witness = self.fetch_witness(source, index as usize); + if witness.is_none() { + machine.set_register(A0, Mac::REG::from_u8(INDEX_OUT_OF_BOUND)); + return Ok(true); + } + let witness = witness.unwrap(); + witness.raw_data() + }; + let data = if length == 0 { + data.slice(offset..data.len()) + } else { + data.slice(offset..offset + length) + }; + let argc = machine.registers()[A4].to_u64(); + let mut addr = machine.registers()[A5].to_u64(); + let mut argv = Vec::new(); + for _ in 0..argc { + let target_addr = machine + .memory_mut() + .load64(&Mac::REG::from_u64(addr))? + .to_u64(); + + let cstr = load_c_string(machine, target_addr)?; + argv.push(cstr); + addr += 8; + } + + let cycles = machine.cycles(); + let max_cycles = machine.max_cycles(); + machine.reset(max_cycles); + machine.set_cycles(cycles); + + match machine.load_elf(&data, true) { + Ok(size) => { + machine.add_cycles(transferred_byte_cycles(size))?; + } + Err(_) => { + machine.set_register(A0, Mac::REG::from_u8(WRONG_FORMAT)); + return Ok(false); + } + } + + match machine.initialize_stack( + &argv, + (RISCV_MAX_MEMORY - DEFAULT_STACK_SIZE) as u64, + DEFAULT_STACK_SIZE as u64, + ) { + Ok(size) => { + machine.add_cycles(transferred_byte_cycles(size))?; + } + Err(_) => { + machine.set_register(A0, Mac::REG::from_u8(WRONG_FORMAT)); + return Ok(false); + } + } + Ok(true) + } +} diff --git a/script/src/syscalls/mod.rs b/script/src/syscalls/mod.rs index 2bd6be87e2..1b8921885c 100644 --- a/script/src/syscalls/mod.rs +++ b/script/src/syscalls/mod.rs @@ -1,4 +1,6 @@ +mod current_cycles; mod debugger; +mod exec; mod load_cell; mod load_cell_data; mod load_header; @@ -8,8 +10,11 @@ mod load_script_hash; mod load_tx; mod load_witness; mod utils; +mod vm_version; +pub use self::current_cycles::CurrentCycles; pub use self::debugger::Debugger; +pub use self::exec::Exec; pub use self::load_cell::LoadCell; pub use self::load_cell_data::LoadCellData; pub use self::load_header::LoadHeader; @@ -18,6 +23,7 @@ pub use self::load_script::LoadScript; pub use self::load_script_hash::LoadScriptHash; pub use self::load_tx::LoadTx; pub use self::load_witness::LoadWitness; +pub use self::vm_version::VMVersion; use ckb_vm::Error; @@ -29,7 +35,11 @@ pub const SUCCESS: u8 = 0; pub const INDEX_OUT_OF_BOUND: u8 = 1; pub const ITEM_MISSING: u8 = 2; pub const SLICE_OUT_OF_BOUND: u8 = 3; +pub const WRONG_FORMAT: u8 = 4; +pub const VM_VERSION: u64 = 2041; +pub const CURRENT_CYCLES: u64 = 2042; +pub const EXEC: u64 = 2043; pub const LOAD_TRANSACTION_SYSCALL_NUMBER: u64 = 2051; pub const LOAD_SCRIPT_SYSCALL_NUMBER: u64 = 2052; pub const LOAD_TX_HASH_SYSCALL_NUMBER: u64 = 2061; @@ -188,11 +198,13 @@ mod tests { prelude::*, H256, }; - use ckb_vm::machine::DefaultCoreMachine; + use ckb_vm::{machine::DefaultCoreMachine, SupportMachine}; use ckb_vm::{ - memory::{FLAG_EXECUTABLE, FLAG_FREEZED, FLAG_WRITABLE}, + machine::{VERSION0, VERSION1}, + memory::{FLAG_DIRTY, FLAG_EXECUTABLE, FLAG_FREEZED, FLAG_WRITABLE}, registers::{A0, A1, A2, A3, A4, A5, A7}, - CoreMachine, Error as VMError, Memory, SparseMemory, Syscalls, WXorXMemory, RISCV_PAGESIZE, + CoreMachine, Error as VMError, Memory, SparseMemory, Syscalls, WXorXMemory, ISA_IMC, + RISCV_PAGESIZE, }; use proptest::{collection::size_range, prelude::*}; use std::collections::HashMap; @@ -237,7 +249,11 @@ mod tests { } fn _test_load_cell_not_exist(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -285,7 +301,11 @@ mod tests { } fn _test_load_cell_all(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -376,7 +396,11 @@ mod tests { } fn _test_load_cell_length(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -428,7 +452,11 @@ mod tests { } fn _test_load_cell_partial(data: &[u8], offset: u64) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -488,7 +516,11 @@ mod tests { } fn _test_load_cell_capacity(capacity: Capacity) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -550,7 +582,11 @@ mod tests { #[test] fn test_load_missing_contract() { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -591,7 +627,11 @@ mod tests { } fn _test_load_header(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -655,7 +695,11 @@ mod tests { } fn _test_load_epoch_number(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -716,7 +760,11 @@ mod tests { } fn _test_load_tx_hash(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -760,7 +808,11 @@ mod tests { } fn _test_load_tx(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -804,7 +856,11 @@ mod tests { } fn _test_load_current_script_hash(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -815,7 +871,7 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(data.to_owned()).pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let hash = script.calc_script_hash(); let data = hash.raw_data(); @@ -856,7 +912,11 @@ mod tests { } fn _test_load_input_lock_script_hash(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -870,7 +930,7 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(data.to_owned()).pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let h = script.calc_script_hash(); let hash = h.as_bytes(); @@ -922,7 +982,11 @@ mod tests { } fn _test_load_witness(data: &[u8], source: SourceEntry) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -977,7 +1041,11 @@ mod tests { } fn _test_load_group_witness(data: &[u8], source: SourceEntry) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -1032,7 +1100,11 @@ mod tests { } fn _test_load_script(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 0; let addr: u64 = 100; @@ -1078,7 +1150,12 @@ mod tests { } fn _test_load_cell_data_as_code(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); + let addr = 4096; let addr_size = 4096; @@ -1113,7 +1190,7 @@ mod tests { prop_assert!(load_code.ecall(&mut machine).is_ok()); prop_assert_eq!(machine.registers()[A0], u64::from(SUCCESS)); - let flags = FLAG_EXECUTABLE | FLAG_FREEZED; + let flags = FLAG_EXECUTABLE | FLAG_FREEZED | FLAG_DIRTY; prop_assert_eq!( machine .memory_mut() @@ -1132,7 +1209,11 @@ mod tests { } fn _test_load_cell_data(data: &[u8]) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let size_addr: u64 = 100; let addr = 4096; let addr_size = 4096; @@ -1167,7 +1248,7 @@ mod tests { prop_assert!(load_code.ecall(&mut machine).is_ok()); prop_assert_eq!(machine.registers()[A0], u64::from(SUCCESS)); - let flags = FLAG_WRITABLE; + let flags = FLAG_WRITABLE | FLAG_DIRTY; prop_assert_eq!( machine .memory_mut() @@ -1203,7 +1284,11 @@ mod tests { #[test] fn test_load_overflowed_cell_data_as_code() { let data = vec![0, 1, 2, 3, 4, 5]; - let mut machine = DefaultCoreMachine::>>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let addr = 4096; let addr_size = 4096; @@ -1243,7 +1328,11 @@ mod tests { as_code: bool, data: &[u8], ) -> Result<(), TestCaseError> { - let mut machine = DefaultCoreMachine::>>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let addr = 8192; let addr_size = 4096; @@ -1308,7 +1397,11 @@ mod tests { #[test] fn test_load_code_unaligned_error() { - let mut machine = DefaultCoreMachine::>>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let addr = 4097; let addr_size = 4096; let data = [2; 32]; @@ -1349,7 +1442,11 @@ mod tests { #[test] fn test_load_code_slice_out_of_bound_error() { - let mut machine = DefaultCoreMachine::>>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let addr = 4096; let addr_size = 4096; let data = [2; 32]; @@ -1392,7 +1489,11 @@ mod tests { #[test] fn test_load_code_not_enough_space_error() { - let mut machine = DefaultCoreMachine::>>::default(); + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); let addr = 4096; let addr_size = 4096; @@ -1434,4 +1535,72 @@ mod tests { assert_eq!(machine.memory_mut().load8(&i), Ok(1)); } } + + #[test] + fn test_vm_version0() { + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION0, + u64::max_value(), + ); + + machine.set_register(A0, 0); + machine.set_register(A1, 0); + machine.set_register(A2, 0); + machine.set_register(A3, 0); + machine.set_register(A4, 0); + machine.set_register(A5, 0); + machine.set_register(A7, VM_VERSION); + + let result = VMVersion::new().ecall(&mut machine); + + assert_eq!(result.unwrap(), true); + assert_eq!(machine.registers()[A0], 0); + } + + #[test] + fn test_vm_version1() { + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION1, + u64::max_value(), + ); + + machine.set_register(A0, 0); + machine.set_register(A1, 0); + machine.set_register(A2, 0); + machine.set_register(A3, 0); + machine.set_register(A4, 0); + machine.set_register(A5, 0); + machine.set_register(A7, VM_VERSION); + + let result = VMVersion::new().ecall(&mut machine); + + assert_eq!(result.unwrap(), true); + assert_eq!(machine.registers()[A0], 1); + } + + #[test] + fn test_current_cycles() { + let mut machine = DefaultCoreMachine::>>::new( + ISA_IMC, + VERSION1, + u64::max_value(), + ); + + machine.set_register(A0, 0); + machine.set_register(A1, 0); + machine.set_register(A2, 0); + machine.set_register(A3, 0); + machine.set_register(A4, 0); + machine.set_register(A5, 0); + machine.set_register(A7, CURRENT_CYCLES); + + machine.set_cycles(100); + + let result = CurrentCycles::new().ecall(&mut machine); + + assert_eq!(result.unwrap(), true); + assert_eq!(machine.registers()[A0], 100); + } } diff --git a/script/src/syscalls/vm_version.rs b/script/src/syscalls/vm_version.rs new file mode 100644 index 0000000000..ad2283dfcb --- /dev/null +++ b/script/src/syscalls/vm_version.rs @@ -0,0 +1,28 @@ +use crate::syscalls::VM_VERSION; +use ckb_vm::{ + registers::{A0, A7}, + Error as VMError, Register, SupportMachine, Syscalls, +}; + +#[derive(Debug)] +pub struct VMVersion {} + +impl VMVersion { + pub fn new() -> Self { + Self {} + } +} + +impl Syscalls for VMVersion { + fn initialize(&mut self, _machine: &mut Mac) -> Result<(), VMError> { + Ok(()) + } + + fn ecall(&mut self, machine: &mut Mac) -> Result { + if machine.registers()[A7].to_u64() != VM_VERSION { + return Ok(false); + } + machine.set_register(A0, Mac::REG::from_u32(machine.version())); + Ok(true) + } +} diff --git a/script/src/verify.rs b/script/src/verify.rs index 844c279854..482141a0f4 100644 --- a/script/src/verify.rs +++ b/script/src/verify.rs @@ -2,8 +2,8 @@ use crate::{ cost_model::{instruction_cycles, transferred_byte_cycles}, error::ScriptError, syscalls::{ - Debugger, LoadCell, LoadCellData, LoadHeader, LoadInput, LoadScript, LoadScriptHash, - LoadTx, LoadWitness, + CurrentCycles, Debugger, Exec, LoadCell, LoadCellData, LoadHeader, LoadInput, LoadScript, + LoadScriptHash, LoadTx, LoadWitness, VMVersion, }, type_id::TypeIdSystemScript, types::{ScriptGroup, ScriptGroupType}, @@ -24,16 +24,14 @@ use ckb_types::{ prelude::*, }; #[cfg(has_asm)] +use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; use ckb_vm::{ - machine::asm::{AsmCoreMachine, AsmMachine}, + machine::{VERSION0, VERSION1}, DefaultMachineBuilder, Error as VMInternalError, InstructionCycleFunc, SupportMachine, - Syscalls, + Syscalls, ISA_B, ISA_IMC, ISA_MOP, }; #[cfg(not(has_asm))] -use ckb_vm::{ - DefaultCoreMachine, DefaultMachineBuilder, Error as VMInternalError, InstructionCycleFunc, - SparseMemory, SupportMachine, Syscalls, TraceMachine, WXorXMemory, -}; +use ckb_vm::{DefaultCoreMachine, SparseMemory, TraceMachine, WXorXMemory}; use std::cell::RefCell; use std::collections::HashMap; use std::convert::TryFrom; @@ -41,7 +39,7 @@ use std::convert::TryFrom; #[cfg(has_asm)] type CoreMachineType = Box; #[cfg(not(has_asm))] -type CoreMachineType = DefaultCoreMachine>>; +type CoreMachineType = DefaultCoreMachine>>; #[derive(Debug, PartialEq, Eq, Clone)] enum DataGurad { @@ -269,6 +267,26 @@ impl<'a, DL: CellDataProvider + HeaderProvider> TransactionScriptsVerifier<'a, D self.rtx.transaction.hash() } + fn build_current_cycles(&self) -> CurrentCycles { + CurrentCycles::new() + } + + fn build_vm_version(&self) -> VMVersion { + VMVersion::new() + } + + fn build_exec(&'a self, group_inputs: &'a [usize], group_outputs: &'a [usize]) -> Exec<'a, DL> { + Exec::new( + &self.data_loader, + &self.outputs, + self.resolved_inputs(), + self.resolved_cell_deps(), + group_inputs, + group_outputs, + self.witnesses(), + ) + } + fn build_load_tx(&self) -> LoadTx { LoadTx::new(&self.rtx.transaction) } @@ -335,8 +353,10 @@ impl<'a, DL: CellDataProvider + HeaderProvider> TransactionScriptsVerifier<'a, D /// Extracts actual script binary either in dep cells. pub fn extract_script(&self, script: &'a Script) -> Result { - match ScriptHashType::try_from(script.hash_type()).expect("checked data") { - ScriptHashType::Data => { + let script_hash_type = ScriptHashType::try_from(script.hash_type()) + .map_err(|err| ScriptError::InvalidScriptHashType(err.to_string()))?; + match script_hash_type { + ScriptHashType::Data(_) => { if let Some(lazy) = self.binaries_by_data_hash.get(&script.code_hash()) { Ok(lazy.access(self.data_loader)) } else { @@ -369,6 +389,37 @@ impl<'a, DL: CellDataProvider + HeaderProvider> TransactionScriptsVerifier<'a, D } } + /// Select the ISA and the version number of the new machine. + pub fn select_machine_options(&self, script: &'a Script) -> Result<(u8, u32), ScriptError> { + let proposal_window = self.consensus.tx_proposal_window(); + let epoch_number = self.tx_env.epoch_number(proposal_window); + let hardfork_switch = self.consensus.hardfork_switch(); + let is_vm_version_1_and_syscalls_2_enabled = + hardfork_switch.is_vm_version_1_and_syscalls_2_enabled(epoch_number); + let script_hash_type = ScriptHashType::try_from(script.hash_type()) + .map_err(|err| ScriptError::InvalidScriptHashType(err.to_string()))?; + match script_hash_type { + ScriptHashType::Data(version) => { + if !is_vm_version_1_and_syscalls_2_enabled && version > 0 { + Err(ScriptError::InvalidVmVersion(version)) + } else { + match version { + 0 => Ok((ISA_IMC, VERSION0)), + 1 => Ok((ISA_IMC | ISA_B | ISA_MOP, VERSION1)), + _ => Err(ScriptError::InvalidVmVersion(version)), + } + } + } + ScriptHashType::Type => { + if is_vm_version_1_and_syscalls_2_enabled { + Ok((ISA_IMC | ISA_B | ISA_MOP, VERSION1)) + } else { + Ok((ISA_IMC, VERSION0)) + } + } + } + } + /// Verifies the transaction by running scripts. /// /// ## Params @@ -459,10 +510,11 @@ impl<'a, DL: CellDataProvider + HeaderProvider> TransactionScriptsVerifier<'a, D /// Prepares syscalls. pub fn generate_syscalls( &'a self, + version: u32, script_group: &'a ScriptGroup, ) -> Vec + 'a)>> { let current_script_hash = script_group.script.calc_script_hash(); - vec![ + let mut syscalls: Vec + 'a)>> = vec![ Box::new(self.build_load_script_hash(current_script_hash.clone())), Box::new(self.build_load_tx()), Box::new( @@ -481,22 +533,30 @@ impl<'a, DL: CellDataProvider + HeaderProvider> TransactionScriptsVerifier<'a, D ), ), Box::new(Debugger::new(current_script_hash, &self.debug_printer)), - ] + ]; + if version >= VERSION1 { + syscalls.append(&mut vec![ + Box::new(self.build_vm_version()), + Box::new(self.build_current_cycles()), + Box::new( + self.build_exec(&script_group.input_indices, &script_group.output_indices), + ), + ]) + } + syscalls } fn run(&self, script_group: &ScriptGroup, max_cycles: Cycle) -> Result { let program = self.extract_script(&script_group.script)?; + let (isa, version) = self.select_machine_options(&script_group.script)?; #[cfg(has_asm)] - let core_machine = AsmCoreMachine::new_with_max_cycles(max_cycles); + let core_machine = AsmCoreMachine::new(isa, version, max_cycles); #[cfg(not(has_asm))] - let core_machine = - DefaultCoreMachine::>>::new_with_max_cycles( - max_cycles, - ); + let core_machine = CoreMachineType::new(isa, version, max_cycles); let machine_builder = DefaultMachineBuilder::::new(core_machine) .instruction_cycle_func(self.cost_model()); let machine_builder = self - .generate_syscalls(script_group) + .generate_syscalls(version, script_group) .into_iter() .fold(machine_builder, |builder, syscall| builder.syscall(syscall)); let default_machine = machine_builder.build(); @@ -538,8 +598,9 @@ mod tests { use ckb_store::{data_loader_wrapper::DataLoaderWrapper, ChainDB}; use ckb_types::{ core::{ - capacity_bytes, cell::CellMetaBuilder, Capacity, Cycle, DepType, HeaderView, - ScriptHashType, TransactionBuilder, TransactionInfo, + capacity_bytes, cell::CellMetaBuilder, hardfork::HardForkSwitch, Capacity, Cycle, + DepType, EpochNumberWithFraction, HeaderView, ScriptHashType, TransactionBuilder, + TransactionInfo, }, h256, packed::{ @@ -666,7 +727,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -706,7 +770,7 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(args).pack()) .code_hash(code_hash.pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let input = CellInput::new(OutPoint::null(), 0); @@ -731,7 +795,10 @@ mod tests { }; let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -777,7 +844,7 @@ mod tests { Some( Script::new_builder() .code_hash(h256!("0x123456abcd90").pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(), ) .pack(), @@ -817,7 +884,10 @@ mod tests { }; let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -852,7 +922,7 @@ mod tests { Some( Script::new_builder() .code_hash(h256!("0x123456abcd90").pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(), ) .pack(), @@ -874,7 +944,7 @@ mod tests { Some( Script::new_builder() .code_hash(h256!("0x123456abcd90").pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(), ) .pack(), @@ -914,7 +984,10 @@ mod tests { }; let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -958,7 +1031,7 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(args).pack()) .code_hash(code_hash.pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let input = CellInput::new(OutPoint::null(), 0); @@ -984,7 +1057,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1017,7 +1093,7 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(args).pack()) .code_hash(blake2b_256(&buffer).pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let input = CellInput::new(OutPoint::null(), 0); @@ -1043,7 +1119,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1089,13 +1168,13 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(args).pack()) .code_hash(blake2b_256(&buffer).pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let output_data = Bytes::default(); let output = CellOutputBuilder::default() .lock( Script::new_builder() - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(), ) .type_(Some(script).pack()) @@ -1132,7 +1211,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1178,7 +1260,7 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(args).pack()) .code_hash(blake2b_256(&buffer).pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let output = CellOutputBuilder::default() .type_(Some(script.clone()).pack()) @@ -1212,7 +1294,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1244,7 +1329,7 @@ mod tests { let script = Script::new_builder() .args(Bytes::from(args).pack()) .code_hash(blake2b_256(&buffer).pack()) - .hash_type(ScriptHashType::Data.into()) + .hash_type(ScriptHashType::Data(0).into()) .build(); let dep_out_point = OutPoint::new(h256!("0x123").pack(), 8); @@ -1283,7 +1368,10 @@ mod tests { }; let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1352,7 +1440,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1419,7 +1510,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1497,7 +1591,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1561,7 +1658,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1640,7 +1740,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1725,7 +1828,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1799,7 +1905,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1961,7 +2070,10 @@ mod tests { let store = new_store(); let data_loader = DataLoaderWrapper::new(&store); - let consensus = ConsensusBuilder::default().build(); + let hardfork_switch = HardForkSwitch::new_without_any_enabled(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); let tx_env = { let header = HeaderView::new_advanced_builder().build(); TxVerifyEnv::new_commit(&header) @@ -1973,4 +2085,209 @@ mod tests { assert!(cycle <= TWO_IN_TWO_OUT_CYCLES); assert!(cycle >= TWO_IN_TWO_OUT_CYCLES - CYCLE_BOUND); } + + #[test] + fn check_vm_version() { + let vm_version_cell_data = Bytes::from( + std::fs::read(Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata/vm_version")) + .unwrap(), + ); + let vm_version_cell = CellOutput::new_builder() + .capacity(Capacity::bytes(vm_version_cell_data.len()).unwrap().pack()) + .build(); + let vm_version_script = Script::new_builder() + .hash_type(ScriptHashType::Data(1).into()) + .code_hash(CellOutput::calc_data_hash(&vm_version_cell_data)) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(vm_version_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default().input(input).build(); + + let dummy_cell = CellMetaBuilder::from_cell_output(output, Bytes::new()) + .transaction_info(default_transaction_info()) + .build(); + let vm_version_cell = + CellMetaBuilder::from_cell_output(vm_version_cell, vm_version_cell_data) + .transaction_info(default_transaction_info()) + .build(); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![vm_version_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + + let fork_at = 10; + let store = new_store(); + let data_loader = DataLoaderWrapper::new(&store); + let hardfork_switch = HardForkSwitch::new_without_any_enabled() + .as_builder() + .rfc_pr_0237(fork_at) + .build() + .unwrap(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); + let tx_env = { + let epoch = EpochNumberWithFraction::new(fork_at, 0, 1); + let header = HeaderView::new_advanced_builder() + .epoch(epoch.pack()) + .build(); + TxVerifyEnv::new_commit(&header) + }; + + let verifier = TransactionScriptsVerifier::new(&rtx, &consensus, &data_loader, &tx_env); + assert!(verifier.verify(6000).is_ok()); + } + + #[test] + fn check_exec_from_cell_data() { + let exec_caller_cell_data = Bytes::from( + std::fs::read( + Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata/exec_caller_from_cell_data"), + ) + .unwrap(), + ); + let exec_caller_cell = CellOutput::new_builder() + .capacity(Capacity::bytes(exec_caller_cell_data.len()).unwrap().pack()) + .build(); + + let exec_callee_cell_data = Bytes::from( + std::fs::read(Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata/exec_callee")) + .unwrap(), + ); + let exec_callee_cell = CellOutput::new_builder() + .capacity(Capacity::bytes(exec_callee_cell_data.len()).unwrap().pack()) + .build(); + + let exec_caller_script = Script::new_builder() + .hash_type(ScriptHashType::Data(1).into()) + .code_hash(CellOutput::calc_data_hash(&exec_caller_cell_data)) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(exec_caller_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default().input(input).build(); + + let dummy_cell = CellMetaBuilder::from_cell_output(output, Bytes::new()) + .transaction_info(default_transaction_info()) + .build(); + let exec_caller_cell = + CellMetaBuilder::from_cell_output(exec_caller_cell, exec_caller_cell_data) + .transaction_info(default_transaction_info()) + .build(); + + let exec_callee_cell = + CellMetaBuilder::from_cell_output(exec_callee_cell, exec_callee_cell_data) + .transaction_info(default_transaction_info()) + .build(); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![exec_caller_cell, exec_callee_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + + let fork_at = 10; + let store = new_store(); + let data_loader = DataLoaderWrapper::new(&store); + let hardfork_switch = HardForkSwitch::new_without_any_enabled() + .as_builder() + .rfc_pr_0237(fork_at) + .build() + .unwrap(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); + let tx_env = { + let epoch = EpochNumberWithFraction::new(fork_at, 0, 1); + let header = HeaderView::new_advanced_builder() + .epoch(epoch.pack()) + .build(); + TxVerifyEnv::new_commit(&header) + }; + + let verifier = TransactionScriptsVerifier::new(&rtx, &consensus, &data_loader, &tx_env); + assert!(verifier.verify(600000).is_ok()); + } + + #[test] + fn check_exec_from_witness() { + let exec_caller_cell_data = Bytes::from( + std::fs::read( + Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata/exec_caller_from_witness"), + ) + .unwrap(), + ); + let exec_caller_cell = CellOutput::new_builder() + .capacity(Capacity::bytes(exec_caller_cell_data.len()).unwrap().pack()) + .build(); + + let exec_callee = Bytes::from( + std::fs::read(Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata/exec_callee")) + .unwrap(), + ) + .pack(); + + let exec_caller_script = Script::new_builder() + .hash_type(ScriptHashType::Data(1).into()) + .code_hash(CellOutput::calc_data_hash(&exec_caller_cell_data)) + .build(); + let output = CellOutputBuilder::default() + .capacity(capacity_bytes!(100).pack()) + .lock(exec_caller_script) + .build(); + let input = CellInput::new(OutPoint::null(), 0); + + let transaction = TransactionBuilder::default() + .input(input) + .set_witnesses(vec![exec_callee]) + .build(); + + let dummy_cell = CellMetaBuilder::from_cell_output(output, Bytes::new()) + .transaction_info(default_transaction_info()) + .build(); + let exec_caller_cell = + CellMetaBuilder::from_cell_output(exec_caller_cell, exec_caller_cell_data) + .transaction_info(default_transaction_info()) + .build(); + + let rtx = ResolvedTransaction { + transaction, + resolved_cell_deps: vec![exec_caller_cell], + resolved_inputs: vec![dummy_cell], + resolved_dep_groups: vec![], + }; + + let fork_at = 10; + let store = new_store(); + let data_loader = DataLoaderWrapper::new(&store); + let hardfork_switch = HardForkSwitch::new_without_any_enabled() + .as_builder() + .rfc_pr_0237(fork_at) + .build() + .unwrap(); + let consensus = ConsensusBuilder::default() + .hardfork_switch(hardfork_switch) + .build(); + let tx_env = { + let epoch = EpochNumberWithFraction::new(fork_at, 0, 1); + let header = HeaderView::new_advanced_builder() + .epoch(epoch.pack()) + .build(); + TxVerifyEnv::new_commit(&header) + }; + + let verifier = TransactionScriptsVerifier::new(&rtx, &consensus, &data_loader, &tx_env); + assert!(verifier.verify(600000).is_ok()); + } } diff --git a/script/testdata/current_cycles b/script/testdata/current_cycles new file mode 100755 index 0000000000..dc53642971 Binary files /dev/null and b/script/testdata/current_cycles differ diff --git a/script/testdata/current_cycles.c b/script/testdata/current_cycles.c new file mode 100644 index 0000000000..d7e9dcf046 --- /dev/null +++ b/script/testdata/current_cycles.c @@ -0,0 +1,23 @@ +static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, + long _a3, long _a4, long _a5) { + register long a0 asm("a0") = _a0; + register long a1 asm("a1") = _a1; + register long a2 asm("a2") = _a2; + register long a3 asm("a3") = _a3; + register long a4 asm("a4") = _a4; + register long a5 asm("a5") = _a5; + register long syscall_id asm("a7") = n; + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id)); + return a0; +} + +#define syscall(n, a, b, c, d, e, f) \ + __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ + (long)(f)) + +int main() { + return syscall(2042, 0, 0, 0, 0, 0, 0); +} diff --git a/script/testdata/exec_callee b/script/testdata/exec_callee new file mode 100755 index 0000000000..5d08c24b6a Binary files /dev/null and b/script/testdata/exec_callee differ diff --git a/script/testdata/exec_callee.c b/script/testdata/exec_callee.c new file mode 100644 index 0000000000..3a815b171c --- /dev/null +++ b/script/testdata/exec_callee.c @@ -0,0 +1,15 @@ +int main(int argc, char* argv[]) { + if (argc != 3) { + return 1; + } + if (argv[0][0] != 'a') { + return 2; + } + if (argv[1][0] != 'b') { + return 3; + } + if (argv[2][0] != 'c') { + return 4; + } + return 0; +} diff --git a/script/testdata/exec_caller_from_cell_data b/script/testdata/exec_caller_from_cell_data new file mode 100755 index 0000000000..6320a6eb1d Binary files /dev/null and b/script/testdata/exec_caller_from_cell_data differ diff --git a/script/testdata/exec_caller_from_cell_data.c b/script/testdata/exec_caller_from_cell_data.c new file mode 100644 index 0000000000..edefd815af --- /dev/null +++ b/script/testdata/exec_caller_from_cell_data.c @@ -0,0 +1,26 @@ +static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, + long _a3, long _a4, long _a5) { + register long a0 asm("a0") = _a0; + register long a1 asm("a1") = _a1; + register long a2 asm("a2") = _a2; + register long a3 asm("a3") = _a3; + register long a4 asm("a4") = _a4; + register long a5 asm("a5") = _a5; + register long syscall_id asm("a7") = n; + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id)); + return a0; +} + +#define syscall(n, a, b, c, d, e, f) \ + __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ + (long)(f)) + +int main() { + int argc = 3; + char *argv[] = {"a", "b", "c"}; + syscall(2043, 1, 3, 0, 0, argc, argv); + return -1; +} diff --git a/script/testdata/exec_caller_from_witness b/script/testdata/exec_caller_from_witness new file mode 100755 index 0000000000..7c19b85b46 Binary files /dev/null and b/script/testdata/exec_caller_from_witness differ diff --git a/script/testdata/exec_caller_from_witness.c b/script/testdata/exec_caller_from_witness.c new file mode 100644 index 0000000000..4a12a0da52 --- /dev/null +++ b/script/testdata/exec_caller_from_witness.c @@ -0,0 +1,26 @@ +static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, + long _a3, long _a4, long _a5) { + register long a0 asm("a0") = _a0; + register long a1 asm("a1") = _a1; + register long a2 asm("a2") = _a2; + register long a3 asm("a3") = _a3; + register long a4 asm("a4") = _a4; + register long a5 asm("a5") = _a5; + register long syscall_id asm("a7") = n; + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id)); + return a0; +} + +#define syscall(n, a, b, c, d, e, f) \ + __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ + (long)(f)) + +int main() { + int argc = 3; + char *argv[] = {"a", "b", "c"}; + syscall(2043, 0, 1, 1, 0, argc, argv); + return -1; +} diff --git a/script/testdata/vm_version b/script/testdata/vm_version new file mode 100644 index 0000000000..b355c5d06a Binary files /dev/null and b/script/testdata/vm_version differ diff --git a/script/testdata/vm_version.c b/script/testdata/vm_version.c new file mode 100644 index 0000000000..66c33c2bbe --- /dev/null +++ b/script/testdata/vm_version.c @@ -0,0 +1,26 @@ +static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, + long _a3, long _a4, long _a5) { + register long a0 asm("a0") = _a0; + register long a1 asm("a1") = _a1; + register long a2 asm("a2") = _a2; + register long a3 asm("a3") = _a3; + register long a4 asm("a4") = _a4; + register long a5 asm("a5") = _a5; + register long syscall_id asm("a7") = n; + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id)); + return a0; +} + +#define syscall(n, a, b, c, d, e, f) \ + __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ + (long)(f)) + +int main() { + if (syscall(2041, 0, 0, 0, 0, 0, 0) == 1) { + return 0; + } + return 1; +} diff --git a/spec/src/hardfork.rs b/spec/src/hardfork.rs index e8021f0784..9e5cb15fd3 100644 --- a/spec/src/hardfork.rs +++ b/spec/src/hardfork.rs @@ -13,30 +13,34 @@ use serde::{Deserialize, Serialize}; pub struct HardForkConfig { // TODO ckb2021 Update all rfc numbers and fix all links, after all proposals are merged. /// Ref: [CKB RFC xxxx](https://github.com/nervosnetwork/rfcs/tree/master/rfcs/xxxx-rfc-title) + #[serde(skip_serializing_if = "Option::is_none")] pub rfc_pr_0221: Option, /// Ref: [CKB RFC xxxx](https://github.com/nervosnetwork/rfcs/tree/master/rfcs/xxxx-rfc-title) + #[serde(skip_serializing_if = "Option::is_none")] pub rfc_pr_0222: Option, /// Ref: [CKB RFC xxxx](https://github.com/nervosnetwork/rfcs/tree/master/rfcs/xxxx-rfc-title) + #[serde(skip_serializing_if = "Option::is_none")] pub rfc_pr_0223: Option, /// Ref: [CKB RFC xxxx](https://github.com/nervosnetwork/rfcs/tree/master/rfcs/xxxx-rfc-title) + #[serde(skip_serializing_if = "Option::is_none")] pub rfc_pr_0224: Option, + /// Ref: [CKB RFC xxxx](https://github.com/nervosnetwork/rfcs/tree/master/rfcs/xxxx-rfc-title) + #[serde(skip_serializing_if = "Option::is_none")] + pub rfc_pr_0237: Option, } macro_rules! check_default { ($config:ident, $feature:ident, $expected:expr) => { - match $config.$feature { - Some(input) if input != $expected => { - let errmsg = format!( - "The value for hard fork feature \"{}\" is incorrect, actual: {}, expected: {}. - Don't set it for mainnet or testnet, or set it as a correct value.", - stringify!($feature), - input, - $expected, - ); - Err(errmsg) - }, - _ => Ok($expected), - }? + if $config.$feature.is_some() { + let errmsg = format!( + "Found the hard fork feature parameter \"{}\" is the chain specification file. + Don't set any hard fork parameters for \"mainnet\" or \"testnet\".", + stringify!($feature), + ); + return Err(errmsg); + } else { + $expected + } }; } @@ -66,7 +70,8 @@ impl HardForkConfig { .rfc_pr_0221(check_default!(self, rfc_pr_0221, ckb2021)) .rfc_pr_0222(check_default!(self, rfc_pr_0222, ckb2021)) .rfc_pr_0223(check_default!(self, rfc_pr_0223, ckb2021)) - .rfc_pr_0224(check_default!(self, rfc_pr_0224, ckb2021)); + .rfc_pr_0224(check_default!(self, rfc_pr_0224, ckb2021)) + .rfc_pr_0237(check_default!(self, rfc_pr_0237, ckb2021)); Ok(builder) } @@ -79,6 +84,7 @@ impl HardForkConfig { .rfc_pr_0222(self.rfc_pr_0222.unwrap_or(default)) .rfc_pr_0223(self.rfc_pr_0223.unwrap_or(default)) .rfc_pr_0224(self.rfc_pr_0224.unwrap_or(default)) + .rfc_pr_0237(self.rfc_pr_0237.unwrap_or(default)) .build() } } diff --git a/spec/src/legacy/mod.rs b/spec/src/legacy/mod.rs new file mode 100644 index 0000000000..3709066da3 --- /dev/null +++ b/spec/src/legacy/mod.rs @@ -0,0 +1,12 @@ +//! Legacy CKB Chain Specification + +use ckb_jsonrpc_types::ChainEdition; +use serde::{Deserialize, Serialize}; + +pub(crate) mod v2019; + +/// The partial CKB block chain specification +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub(crate) struct PartialChainSpec { + pub(crate) edition: Option, +} diff --git a/spec/src/legacy/v2019.rs b/spec/src/legacy/v2019.rs new file mode 100644 index 0000000000..31508a6e57 --- /dev/null +++ b/spec/src/legacy/v2019.rs @@ -0,0 +1,211 @@ +//! Legacy CKB Chain Specification (Edition 2019) + +use ckb_jsonrpc_types as rpc; +use ckb_pow::Pow; +use ckb_types::{core, packed, H256, U128}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub(crate) struct ChainSpec { + name: String, + pub(crate) genesis: Genesis, + #[serde(default)] + params: Params, + pow: Pow, + #[serde(skip)] + pub(crate) hash: packed::Byte32, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub(crate) struct Genesis { + version: u32, + parent_hash: H256, + timestamp: u64, + compact_target: u32, + uncles_hash: H256, + hash: Option, + nonce: U128, + issued_cells: Vec, + genesis_cell: GenesisCell, + pub(crate) system_cells: Vec, + system_cells_lock: Script, + bootstrap_lock: Script, + dep_groups: Vec, + #[serde(default)] + satoshi_gift: crate::SatoshiGift, +} + +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +struct Params { + #[serde(skip_serializing_if = "Option::is_none")] + initial_primary_epoch_reward: Option, + #[serde(skip_serializing_if = "Option::is_none")] + secondary_epoch_reward: Option, + #[serde(skip_serializing_if = "Option::is_none")] + max_block_cycles: Option, + #[serde(skip_serializing_if = "Option::is_none")] + max_block_bytes: Option, + #[serde(skip_serializing_if = "Option::is_none")] + cellbase_maturity: Option, + #[serde(skip_serializing_if = "Option::is_none")] + primary_epoch_reward_halving_interval: Option, + #[serde(skip_serializing_if = "Option::is_none")] + epoch_duration_target: Option, + #[serde(skip_serializing_if = "Option::is_none")] + genesis_epoch_length: Option, + #[serde(skip_serializing_if = "Option::is_none")] + permanent_difficulty_in_dummy: Option, + #[serde(skip_serializing_if = "Option::is_none")] + max_block_proposals_limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + orphan_rate_target: Option<(u32, u32)>, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +struct Script { + code_hash: H256, + hash_type: rpc::ScriptHashTypeKind, + args: rpc::JsonBytes, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct IssuedCell { + capacity: core::Capacity, + lock: Script, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +struct GenesisCell { + message: String, + lock: Script, +} + +impl From