diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b2a9b28..91b6bb766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,9 +43,16 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/ of a cluster that exceeds the limits. The default cluster limits are: max 64 transactions, max 100'000 bytes in total. +## [1.3.1] - 2026-06-03 + ### Fixed - Wallet: - - Fixed handling of confirmed and unconfirmed conflicting order transactions in the wallet. + - Fixed wallet handling of V1 order command conflicts, allowing confirmed ConcludeOrder and FreezeOrder transactions + to replace conflicting unconfirmed order transactions correctly. + - Fixed an issue where the wallet in cold mode would always use input commitments v0, thus producing signatures + that may no longer be valid at the current height. + - Fixed an issue where the wallet in cold mode would still try to access the mempool, which would cause `wallet-cli` + to print lots of error messages like "Method is not available in cold wallet mode". ## [1.3.0] - 2026-04-09 diff --git a/Cargo.lock b/Cargo.lock index ddb5a40ba..27846f3cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,7 +20,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "accounting" -version = "1.3.0" +version = "1.3.1" dependencies = [ "common", "parity-scale-codec", @@ -227,7 +227,7 @@ checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "api-blockchain-scanner-daemon" -version = "1.3.0" +version = "1.3.1" dependencies = [ "api-blockchain-scanner-lib", "api-server-common", @@ -247,7 +247,7 @@ dependencies = [ [[package]] name = "api-blockchain-scanner-lib" -version = "1.3.0" +version = "1.3.1" dependencies = [ "api-server-common", "async-trait", @@ -277,7 +277,7 @@ dependencies = [ [[package]] name = "api-server-backend-test-suite" -version = "1.3.0" +version = "1.3.1" dependencies = [ "api-server-common", "async-trait", @@ -300,7 +300,7 @@ dependencies = [ [[package]] name = "api-server-common" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "bb8-postgres", @@ -326,7 +326,7 @@ dependencies = [ [[package]] name = "api-server-stack-test-suite" -version = "1.3.0" +version = "1.3.1" dependencies = [ "api-blockchain-scanner-lib", "api-server-common", @@ -357,7 +357,7 @@ dependencies = [ [[package]] name = "api-web-server" -version = "1.3.0" +version = "1.3.1" dependencies = [ "api-server-common", "async-trait", @@ -994,7 +994,7 @@ dependencies = [ [[package]] name = "blockprod" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "chainstate", @@ -1124,7 +1124,7 @@ dependencies = [ [[package]] name = "build_utils" -version = "1.3.0" +version = "1.3.1" dependencies = [ "substrate-build-script-utils", ] @@ -1343,7 +1343,7 @@ dependencies = [ [[package]] name = "chainstate" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "async-trait", @@ -1389,7 +1389,7 @@ dependencies = [ [[package]] name = "chainstate-db-dumper" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "chainstate", @@ -1414,7 +1414,7 @@ dependencies = [ [[package]] name = "chainstate-launcher" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chainstate", "chainstate-storage", @@ -1430,7 +1430,7 @@ dependencies = [ [[package]] name = "chainstate-storage" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "chainstate-types", @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "chainstate-test-framework" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chainstate", "chainstate-storage", @@ -1487,7 +1487,7 @@ dependencies = [ [[package]] name = "chainstate-test-suite" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "chainstate", @@ -1520,7 +1520,7 @@ dependencies = [ [[package]] name = "chainstate-types" -version = "1.3.0" +version = "1.3.1" dependencies = [ "common", "crypto", @@ -1728,7 +1728,7 @@ dependencies = [ [[package]] name = "common" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "bech32 0.11.1", @@ -1788,7 +1788,7 @@ dependencies = [ [[package]] name = "consensus" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chainstate-types", "common", @@ -1869,7 +1869,7 @@ dependencies = [ [[package]] name = "constraints-value-accumulator" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "common", @@ -2129,7 +2129,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto" -version = "1.3.0" +version = "1.3.1" dependencies = [ "argon2", "bip39", @@ -2613,7 +2613,7 @@ checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" [[package]] name = "dns-server" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "async-trait", @@ -4858,7 +4858,7 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "log_error" -version = "1.3.0" +version = "1.3.1" dependencies = [ "derive_more 1.0.0", "logging", @@ -4871,7 +4871,7 @@ dependencies = [ [[package]] name = "logging" -version = "1.3.0" +version = "1.3.1" dependencies = [ "console-subscriber", "log", @@ -5019,7 +5019,7 @@ dependencies = [ [[package]] name = "mempool" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "anyhow", @@ -5065,7 +5065,7 @@ dependencies = [ [[package]] name = "mempool-types" -version = "1.3.0" +version = "1.3.1" dependencies = [ "p2p-types", "rpc-description", @@ -5145,7 +5145,7 @@ dependencies = [ [[package]] name = "mintlayer-core" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chainstate", "chainstate-storage", @@ -5183,7 +5183,7 @@ dependencies = [ [[package]] name = "mintlayer-test" -version = "1.3.0" +version = "1.3.1" dependencies = [ "clap", "ctor", @@ -5200,7 +5200,7 @@ dependencies = [ [[package]] name = "mintscript" -version = "1.3.0" +version = "1.3.1" dependencies = [ "common", "crypto", @@ -5262,7 +5262,7 @@ dependencies = [ [[package]] name = "mocks" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "chainstate", @@ -5359,7 +5359,7 @@ dependencies = [ [[package]] name = "networking" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "bytes", @@ -5406,7 +5406,7 @@ dependencies = [ [[package]] name = "node-comm" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "async-trait", @@ -5439,7 +5439,7 @@ dependencies = [ [[package]] name = "node-daemon" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "assert_cmd", @@ -5454,7 +5454,7 @@ dependencies = [ [[package]] name = "node-gui" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "chainstate", @@ -5489,7 +5489,7 @@ dependencies = [ [[package]] name = "node-gui-backend" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "chainstate", @@ -5524,7 +5524,7 @@ dependencies = [ [[package]] name = "node-lib" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "blockprod", @@ -6142,7 +6142,7 @@ dependencies = [ [[package]] name = "orders-accounting" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "common", @@ -6193,7 +6193,7 @@ dependencies = [ [[package]] name = "p2p" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "bytes", @@ -6250,7 +6250,7 @@ dependencies = [ [[package]] name = "p2p-backend-test-suite" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chainstate", "common", @@ -6270,7 +6270,7 @@ dependencies = [ [[package]] name = "p2p-test-utils" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chainstate", "chainstate-storage", @@ -6290,7 +6290,7 @@ dependencies = [ [[package]] name = "p2p-types" -version = "1.3.0" +version = "1.3.1" dependencies = [ "common", "networking", @@ -6623,7 +6623,7 @@ dependencies = [ [[package]] name = "pos-accounting" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "common", @@ -7104,7 +7104,7 @@ dependencies = [ [[package]] name = "randomness" -version = "1.3.0" +version = "1.3.1" dependencies = [ "rand 0.10.1", "rand 0.8.6", @@ -7437,7 +7437,7 @@ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "rpc" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "async-trait", @@ -7467,7 +7467,7 @@ dependencies = [ [[package]] name = "rpc-description" -version = "1.3.0" +version = "1.3.1" dependencies = [ "rpc-description-macro", "serde_json", @@ -7475,7 +7475,7 @@ dependencies = [ [[package]] name = "rpc-description-macro" -version = "1.3.0" +version = "1.3.1" dependencies = [ "proc-macro2", "quote", @@ -7484,7 +7484,7 @@ dependencies = [ [[package]] name = "rpc-types" -version = "1.3.0" +version = "1.3.1" dependencies = [ "hex", "rpc-description", @@ -7838,7 +7838,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "script" -version = "1.3.0" +version = "1.3.1" dependencies = [ "crypto", "flate2", @@ -8146,7 +8146,7 @@ dependencies = [ [[package]] name = "serialization" -version = "1.3.0" +version = "1.3.1" dependencies = [ "hex", "rpc-description", @@ -8159,7 +8159,7 @@ dependencies = [ [[package]] name = "serialization-core" -version = "1.3.0" +version = "1.3.1" dependencies = [ "arraytools", "hex-literal", @@ -8172,7 +8172,7 @@ dependencies = [ [[package]] name = "serialization-tagged" -version = "1.3.0" +version = "1.3.1" dependencies = [ "parity-scale-codec", "proptest", @@ -8184,7 +8184,7 @@ dependencies = [ [[package]] name = "serialization-tagged-derive" -version = "1.3.0" +version = "1.3.1" dependencies = [ "itertools 0.14.0", "proc-macro2", @@ -8540,7 +8540,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "storage" -version = "1.3.0" +version = "1.3.1" dependencies = [ "common", "rstest", @@ -8553,7 +8553,7 @@ dependencies = [ [[package]] name = "storage-backend-test-suite" -version = "1.3.0" +version = "1.3.1" dependencies = [ "libtest-mimic", "logging", @@ -8568,7 +8568,7 @@ dependencies = [ [[package]] name = "storage-core" -version = "1.3.0" +version = "1.3.1" dependencies = [ "common", "itertools 0.14.0", @@ -8581,7 +8581,7 @@ dependencies = [ [[package]] name = "storage-failing" -version = "1.3.0" +version = "1.3.1" dependencies = [ "enumflags2", "storage", @@ -8593,7 +8593,7 @@ dependencies = [ [[package]] name = "storage-inmemory" -version = "1.3.0" +version = "1.3.1" dependencies = [ "storage-backend-test-suite", "storage-core", @@ -8602,7 +8602,7 @@ dependencies = [ [[package]] name = "storage-lmdb" -version = "1.3.0" +version = "1.3.1" dependencies = [ "lmdb-mintlayer", "logging", @@ -8616,7 +8616,7 @@ dependencies = [ [[package]] name = "storage-sqlite" -version = "1.3.0" +version = "1.3.1" dependencies = [ "hex", "logging", @@ -8719,7 +8719,7 @@ checksum = "b285e7d183a32732fdc119f3d81b7915790191fad602b7c709ef247073c77a2e" [[package]] name = "subsystem" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "cfg-if", @@ -8875,7 +8875,7 @@ checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "test-rpc-functions" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "chainstate", @@ -8897,7 +8897,7 @@ dependencies = [ [[package]] name = "test-utils" -version = "1.3.0" +version = "1.3.1" dependencies = [ "common", "crypto", @@ -9079,7 +9079,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokens-accounting" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "chainstate-types", @@ -9538,7 +9538,7 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "tx-verifier" -version = "1.3.0" +version = "1.3.1" dependencies = [ "accounting", "chainstate-storage", @@ -9567,14 +9567,14 @@ dependencies = [ [[package]] name = "typename" -version = "1.3.0" +version = "1.3.1" dependencies = [ "typename-derive", ] [[package]] name = "typename-derive" -version = "1.3.0" +version = "1.3.1" dependencies = [ "itertools 0.14.0", "quote", @@ -9734,7 +9734,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utils" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "clap", @@ -9769,7 +9769,7 @@ dependencies = [ [[package]] name = "utils-networking" -version = "1.3.0" +version = "1.3.1" dependencies = [ "addr", "itertools 0.14.0", @@ -9784,7 +9784,7 @@ dependencies = [ [[package]] name = "utxo" -version = "1.3.0" +version = "1.3.1" dependencies = [ "chainstate-types", "common", @@ -9858,7 +9858,7 @@ dependencies = [ [[package]] name = "wallet" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "async-trait", @@ -9911,7 +9911,7 @@ dependencies = [ [[package]] name = "wallet-address-generator" -version = "1.3.0" +version = "1.3.1" dependencies = [ "clap", "common", @@ -9927,7 +9927,7 @@ dependencies = [ [[package]] name = "wallet-address-generator-lib" -version = "1.3.0" +version = "1.3.1" dependencies = [ "build_utils", "clap", @@ -9942,7 +9942,7 @@ dependencies = [ [[package]] name = "wallet-cli" -version = "1.3.0" +version = "1.3.1" dependencies = [ "clap", "ctor", @@ -9953,7 +9953,7 @@ dependencies = [ [[package]] name = "wallet-cli-commands" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "bigdecimal", @@ -10010,7 +10010,7 @@ dependencies = [ [[package]] name = "wallet-cli-lib" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "blockprod", @@ -10060,7 +10060,7 @@ dependencies = [ [[package]] name = "wallet-controller" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "async-trait", @@ -10101,7 +10101,7 @@ dependencies = [ [[package]] name = "wallet-rpc-client" -version = "1.3.0" +version = "1.3.1" dependencies = [ "async-trait", "base64 0.22.1", @@ -10133,7 +10133,7 @@ dependencies = [ [[package]] name = "wallet-rpc-daemon" -version = "1.3.0" +version = "1.3.1" dependencies = [ "clap", "common", @@ -10150,7 +10150,7 @@ dependencies = [ [[package]] name = "wallet-rpc-lib" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "async-trait", @@ -10193,7 +10193,7 @@ dependencies = [ [[package]] name = "wallet-storage" -version = "1.3.0" +version = "1.3.1" dependencies = [ "bip39", "common", @@ -10212,7 +10212,7 @@ dependencies = [ [[package]] name = "wallet-test-node" -version = "1.3.0" +version = "1.3.1" dependencies = [ "blockprod", "chainstate", @@ -10233,7 +10233,7 @@ dependencies = [ [[package]] name = "wallet-types" -version = "1.3.0" +version = "1.3.1" dependencies = [ "bip39", "common", @@ -10376,7 +10376,7 @@ dependencies = [ [[package]] name = "wasm-doc-gen" -version = "1.3.0" +version = "1.3.1" dependencies = [ "anyhow", "clap", @@ -10422,7 +10422,7 @@ dependencies = [ [[package]] name = "wasm-wrappers" -version = "1.3.0" +version = "1.3.1" dependencies = [ "bip39", "common", diff --git a/Cargo.toml b/Cargo.toml index a0503442f..9b493a686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ homepage = "https://mintlayer.org" repository = "https://github.com/mintlayer/mintlayer-core" readme = "README.md" license = "MIT" -version = "1.3.0" +version = "1.3.1" edition = "2024" [workspace] @@ -128,7 +128,7 @@ utxo = { path = "utxo" } [workspace.package] edition = "2024" rust-version = "1.92" -version = "1.3.0" +version = "1.3.1" license = "MIT" [workspace.dependencies] diff --git a/api-server/CHANGELOG.md b/api-server/CHANGELOG.md index d2ee456c4..5491aea74 100644 --- a/api-server/CHANGELOG.md +++ b/api-server/CHANGELOG.md @@ -6,6 +6,10 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/ ## [Unreleased] +## [1.3.1] - 2026-06-03 + +No changes + ## [1.3.0] - 2026-04-09 ### Added diff --git a/build-tools/docker/example-mainnet-dns-server/.env b/build-tools/docker/example-mainnet-dns-server/.env index e7a3627cd..e3a6d62f9 100644 --- a/build-tools/docker/example-mainnet-dns-server/.env +++ b/build-tools/docker/example-mainnet-dns-server/.env @@ -4,7 +4,7 @@ COMPOSE_PROJECT_NAME=mintlayer-mainnet-dns-server # Dockerhub username, from which the docker images will be pulled. ML_DOCKERHUB_USERNAME=mintlayer -# The image tag to use, e.g. "v1.3.0" or "latest". +# The image tag to use, e.g. "v1.3.1" or "latest". ML_DOCKER_IMAGE_TAG=latest # The user and group ids that will be used to run the software. diff --git a/build-tools/docker/example-mainnet/.env b/build-tools/docker/example-mainnet/.env index 1f1e5c73a..871b088c3 100644 --- a/build-tools/docker/example-mainnet/.env +++ b/build-tools/docker/example-mainnet/.env @@ -4,7 +4,7 @@ COMPOSE_PROJECT_NAME=mintlayer-mainnet # Dockerhub username, from which the docker images will be pulled. ML_DOCKERHUB_USERNAME=mintlayer -# The image tag to use, e.g. "v1.3.0" or "latest". +# The image tag to use, e.g. "v1.3.1" or "latest". ML_DOCKER_IMAGE_TAG=latest # The user and group ids that will be used to run the software. diff --git a/common/src/chain/config/checkpoints_data/mainnet.rs b/common/src/chain/config/checkpoints_data/mainnet.rs index e4ff0b555..f7aa2d300 100644 --- a/common/src/chain/config/checkpoints_data/mainnet.rs +++ b/common/src/chain/config/checkpoints_data/mainnet.rs @@ -1031,4 +1031,81 @@ pub const CHECKPOINTS_DATA: &[(u64, &str)] = &[ (571000, "E1FE292E481108C0E175C360FEA4855E6E14379E41E3380FF62BB9CEC165FE1B"), (571500, "680FF51717E055C75BC6327EBEE87AF168B9453775805601C3C9A9DF52F9F082"), (572000, "08F370D7E17B2D62901D1C5E5E71B6134AB0A8518FBAFC7026BFFCDADE7AE038"), + (572500, "9FF71B9096AABEB1E1A68C64AFB191AD18F78F4F4A874922F85B41BD30F146F6"), + (573000, "154F8C9744BB90199234180B45AF1267A6439887BD18691A5A27753C5978E325"), + (573500, "97F9550868D0EB93A184DED8F88390E53EECCEEAA64653070579689163975F5E"), + (574000, "FA830BA235F51A9DF194D7CD4D0B89225CCC2E911B1D3C5C469F19BC6591B020"), + (574500, "54B6F3F339257E8D46EC619C8906EB435B3E8662B351421E5EE548E571643230"), + (575000, "5DC351494BF552B4F043CD91BEF4492042CE774E4679F5E7644F7E96C01406DD"), + (575500, "82BBD7DFD7C7990D091C68E9FED49884FED09E59743A41A0F5AA092B689EAB95"), + (576000, "888E895CF50D46139DC2296601DEF25BB8B82728F97E466E4D14D8E5282B84DE"), + (576500, "938599E15B2361307115322F8872F1CABCB37AB74EB51A196E9F9549F93F38B2"), + (577000, "8FB79FFFE8BE597050479F255D7896756A5F04E49FE4511EB2442677C5F303F6"), + (577500, "905528C2F12C23250348CE95FB318FD5A82573D6D9B3B1D74F34D3498B446B1B"), + (578000, "B92F84AF82489387BEB7C06AAF4DFEF2E73301ED02E9DCA1ED97D20E684B89E9"), + (578500, "D9100010DF7B61FD64DBC95604123CF989232B7BC7C0886DA021F5FD8D50C8AD"), + (579000, "44295AFD81231BE3D195BCD0D9B85EAFF34B12384752600FE9CE45EF2321A33A"), + (579500, "0C95513C2FE846C4A26A0E1D84A54F9CB2C8FA03D2665FD705640B90ECC162F9"), + (580000, "FF2ACB29B02A994119B57B5DA7F61410DA848FDCAA936E444D7BDEEBC5A98BD1"), + (580500, "CF0DB4325A7CB866282AD011C2506D258E11B5E905054D6FA3D4BC96B731DC87"), + (581000, "13154D1F904501EEA092C46886A9D24BC212BB48B5C19997F1E476B34676BC69"), + (581500, "3154CB99BD507B68908D30545573CFBE8227F2D70DAADB63EC17BAA57D0A25B2"), + (582000, "9C50E359087118288AE1602A14AAA0ADFE39EF72A2D1606C3782B622D4164F95"), + (582500, "E5C65276CE9019D308A3B8058562DF238B9875A7474DB489598705F501CE475E"), + (583000, "B88BD6E98219A4D3CBBB63471CF6146589BE986E8AB5EC5D0F055D03F27DFB6D"), + (583500, "662E95DF3D838F2C17E99E3FFD5CF0773BF3AC3618B25A682E394044BCD3F742"), + (584000, "A545E888816623E98E9AEEFC1BABB67BAE07008A438BE777DD77BA95832D1491"), + (584500, "1E727BB89E44A5D6E4772E43B07FCDF89721B0C16992C49816A55B1A72C2EB6D"), + (585000, "BCBF1FC7C967ACF6B00A7F21CAF0EFF2080BE937B8F0AE8D3AF9C87955122CC5"), + (585500, "088E1C3205E95CF95F117054560FD2640280F2CDE9D71933EC2370439DEEA9BF"), + (586000, "6813913B325E62E99270F2BE9DCADF2BEE6AA74DD1CEF5966CCA6435EE717507"), + (586500, "DF8AA27DB196F74D8A86A952DDD75789F00BC119B0ED2030E3857C5E5240089E"), + (587000, "770A40FCE1FBF89CCB43A76D2411C1B1A817106D5F8CB89768AE6E0583D84E9D"), + (587500, "1054B6E45F1D0C882E688A4C5091E2E2E39CC8F66B3A96279E9597A9475917AD"), + (588000, "15E11732DD23EBE78CC5FD703004E7DCCC96253401CEB0697063D822D77499EB"), + (588500, "B78C0930380B6B4033CF211B80AB0189DB528C9E231BE6EC30D3CA41AFDB7061"), + (589000, "043DF995514330EB269C52E6760CF4E53804699DCE1E541B720B6934D665E5FD"), + (589500, "EE82505F86230110A06C15655AE5346FDA103155DA7AA8AB4BE5CBC2CEDEA60A"), + (590000, "ADC8835919DE04689FCF3FE25FA5B8C8A3D04528D55A5B46E02D19001907C29D"), + (590500, "265D271C0D5A474F980C80D2C05A68C184FCE407D26346DBCA4A819CC01D1D57"), + (591000, "232B8307D70C45CDEE81AB0965F8B0BCFD45C3A124B8E425E57972998DA9CE14"), + (591500, "ECD2FD7A903396FF4ECC9C9DF4EBA158C8DE5CB5C6872FF9CE40473E0A9AC687"), + (592000, "8352DB0AA07F0B090A906393633E517A5EC03C90585A38E47E8F39E3610AD3D2"), + (592500, "0A325174E9741832A7FFA2E5311830989FCE581A99E8A4C88E5A182A567A41CB"), + (593000, "F53FE957CBD3C4B9CD49426F95DCAC0484B0EF6498518DCD99B5D3CB93DF3E2A"), + (593500, "EC1A95B439A3DBA96BBB6E60BEAA4E906D259B5055B5D9CAFFA8918033F67A1C"), + (594000, "74263832D93E5BA1306FEDE16B644F0E40161F674EFC383311DAF3563E583415"), + (594500, "3F3B59DEB89D0046B31F1B08979422DA41186B0138488D1B02BA031C95C0D03C"), + (595000, "39235B251ADB908D1190A025F2BA7840D222B6816643C9DC4C61F1B6E1386C2E"), + (595500, "318F6D52C41A5C3A8399D66E181587919BF99A4AB16F49602E363B2239A916B5"), + (596000, "BC574068D1682FBAA4085B8E68B581E4598F9F13565B7ABB064CEFD1B56895AC"), + (596500, "23885CA1F69C2C0DE5C0BC47C1025E1E933252E73C89334D051FE39F4DE6F086"), + (597000, "026F3F7572AE0D2FC92756CDC3CFEEB0F3757F25C0D51090F6A279088726B797"), + (597500, "23B3A6942644500B8896B32231F7B47A62496305717D58420130DFDD8539D901"), + (598000, "DAC6C47F0A2D5013973125B1C23B69DE4C85C2B25DFCB9CD8C2C9A3369033EB7"), + (598500, "D7BEB0BBFC817CBA264A4AFC2216BE171AADF929DC2A876BB58F5988D8185690"), + (599000, "857C3045927B5FBB8A2DA00F37A212D0CEFA8A4E7EDCF5041DDC37300E40DC77"), + (599500, "1855AC787B9372A53A00B3ECC45C8C63EDC2D5C292F623D1A64FE1A86CE58E22"), + (600000, "F573BFF2067EC8A5E1501178BFA0FF817417BDF4344B0E4A9A75B9681878CEB3"), + (600500, "0064604064C7FD0C381F45427D2E45D7FAE4C938D9F4D7AC527ACA0CF14345BF"), + (601000, "09077F902A869B160D4628CF140D1D127B8258817710E898553EFD00E57D2FC4"), + (601500, "5D21ABBCDEF75F0A0A2F0B141F22A55D501A3376F04A763A28C3710940F7946E"), + (602000, "E9E3F90235FB9222DCDE99BB562A29DCEEE3FBA23898323912DEC6AC04D0365D"), + (602500, "F746D40BB3D35AB372E67590099C64FA4E427C97BFC1636D20D53F4F5B4ADCB3"), + (603000, "2B08F7B90A65CBFBB375FD15917A8BFA040423D5B4F5055C44887357D47E13B7"), + (603500, "CBA56847AB4478C310C3A4445CE3FD2D7CBADEDDE0048E2E899B59952058B45B"), + (604000, "C62FA7D291C42246D1540C32007A8C164E7112029A213C7416A54B2B38FCBC57"), + (604500, "41EC6FB625B26E072E3337EF423382F841A629B39119EC8E9F78723BF72D10A5"), + (605000, "97380622B5818ADF1024105516EBB01F9931B777F7011CBB713E0767C6CFACD9"), + (605500, "67005D1D46C18808C569C43CA64A10F0C8F40AF90BFBA1A138A4257034AC4DD4"), + (606000, "DF56F9AA7A0327D789320083FCEF96939BAF32D03097803FA61DCF65EE347B15"), + (606500, "EBD9B06C1A0AE56C1A02D6AA4CE3473E67D2DE0DE2E054413606F5C7D7D8FCC5"), + (607000, "4F5A869919347634677D5BCE216A30CFDE5CB1CD09CCDBB43903AAFFC24F0BE2"), + (607500, "75F3962FA2538B89EFF29AAF80C00026FE2D183C41CB4A7D0E5752AC13B0FCD9"), + (608000, "4CAA0695EB1396B748291A12E1E2BE93F1AAB418BCB27A33B89518EF327C9089"), + (608500, "2D9B82A2D269894A4C98E3B7F2918B6E1D37C14794A85719EA661BAE9C342563"), + (609000, "6BEFA2885B689CA8D41866090EF95D9E65804AA7E5702146462A262A3132BED3"), + (609500, "713EEDDB8D27D547A69E6E056B282206CDC85914D514DA1958693C58E593010B"), + (610000, "EEC7EA398230E662121E3527BC552ECC6F707E4A292CDE654C76F1A2C6B97F79"), + (610500, "B5657FEAFA70591DE7096BF1C3CFF6134631AD612CDFD8C18818BC6AB86C98F5"), ]; diff --git a/common/src/chain/config/checkpoints_data/testnet.rs b/common/src/chain/config/checkpoints_data/testnet.rs index 35bc4a3e4..b70354e27 100644 --- a/common/src/chain/config/checkpoints_data/testnet.rs +++ b/common/src/chain/config/checkpoints_data/testnet.rs @@ -1289,4 +1289,80 @@ pub const CHECKPOINTS_DATA: &[(u64, &str)] = &[ (699000, "1BE1CA072B2917B5701076D255736E2273310BA3EE2A352A4B01ED6469039BF3"), (699500, "1D9DCFB70F0E49B9D701B5002000AD34150C20BDE776761D064A82D75473D23E"), (700000, "7C64C4C6B4004BA5C0807D1DF4AC631926A4B12B33FED40FDA285428824C8A02"), + (700500, "B0C8589D75E30ADC8F0CEC6FE882C5CB70D2F749E35D5EBF748D433964A318D8"), + (701000, "2972DB8142E0566E2F50C24232DE46428B60D50D2C4B654923FCAA159F7E2203"), + (701500, "E4F96B3270EF59628114375B1BF727ABA4D15684D8877B564160F4D2168EAC27"), + (702000, "07093CE01C05F74B34687D0CE9D7A02BCA564DEBE5083E2283831A0D9ED542BF"), + (702500, "55899518D812DD4D5DC54D7E9FA8048E1CE82FF23CB88641FB5DCDD9B91717D0"), + (703000, "124A0F31E0F91459B2AB4F320AB4C6AFFB83C984FC7D7F2A4A6FB65DFE89A8AA"), + (703500, "003586ABE3993BA06B9F9315B213A4138CDBDFB02CBACB97C5EE1E8FB617C20D"), + (704000, "FBC2ABA8D2B4F0A2EDFC87F40448C19559293F15FE7E3029DF4FB06AD7ABE118"), + (704500, "F2225A757D225D2A5ED1D13025E05705116CADEE7D0A20430F0DD5F8BEF4F131"), + (705000, "CA8BC73D5FB1C47113629002F8DD456DD227DA436B6B4544444E89AA4C671867"), + (705500, "F23E9F56A6F2579D945DAFAD6AF3A725157284491F34C44F90E9B6732D901518"), + (706000, "CD86359DE4B0B1CE7D8BE4FAADBD8C3092A18067EF700624AFC8B1B44DF60F95"), + (706500, "3262DFB6B26047B5DD1742619D6DD0673A52A2167E86A835CE569B03A228BBD5"), + (707000, "D5E27A87531E29763E3F7D711BE6AFFEDAE60C83BFFD855A137860A4658EC134"), + (707500, "93014E32C099EAA9D15F6ECA007C06DA2E02C5127468FA09EBAD6C59B85ED366"), + (708000, "148E55C9A9D0FAD47143C67B19CFB96128AA71CBFB795970A1F1D4836925D283"), + (708500, "72AF91E1A4958B4C6A949EF6A6CFF3879F99D5A8D4C42AE84CA55A6FDDB2C351"), + (709000, "8C617F301F52F6492F53C2BC71021B88B1536B29E01ED5E67510E055BBB13CB4"), + (709500, "A6DFFEE8F80922466565498A945267B1FED451EF33BE8CD5BC027AF1F1B5C59E"), + (710000, "C3083C6B254EB676EA6CDB100145B670ED89337906F86B9227BAE0DED6B19CCF"), + (710500, "697D6D97D46C07D51B53CD74B142FE6AEB9599915F4CB732D690764272737DA0"), + (711000, "8B618FC8298746F07D7F68A4679ECA51EDF50B8202EA50D482583A0910BA6AB9"), + (711500, "6696345D7CFFF9E073401DD985B67756FE87A6973DB609A0585BCF2F0E730EBD"), + (712000, "0B52B9FDD0E977183E2079C26411D3368372E20D43F1B1EF2975A9ED7F8CDF36"), + (712500, "DA724AA8874096DB15AE88E6C4FF69A6DBA50FBC7A362853438D1D91D3B02072"), + (713000, "00898F03F56262E6CB4DAE2E329F671313E14522B52FC4F83D10EF39DF8623DB"), + (713500, "38E06BAC679A35B1D7563DF569F8D467249ED2CB2699B1C6271181CD83424565"), + (714000, "53DAF384FCEF436EEA747355F78557CF0F6392021B9445E503EA1D93F0FE5D35"), + (714500, "FC5D388FEEA864FC38759F4CED291C9532C5A1ACBC9866FD18B5C3B26C121EDF"), + (715000, "6D00A8FE67A7BB0444BD7C25C31DCD618BDA8BB3F70F6CA950CAB5FA77B05729"), + (715500, "8FBE0F867714CF4CC91669C2BAAE3923397F5C0153E0FB88E759A362EDBE7679"), + (716000, "07AECB3AEB119487CECF7E6D27869786CFA57BEA1745A30A1700D43502E5F10A"), + (716500, "2A71878118FA95C6E11EBEF01A09343B84C24F08C574E38C9ED2350C39881E1B"), + (717000, "EB50CB5A4CA0F4F9BF47A44AF4BC3D7A4000581C47B74F1CF4AADC08359B22BF"), + (717500, "B635B1C21AE76CF503D00F0B454E12CDC413BE974AEEC4B366C17901321FCE4D"), + (718000, "7F9CDB5C0C0A50FC413C63F60F89F3167E8DA6280625386574DD69CFF08C635F"), + (718500, "C56291025A0BECAA559B370195541F01347D3189FEE62B006A17EDFD695128ED"), + (719000, "CBF9E262BB1C010F0E4C91E2E4D164D7F1A4FAE45FB24443F7D831804AAD46E8"), + (719500, "83C8E37ED3A071197E9FA6FDF5558421C567F4DE22CBB575AF181224516AF59C"), + (720000, "9B3713893037F5F259AF9B142FFEA5B04A17FFF8EA0293A7CFFFB5ADAECFD119"), + (720500, "277BB9066F0961C4BB37918CDB7E17D3ED11440521843297E3293D744A25C1EB"), + (721000, "4683630294E33E956EA9731FD3B418FAF8828A6AB02D3F7F7B803804A84E36C5"), + (721500, "BE2C7779050CD9ABD28EA6EF603CAF0F56CAD9024762EB964B0EE33162196F94"), + (722000, "98D577BE72031B36C2E4A57ECF68585DF8C7259F0D2B392B1C74E2A8438434F5"), + (722500, "818E3C2F9A8782EBCB93905E1A577D1BA44ED31C1728F9F39797D02047C1F6E5"), + (723000, "4CC30956A313CBF26E2784F2B3C7B245EA76F2DC7B6A54B32EF0EDB3D54A669C"), + (723500, "12AA7E2DFEA164FF3F30BB4E7078C9670738E8B9B8092B194F39DC4D4EDC6D62"), + (724000, "397006774D0A2054FB75C2F3988C3440235749FF8625B85B4F008EC8BABB16D4"), + (724500, "454559EAEC445CCA2A585A9763DC938D66ECE93818372E78F19E98EA89011530"), + (725000, "A48168E5A3D46D63E8B900E28E4B6F556D4EF0BD431E2C59926293C27E8C297B"), + (725500, "D2A267354419FF462214779E60B74342CF2FC485AEA6DE14F39CD9F9BA80CBC4"), + (726000, "B403317107F0D9E02F89E1F34A8DC96328FA917FB9329077AB84388A6D19BBA5"), + (726500, "3B2D32D9AB8B44F067C9D61C547884E5CAD0A3BB6113390C179976960EE0F3D4"), + (727000, "23AD6E1A6CFFB967CBF64A9D7654E8DAE09AF4CA18710A5D5BAD369C49656F2C"), + (727500, "A6C3C31BE9708D80F3894924BE2303DA7E43A929AA533879F8C02BF5769981E5"), + (728000, "6DC9464D27B2D81B8826412520B131F3D50D0F2C3777CDA20C531F7DD8D7A559"), + (728500, "3ED0BE60943942DE55AB455BF786BC74573424F5B6499564119AD5CA86BFF843"), + (729000, "8188A961C0D999A219429AA38DC937865154F4FFA6F52CF42C94EE710D1D5AFD"), + (729500, "E06AC361B6749A024F91D777030FE2CB9650C1574E5DE2565DFA73DB6C836E93"), + (730000, "6F4B3620AE3AC97DB9DFA2DD57A540DD0DB78A14DB66FE290137B328347AC69A"), + (730500, "3DB6A56E2AFCD453FC721290ABFD3B63D50E36C8505F2E1EDF6847852DFE915A"), + (731000, "532305C427CDF24CB8E429EDABEF3B0299256935419909BB5F8D23ED9B9B1854"), + (731500, "18ABC13E9122EE13AEF49C8330F6CD41A5E9F29E171572D5C25D30C3C4455E83"), + (732000, "DF0DFB4A5D069FA9FE0B2E45185E29A5E8F54EAF210664E1DAFF7C534359A90A"), + (732500, "1F7814610C3B71DC81582133A9C4A9014FA518EA0A0696E2DC92C5FE465EBFB3"), + (733000, "EAF8BFC36FC4FCE5448654DCF808FC4F971DC57945A15C5277518B8E91650EB3"), + (733500, "B6143131629322D1E030692F6ED24B022AAC9AA493C254E13D2C44D9303AFF34"), + (734000, "3CF89CBEAF917C5171F266BA4FF8C50C18507CF911A79A6B0E3340958B637409"), + (734500, "50DD1C4AA1D1DC2146978E53011A33BABE8115A1C0D407E18A19DADBCC31AD9A"), + (735000, "EB3BFC1D1D8E3EB8BC15D53B808AF78FF159DCF4D3810E9811608CAEDA34A2DB"), + (735500, "4951BE78DE943D1A8744E95FCEEB2B0EBAA31323A1C526DEFE8E094CA7A45AFD"), + (736000, "651A0BCB3904BA3383361E31E27E09FFEFD4B679F3C2FE995DCB0F1C43CA1755"), + (736500, "A68B45E302F3811FAA71C77F4A465949A1E600E84C7BABF07B538E72A261F72F"), + (737000, "AED233AFB23BCF49DA9AD6AD27A8F77C25F366BF60A37E6803474C154B424785"), + (737500, "6B5E866C4198463DFB9BB7FC2BCEC755369800429A275847912B2EE3BC1E18AE"), + (738000, "02C9E23C5E990419CD591703A1DB54C28F31E4DB5EDBA1ED88C7CE9DBF4D1142"), ]; diff --git a/mempool/src/pool/tx_pool/tests/utils.rs b/mempool/src/pool/tx_pool/tests/utils.rs index bc9ae9a84..e272a5051 100644 --- a/mempool/src/pool/tx_pool/tests/utils.rs +++ b/mempool/src/pool/tx_pool/tests/utils.rs @@ -406,10 +406,9 @@ pub async fn tx_spend_input( fee: impl Into>, flags: u128, ) -> anyhow::Result { - let fee = fee.into().map_or_else( - || get_relay_fee_from_tx_size(estimate_tx_size(1, 2)).into(), - std::convert::identity, - ); + let fee = fee + .into() + .unwrap_or_else(|| get_relay_fee_from_tx_size(estimate_tx_size(1, 2)).into()); tx_spend_several_inputs(tx_pool, &[input], &[witness], fee, flags).await } diff --git a/node-daemon/docs/RPC.md b/node-daemon/docs/RPC.md index 311b2939b..741633fd4 100644 --- a/node-daemon/docs/RPC.md +++ b/node-daemon/docs/RPC.md @@ -1,6 +1,6 @@ # RPC documentation for Mintlayer node -Version `1.3.0`. +Version `1.3.1`. ## Module `node` diff --git a/node-daemon/docs/RPC_DEV.md b/node-daemon/docs/RPC_DEV.md index 639fb8c2a..16e665041 100644 --- a/node-daemon/docs/RPC_DEV.md +++ b/node-daemon/docs/RPC_DEV.md @@ -1,6 +1,6 @@ # RPC documentation for Mintlayer node developer functions -Version `1.3.0`. +Version `1.3.1`. These functions are used for testing and only enabled in regtest. diff --git a/wallet/TREZOR_SUPPORT.md b/wallet/TREZOR_SUPPORT.md index 8d3ee8710..8f79b6ae3 100644 --- a/wallet/TREZOR_SUPPORT.md +++ b/wallet/TREZOR_SUPPORT.md @@ -42,7 +42,7 @@ The Mintlayer firmware version determines the compatibility between the firmware | Mintlayer Core version | Required Mintlayer firmware version | | --- | --- | -| 1.1.0, 1.2.x, 1.3.0 | 1.x.x | +| 1.1.0, 1.2.x, 1.3.x | 1.x.x | Note: if you've built Core wallets directly from `master` instead of using a specific release, you'll probably won't be able to use a specific release for the firmware either. diff --git a/wallet/src/signer/ledger_signer/mod.rs b/wallet/src/signer/ledger_signer/mod.rs index 49b99fd1e..27c124a06 100644 --- a/wallet/src/signer/ledger_signer/mod.rs +++ b/wallet/src/signer/ledger_signer/mod.rs @@ -1235,8 +1235,17 @@ impl SignerProvider for LedgerSignerProvider { type S = LedgerSigner; type K = AccountKeyChainImplHardware; - fn provide(&mut self, chain_config: Arc, _account_index: U31) -> Self::S { - LedgerSigner::new(chain_config, self.client.clone(), self.clone()) + fn provide( + &mut self, + chain_config: Arc, + _account_index: U31, + _db_tx: &impl WalletStorageReadLocked, + ) -> WalletResult { + Ok(LedgerSigner::new( + chain_config, + self.client.clone(), + self.clone(), + )) } async fn make_new_account( diff --git a/wallet/src/signer/ledger_signer/tests/mod.rs b/wallet/src/signer/ledger_signer/tests/mod.rs index f12124f7e..f6f71462b 100644 --- a/wallet/src/signer/ledger_signer/tests/mod.rs +++ b/wallet/src/signer/ledger_signer/tests/mod.rs @@ -316,15 +316,10 @@ async fn test_sign_transaction_intent(#[case] seed: Seed) { #[rstest] #[trace] #[serial_test::serial] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V1)] +#[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] -async fn test_sign_transaction( - #[case] seed: Seed, - #[case] input_commitments_version: SighashInputCommitmentVersion, -) { - log::debug!( - "test_sign_transaction, seed = {seed:?}, input_commitments_version = {input_commitments_version:?}" - ); +async fn test_sign_transaction(#[case] seed: Seed) { + log::debug!("test_sign_transaction, seed = {seed:?}"); let (auto_confirmer_handle, control_msg_tx, make_ledger_signer) = setup(false).await; @@ -332,7 +327,8 @@ async fn test_sign_transaction( test_sign_transaction_generic( &mut rng, - input_commitments_version, + false, + SighashInputCommitmentVersion::V1, make_ledger_signer, no_another_signer(), false, @@ -399,15 +395,10 @@ async fn test_sign_transaction_intent_sig_consistency(#[case] seed: Seed) { #[rstest] #[trace] #[serial_test::serial] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V1)] +#[case(Seed::from_entropy())] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] -async fn test_sign_transaction_sig_consistency( - #[case] seed: Seed, - #[case] input_commitments_version: SighashInputCommitmentVersion, -) { - log::debug!( - "test_sign_transaction_sig_consistency, seed = {seed:?}, input_commitments_version = {input_commitments_version:?}" - ); +async fn test_sign_transaction_sig_consistency(#[case] seed: Seed) { + log::debug!("test_sign_transaction_sig_consistency, seed = {seed:?}"); let (auto_confirmer_handle, control_msg_tx, make_ledger_signer) = setup(true).await; @@ -415,7 +406,8 @@ async fn test_sign_transaction_sig_consistency( test_sign_transaction_generic( &mut rng, - input_commitments_version, + false, + SighashInputCommitmentVersion::V1, make_ledger_signer, Some(make_deterministic_software_signer), false, diff --git a/wallet/src/signer/mod.rs b/wallet/src/signer/mod.rs index 4840d70ab..07139393f 100644 --- a/wallet/src/signer/mod.rs +++ b/wallet/src/signer/mod.rs @@ -182,7 +182,12 @@ pub trait SignerProvider: Send { type S: Signer + Send; type K: AccountKeyChains + Sync + Send; - fn provide(&mut self, chain_config: Arc, account_index: U31) -> Self::S; + fn provide( + &mut self, + chain_config: Arc, + account_index: U31, + db_tx: &impl WalletStorageReadLocked, + ) -> WalletResult; async fn make_new_account( &mut self, diff --git a/wallet/src/signer/software_signer/mod.rs b/wallet/src/signer/software_signer/mod.rs index 7cbed1511..164df1cf7 100644 --- a/wallet/src/signer/software_signer/mod.rs +++ b/wallet/src/signer/software_signer/mod.rs @@ -20,7 +20,8 @@ use itertools::Itertools; use common::{ chain::{ - ChainConfig, Destination, SignedTransactionIntent, Transaction, TxOutput, + ChainConfig, Destination, SighashInputCommitmentVersion, SignedTransactionIntent, + Transaction, TxOutput, config::ChainType, htlc::HtlcSecret, signature::{ @@ -49,7 +50,7 @@ use crypto::key::{ hdkd::{derivable::Derivable, u31::U31}, }; use randomness::make_true_rng; -use utils::ensure; +use utils::{debug_panic_or_log, ensure}; use wallet_storage::{ WalletStorageReadLocked, WalletStorageReadUnlocked, WalletStorageWriteUnlocked, }; @@ -59,7 +60,7 @@ use wallet_types::{ partially_signed_transaction::{PartiallySignedTransaction, TokensAdditionalInfo}, seed_phrase::StoreSeedPhrase, signature_status::SignatureStatus, - wallet_type::WalletType, + wallet_type::SoftwareWalletType, }; use crate::{ @@ -76,11 +77,16 @@ use super::{Signer, SignerError, SignerProvider, SignerResult, utils::is_htlc_ut pub struct SoftwareSigner { chain_config: Arc, account_index: U31, + wallet_type: SoftwareWalletType, sig_aux_data_provider: Mutex>, } impl SoftwareSigner { - pub fn new(chain_config: Arc, account_index: U31) -> Self { + pub fn new( + chain_config: Arc, + account_index: U31, + wallet_type: SoftwareWalletType, + ) -> Self { let use_deterministic_signer = *chain_config.chain_type() == ChainType::Regtest && cfg!(feature = "use-deterministic-signatures-in-software-signer-for-regtest"); @@ -88,12 +94,14 @@ impl SoftwareSigner { Self::new_with_sig_aux_data_provider( chain_config, account_index, + wallet_type, Box::new(PredefinedSigAuxDataProvider), ) } else { Self::new_with_sig_aux_data_provider( chain_config, account_index, + wallet_type, Box::new(make_true_rng()), ) } @@ -102,11 +110,13 @@ impl SoftwareSigner { pub fn new_with_sig_aux_data_provider( chain_config: Arc, account_index: U31, + wallet_type: SoftwareWalletType, sig_aux_data_provider: Box, ) -> Self { Self { chain_config, account_index, + wallet_type, sig_aux_data_provider: Mutex::new(sig_aux_data_provider), } } @@ -291,8 +301,19 @@ impl Signer for SoftwareSigner { Vec, Vec, )> { - let input_commitments = - ptx.make_sighash_input_commitments_at_height(&self.chain_config, block_height)?; + let input_commitments = match self.wallet_type { + SoftwareWalletType::Hot => { + ptx.make_sighash_input_commitments_at_height(&self.chain_config, block_height)? + } + SoftwareWalletType::Cold => { + // Wallet in the cold mode is not aware of the actual chain height, so block_height + // will always be zero here. Since at the moment of writing this the fork has already + // happened both on testnet and mainnet, we can unconditionally assume input commitments v1. + // TODO: remove the support of input commitments v0 in the wallet, always assume v1. + // Same for orders v0/v1. + ptx.make_sighash_input_commitments(SighashInputCommitmentVersion::V1)? + } + }; let (witnesses, prev_statuses, new_statuses) = ptx .witnesses() @@ -478,9 +499,10 @@ impl SoftwareSignerProvider { ) -> WalletResult { let this_wallet_type = db_tx.get_wallet_type()?; ensure!( - this_wallet_type == WalletType::Hot || this_wallet_type == WalletType::Cold, + this_wallet_type.to_software_wallet_type().is_some(), WalletError::HardwareWalletOpenedAsSoftwareWallet(this_wallet_type) ); + let master_key_chain = MasterKeyChain::new_from_existing_database(chain_config, db_tx)?; Ok(Self { master_key_chain }) } @@ -491,8 +513,26 @@ impl SignerProvider for SoftwareSignerProvider { type S = SoftwareSigner; type K = AccountKeyChainImplSoftware; - fn provide(&mut self, chain_config: Arc, account_index: U31) -> Self::S { - SoftwareSigner::new(chain_config, account_index) + fn provide( + &mut self, + chain_config: Arc, + account_index: U31, + db_tx: &impl WalletStorageReadLocked, + ) -> WalletResult { + let wallet_type = db_tx.get_wallet_type()?; + let software_wallet_type = + wallet_type.to_software_wallet_type().unwrap_or_else(|| { + debug_panic_or_log!( + "Db tx related to a hardware wallet ({wallet_type:?}) was passed to SoftwareSignerProvider::provide" + ); + SoftwareWalletType::Hot + }); + + Ok(SoftwareSigner::new( + chain_config, + account_index, + software_wallet_type, + )) } async fn make_new_account( diff --git a/wallet/src/signer/software_signer/tests.rs b/wallet/src/signer/software_signer/tests.rs index 08f730fbc..8ec1aa2b3 100644 --- a/wallet/src/signer/software_signer/tests.rs +++ b/wallet/src/signer/software_signer/tests.rs @@ -27,7 +27,8 @@ use crate::signer::tests::{ MessageToSign, test_sign_message_generic, test_sign_transaction_generic, test_sign_transaction_intent_generic, }, - make_deterministic_software_signer, make_software_signer, no_another_signer, + make_deterministic_software_signer, make_software_signer, make_software_signer_for_cold_wallet, + no_another_signer, }; #[rstest] @@ -57,19 +58,21 @@ async fn test_sign_transaction_intent(#[case] seed: Seed) { } #[rstest] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V0)] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V1)] +#[case(Seed::from_entropy(), true, SighashInputCommitmentVersion::V0)] +#[case(Seed::from_entropy(), false, SighashInputCommitmentVersion::V1)] #[trace] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_sign_transaction( #[case] seed: Seed, - #[case] input_commitments_version: SighashInputCommitmentVersion, + #[case] before_fork: bool, + #[case] expected_input_commitments_version: SighashInputCommitmentVersion, ) { let mut rng = make_seedable_rng(seed); test_sign_transaction_generic( &mut rng, - input_commitments_version, + before_fork, + expected_input_commitments_version, make_software_signer, no_another_signer(), true, @@ -77,6 +80,28 @@ async fn test_sign_transaction( .await; } +// Cold wallet should assume v1 commitments regardless of what it thinks the current height is. +#[rstest] +#[case(Seed::from_entropy())] +#[trace] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_sign_transaction_cold_wallet( + #[case] seed: Seed, + #[values(false, true)] before_fork: bool, +) { + let mut rng = make_seedable_rng(seed); + + test_sign_transaction_generic( + &mut rng, + before_fork, + SighashInputCommitmentVersion::V1, + make_software_signer_for_cold_wallet, + no_another_signer(), + true, + ) + .await; +} + #[rstest] #[trace] #[case(Seed::from_entropy())] diff --git a/wallet/src/signer/tests/generic_fixed_signature_tests.rs b/wallet/src/signer/tests/generic_fixed_signature_tests.rs index 19dd3424c..b7a73c1ab 100644 --- a/wallet/src/signer/tests/generic_fixed_signature_tests.rs +++ b/wallet/src/signer/tests/generic_fixed_signature_tests.rs @@ -387,9 +387,8 @@ where .unwrap(); assert!(ptx.all_signatures_available()); - let input_commitments = ptx - .make_sighash_input_commitments_at_height(&chain_config, tx_block_height) - .unwrap(); + let expected_input_commitments = + ptx.make_sighash_input_commitments(SighashInputCommitmentVersion::V0).unwrap(); let all_utxos = utxos .iter() .map(Some) @@ -402,7 +401,7 @@ where &chain_config, dest, &ptx, - &input_commitments, + &expected_input_commitments, i, all_utxos[i].cloned(), ) @@ -917,8 +916,8 @@ pub async fn test_fixed_signatures_generic2( ); let ptx = req.into_partially_signed_tx(ptx_additional_info).unwrap(); - let input_commitments = ptx - .make_sighash_input_commitments_at_height(&chain_config, tx_block_height) + let expected_input_commitments = ptx + .make_sighash_input_commitments(input_commitments_version) .unwrap() .into_iter() .map(|comm| comm.deep_clone()) @@ -958,7 +957,7 @@ pub async fn test_fixed_signatures_generic2( &chain_config, dest, &ptx, - &input_commitments, + &expected_input_commitments, i, all_utxos[i].cloned(), ) @@ -1572,8 +1571,8 @@ pub async fn test_fixed_signatures_generic_no_legacy( ); let ptx = req.into_partially_signed_tx(ptx_additional_info).unwrap(); - let input_commitments = ptx - .make_sighash_input_commitments_at_height(&chain_config, tx_block_height) + let expected_input_commitments = ptx + .make_sighash_input_commitments(SighashInputCommitmentVersion::V1) .unwrap() .into_iter() .map(|comm| comm.deep_clone()) @@ -1613,7 +1612,7 @@ pub async fn test_fixed_signatures_generic_no_legacy( &chain_config, dest, &ptx, - &input_commitments, + &expected_input_commitments, i, all_utxos[i].cloned(), ) @@ -1952,8 +1951,8 @@ pub async fn test_fixed_signatures_generic_htlc_refunding( ); let ptx = req.into_partially_signed_tx(ptx_additional_info).unwrap(); - let input_commitments = ptx - .make_sighash_input_commitments_at_height(&chain_config, tx_block_height) + let expected_input_commitments = ptx + .make_sighash_input_commitments(input_commitments_version) .unwrap() .into_iter() .map(|comm| comm.deep_clone()) @@ -1995,7 +1994,7 @@ pub async fn test_fixed_signatures_generic_htlc_refunding( &chain_config, dest, &ptx, - &input_commitments, + &expected_input_commitments, i, all_utxos[i].cloned(), ) diff --git a/wallet/src/signer/tests/generic_tests.rs b/wallet/src/signer/tests/generic_tests.rs index ffb213703..f4c2a04db 100644 --- a/wallet/src/signer/tests/generic_tests.rs +++ b/wallet/src/signer/tests/generic_tests.rs @@ -324,9 +324,15 @@ pub async fn test_sign_transaction_intent_generic( assert_eq!(err, SignerError::DestinationNotFromThisWallet); } +// Note: unlike some other tests (in particular, the "fixed signature" ones) that only accept +// input_commitments_version, which determines both the expected commitments and the height +// at which the signatures will be produced, this test accepts both the expected version +// and the flag `before_fork`, which determines the height. This is used in the software signer +// tests to check that in the cold mode v1 commitments are used regardless of the current height. pub async fn test_sign_transaction_generic( rng: &mut impl CryptoRng, - input_commitments_version: SighashInputCommitmentVersion, + before_fork: bool, + expected_input_commitments_version: SighashInputCommitmentVersion, make_signer: MkS1, make_another_signer: Option, include_orders_v0: bool, @@ -338,9 +344,10 @@ pub async fn test_sign_transaction_generic( { let (sighash_input_commitment_version_fork_height, tx_block_height) = { let fork_height = rng.random_range(100..100_000); - let tx_block_height = match input_commitments_version { - SighashInputCommitmentVersion::V0 => rng.random_range(1..fork_height), - SighashInputCommitmentVersion::V1 => rng.random_range(fork_height..fork_height * 2), + let tx_block_height = if before_fork { + rng.random_range(1..fork_height) + } else { + rng.random_range(fork_height..fork_height * 2) }; ( BlockHeight::new(fork_height), @@ -895,8 +902,8 @@ pub async fn test_sign_transaction_generic( assert_eq!(ptx, another_ptx); } - let input_commitments = ptx - .make_sighash_input_commitments_at_height(&chain_config, tx_block_height) + let expected_input_commitments = ptx + .make_sighash_input_commitments(expected_input_commitments_version) .unwrap() .into_iter() .map(|comm| comm.deep_clone()) @@ -915,7 +922,7 @@ pub async fn test_sign_transaction_generic( &chain_config, dest, &ptx, - &input_commitments, + &expected_input_commitments, i, all_utxos[i].cloned(), ) @@ -990,7 +997,7 @@ pub async fn test_sign_transaction_generic( &chain_config, dest, &ptx, - &input_commitments, + &expected_input_commitments, i, all_utxos[i].cloned(), ) diff --git a/wallet/src/signer/tests/mod.rs b/wallet/src/signer/tests/mod.rs index 765dfc6e0..c8adc1f73 100644 --- a/wallet/src/signer/tests/mod.rs +++ b/wallet/src/signer/tests/mod.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use common::chain::ChainConfig; use crypto::key::{PredefinedSigAuxDataProvider, hdkd::u31::U31}; use wallet_storage::StoreTxRwUnlocked; -use wallet_types::seed_phrase::StoreSeedPhrase; +use wallet_types::{seed_phrase::StoreSeedPhrase, wallet_type::SoftwareWalletType}; use crate::{ Account, @@ -58,7 +58,14 @@ fn account_from_mnemonic( } pub fn make_software_signer(chain_config: Arc, account_index: U31) -> SoftwareSigner { - SoftwareSigner::new(chain_config, account_index) + SoftwareSigner::new(chain_config, account_index, SoftwareWalletType::Hot) +} + +pub fn make_software_signer_for_cold_wallet( + chain_config: Arc, + account_index: U31, +) -> SoftwareSigner { + SoftwareSigner::new(chain_config, account_index, SoftwareWalletType::Cold) } // Return a SoftwareSigner that will produce Trezor-like signatures. @@ -69,6 +76,7 @@ pub fn make_deterministic_software_signer( SoftwareSigner::new_with_sig_aux_data_provider( chain_config, account_index, + SoftwareWalletType::Hot, Box::new(PredefinedSigAuxDataProvider), ) } diff --git a/wallet/src/signer/trezor_signer/mod.rs b/wallet/src/signer/trezor_signer/mod.rs index 3783c8b03..d386bfd13 100644 --- a/wallet/src/signer/trezor_signer/mod.rs +++ b/wallet/src/signer/trezor_signer/mod.rs @@ -1789,8 +1789,17 @@ impl SignerProvider for TrezorSignerProvider { type S = TrezorSigner; type K = AccountKeyChainImplHardware; - fn provide(&mut self, chain_config: Arc, _account_index: U31) -> Self::S { - TrezorSigner::new(chain_config, self.client.clone(), self.session_id.clone()) + fn provide( + &mut self, + chain_config: Arc, + _account_index: U31, + _db_tx: &impl WalletStorageReadLocked, + ) -> WalletResult { + Ok(TrezorSigner::new( + chain_config, + self.client.clone(), + self.session_id.clone(), + )) } async fn make_new_account( diff --git a/wallet/src/signer/trezor_signer/tests.rs b/wallet/src/signer/trezor_signer/tests.rs index 111513cf2..ad0c763e5 100644 --- a/wallet/src/signer/trezor_signer/tests.rs +++ b/wallet/src/signer/trezor_signer/tests.rs @@ -110,17 +110,21 @@ async fn test_sign_transaction_intent(#[case] seed: Seed) { } #[rstest] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V0)] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V1)] +#[case(Seed::from_entropy(), true, SighashInputCommitmentVersion::V0)] +#[case(Seed::from_entropy(), false, SighashInputCommitmentVersion::V1)] #[trace] #[serial] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_sign_transaction( #[case] seed: Seed, - #[case] input_commitments_version: SighashInputCommitmentVersion, + #[case] before_fork: bool, + #[case] expected_input_commitments_version: SighashInputCommitmentVersion, ) { log::debug!( - "test_sign_transaction, seed = {seed:?}, input_commitments_version = {input_commitments_version:?}" + "test_sign_transaction, seed = {:?}, before_fork = {}, expected_input_commitments_version = {:?}", + seed, + before_fork, + expected_input_commitments_version ); let _join_guard = maybe_spawn_auto_confirmer(); @@ -129,7 +133,8 @@ async fn test_sign_transaction( test_sign_transaction_generic( &mut rng, - input_commitments_version, + before_fork, + expected_input_commitments_version, make_trezor_signer, no_another_signer(), true, @@ -256,17 +261,21 @@ async fn test_sign_transaction_intent_sig_consistency(#[case] seed: Seed) { } #[rstest] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V0)] -#[case(Seed::from_entropy(), SighashInputCommitmentVersion::V1)] +#[case(Seed::from_entropy(), true, SighashInputCommitmentVersion::V0)] +#[case(Seed::from_entropy(), false, SighashInputCommitmentVersion::V1)] #[trace] #[serial] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_sign_transaction_sig_consistency( #[case] seed: Seed, - #[case] input_commitments_version: SighashInputCommitmentVersion, + #[case] before_fork: bool, + #[case] expected_input_commitments_version: SighashInputCommitmentVersion, ) { log::debug!( - "test_sign_transaction_sig_consistency, seed = {seed:?}, input_commitments_version = {input_commitments_version:?}" + "test_sign_transaction_sig_consistency, seed = {:?}, before_fork = {}, expected_input_commitments_version = {:?}", + seed, + before_fork, + expected_input_commitments_version ); let _join_guard = maybe_spawn_auto_confirmer(); @@ -275,7 +284,8 @@ async fn test_sign_transaction_sig_consistency( test_sign_transaction_generic( &mut rng, - input_commitments_version, + before_fork, + expected_input_commitments_version, make_deterministic_trezor_signer, Some(make_deterministic_software_signer), true, diff --git a/wallet/src/wallet/mod.rs b/wallet/src/wallet/mod.rs index 7059051c2..2414b8253 100644 --- a/wallet/src/wallet/mod.rs +++ b/wallet/src/wallet/mod.rs @@ -1229,7 +1229,8 @@ where let account = Self::get_account_mut(&mut self.accounts, account_index)?; let mut db_tx = self.db.transaction_rw_unlocked(None)?; let result = create_request(account, &mut db_tx); - let signer = self.signer_provider.provide(self.chain_config.clone(), account_index); + let signer = + self.signer_provider.provide(self.chain_config.clone(), account_index, &db_tx)?; let config = self.chain_config.clone(); let result = sign_request(result, account.key_chain(), &mut db_tx, config, signer).await; diff --git a/wallet/src/wallet/test_helpers.rs b/wallet/src/wallet/test_helpers.rs index 59fd24a57..a8ce41bc7 100644 --- a/wallet/src/wallet/test_helpers.rs +++ b/wallet/src/wallet/test_helpers.rs @@ -25,7 +25,10 @@ use common::{ primitives::BlockHeight, }; use wallet_storage::{DefaultBackend, Store}; -use wallet_types::{seed_phrase::StoreSeedPhrase, wallet_type::WalletType}; +use wallet_types::{ + seed_phrase::StoreSeedPhrase, + wallet_type::{WalletControllerMode, WalletType}, +}; use crate::{ DefaultWallet, Wallet, @@ -38,28 +41,15 @@ pub async fn create_wallet_with_mnemonic( chain_config: Arc, mnemonic: &str, ) -> DefaultWallet { - let db = create_wallet_in_memory().unwrap(); - let genesis_block_id = chain_config.genesis_block_id(); - Wallet::create_new_wallet( - chain_config.clone(), - Default::default(), - db, - (BlockHeight::new(0), genesis_block_id), - WalletType::Hot, - async |db_tx| { - Ok(SoftwareSignerProvider::new_from_mnemonic( - chain_config, - db_tx, - mnemonic, - None, - StoreSeedPhrase::DoNotStore, - )?) - }, - ) - .await - .unwrap() - .wallet() - .unwrap() + create_wallet_with_type_and_mnemonic(chain_config, WalletType::Hot, mnemonic).await +} + +pub async fn create_wallet_with_type_and_mnemonic( + chain_config: Arc, + wallet_type: WalletType, + mnemonic: &str, +) -> DefaultWallet { + create_wallet_generic(chain_config, wallet_type, mnemonic, None).await } pub fn create_named_in_memory_backend(db_name: &str) -> DefaultBackend { @@ -75,14 +65,27 @@ pub async fn create_wallet_with_mnemonic_and_named_db( mnemonic: &str, db_name: &str, ) -> DefaultWallet { - let db = create_named_in_memory_store(db_name); + create_wallet_generic(chain_config, WalletType::Hot, mnemonic, Some(db_name)).await +} + +pub async fn create_wallet_generic( + chain_config: Arc, + wallet_type: WalletType, + mnemonic: &str, + db_name: Option<&str>, +) -> DefaultWallet { + let db = if let Some(db_name) = db_name { + create_named_in_memory_store(db_name) + } else { + create_wallet_in_memory().unwrap() + }; let genesis_block_id = chain_config.genesis_block_id(); Wallet::create_new_wallet( chain_config.clone(), Default::default(), db, (BlockHeight::new(0), genesis_block_id), - WalletType::Hot, + wallet_type, async |db_tx| { SoftwareSignerProvider::new_from_mnemonic( chain_config, @@ -100,6 +103,30 @@ pub async fn create_wallet_with_mnemonic_and_named_db( .unwrap() } +pub async fn load_wallet( + chain_config: Arc, + db_name: &str, + controller_mode: WalletControllerMode, + force_change_wallet_type: bool, +) -> DefaultWallet { + let db = create_named_in_memory_store(db_name); + + Wallet::load_wallet( + Arc::clone(&chain_config), + Default::default(), + db, + None, + |_| Ok(()), + controller_mode, + force_change_wallet_type, + async |db_tx| SoftwareSignerProvider::load_from_database(chain_config, &db_tx), + ) + .await + .unwrap() + .wallet() + .unwrap() +} + pub async fn scan_wallet(wallet: &mut Wallet, height: BlockHeight, blocks: Vec) where B: storage::BackendWithSendableTransactions + 'static, diff --git a/wallet/src/wallet/tests.rs b/wallet/src/wallet/tests.rs index b3f102ec0..c8d4b453b 100644 --- a/wallet/src/wallet/tests.rs +++ b/wallet/src/wallet/tests.rs @@ -24,8 +24,8 @@ use rstest::rstest; use common::{ address::pubkeyhash::PublicKeyHash, chain::{ - AccountNonce, AccountSpending, ChainstateUpgradeBuilder, Currency, Destination, Genesis, - OutPointSourceId, TxInput, + self, AccountNonce, AccountSpending, ChainstateUpgradeBuilder, Currency, Destination, + Genesis, NetUpgrades, OutPointSourceId, SighashInputCommitmentVersion, TxInput, block::{BlockReward, ConsensusData, consensus_data::PoSData, timestamp::BlockTimestamp}, config::{Builder, ChainType, create_mainnet, create_regtest, create_unit_test_config}, output_value::{OutputValue, RpcOutputValue}, @@ -43,7 +43,7 @@ use crypto::{ }, vrf::transcript::no_rng::VRFTranscript, }; -use randomness::{CryptoRng, Rng, RngExt as _, SliceRandom}; +use randomness::{CryptoRng, IndexedRandom as _, Rng, RngExt as _, SliceRandom as _}; use serialization::{Encode, extras::non_empty_vec::DataOrNoVec, hex::HexEncode}; use storage::raw::DbMapId; use test_utils::{ @@ -70,14 +70,20 @@ use crate::{ send_request::{make_address_output, make_create_delegation_output}, signer::software_signer::SoftwareSignerProvider, wallet::test_helpers::{ - create_named_in_memory_backend, create_named_in_memory_store, create_wallet_with_mnemonic, - create_wallet_with_mnemonic_and_named_db, scan_wallet, + create_named_in_memory_backend, create_named_in_memory_store, create_wallet_generic, + create_wallet_with_mnemonic, create_wallet_with_mnemonic_and_named_db, + create_wallet_with_type_and_mnemonic, load_wallet, scan_wallet, }, wallet_events::WalletEventsNoOp, }; use super::*; +#[ctor::ctor] +fn init() { + logging::init_logging(); +} + // TODO: Many of these tests require randomization... const MNEMONIC: &str = @@ -5520,7 +5526,12 @@ async fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { // create cold wallet that is not synced and only contains decommission key let another_mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"; - let mut cold_wallet = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic).await; + let mut cold_wallet = create_wallet_with_type_and_mnemonic( + chain_config.clone(), + *[WalletType::Hot, WalletType::Cold].choose(&mut rng).unwrap(), + another_mnemonic, + ) + .await; let decommission_key = cold_wallet.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; let coin_balance = get_coin_balance(&hot_wallet); @@ -5624,6 +5635,218 @@ async fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { assert_eq!(coin_balance, pool_amount,); } +// Check that signing a pool decommission tx from a cold wallet produces signatures using +// input commitments v1. +#[rstest] +#[case(Seed::from_entropy())] +#[trace] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_decommission_pool_request_in_cold_wallet_expect_input_commitments_v1( + #[case] seed: Seed, + #[values(false, true)] reload_as_cold: bool, +) { + let mut rng = make_seedable_rng(seed); + + let input_commitments_v1_fork_height = BlockHeight::new(4); + let chain_config = chain::config::Builder::new(ChainType::Regtest) + .chainstate_upgrades({ + NetUpgrades::initialize(vec![ + ( + BlockHeight::zero(), + ChainstateUpgradeBuilder::latest() + .sighash_input_commitment_version(SighashInputCommitmentVersion::V0) + .build(), + ), + ( + input_commitments_v1_fork_height, + ChainstateUpgradeBuilder::latest() + .sighash_input_commitment_version(SighashInputCommitmentVersion::V1) + .build(), + ), + ]) + .unwrap() + }) + .build(); + + let chain_config = Arc::new(chain_config); + + let mut hot_wallet = create_wallet(Arc::clone(&chain_config)).await; + + // Create a cold wallet. If reload_as_cold is true, first create a hot wallet and force-reload + // it as cold. Otherwise just create a cold wallet. + let another_mnemonic = + "legal winner thank year wave sausage worth useful legal winner thank yellow"; + let mut cold_wallet = if reload_as_cold { + let db_name = random_ascii_alphanumeric_string(&mut rng, 10..20); + let _tmp_wallet = create_wallet_generic( + Arc::clone(&chain_config), + WalletType::Hot, + another_mnemonic, + Some(&db_name), + ) + .await; + + load_wallet( + Arc::clone(&chain_config), + &db_name, + WalletControllerMode::Cold, + true, + ) + .await + } else { + create_wallet_generic( + Arc::clone(&chain_config), + WalletType::Cold, + another_mnemonic, + None, + ) + .await + }; + let decommission_key = + cold_wallet.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1.into_object(); + + let coin_balance = get_coin_balance(&hot_wallet); + assert_eq!(coin_balance, Amount::ZERO); + + // Generate a new block which sends reward to the wallet + let block1_amount = + Amount::from_atoms(rng.random_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); + let (_, _block1) = create_block(&chain_config, &mut hot_wallet, vec![], block1_amount, 0).await; + + let pool_ids = hot_wallet.get_pools(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); + assert!(pool_ids.is_empty()); + + let coin_balance = get_coin_balance(&hot_wallet); + assert_eq!(coin_balance, block1_amount); + + let pool_amount = block1_amount; + + let res = hot_wallet.create_next_account(Some("name".into())).await.unwrap(); + assert_eq!(res, (U31::from_u32(1).unwrap(), Some("name".into()))); + + let pool_creation_tx = hot_wallet + .create_stake_pool( + DEFAULT_ACCOUNT_INDEX, + FeeRate::from_amount_per_kb(Amount::ZERO), + FeeRate::from_amount_per_kb(Amount::ZERO), + StakePoolCreationArguments { + amount: pool_amount, + margin_ratio_per_thousand: PerThousand::new_from_rng(&mut rng), + cost_per_block: Amount::ZERO, + decommission_key: decommission_key.clone(), + staker_key: None, + vrf_public_key: None, + }, + ) + .await + .unwrap() + .tx; + let pool_creation_tx_id = pool_creation_tx.transaction().get_id(); + let (_, _block2) = create_block( + &chain_config, + &mut hot_wallet, + vec![pool_creation_tx], + Amount::ZERO, + 1, + ) + .await; + + let pool_ids = hot_wallet.get_pools(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); + assert_eq!(pool_ids.len(), 1); + let pool_id = pool_ids.first().unwrap().0; + + let pos_data = hot_wallet.get_pos_gen_block_data(DEFAULT_ACCOUNT_INDEX, pool_id).unwrap(); + let staker_key = Destination::PublicKey(pos_data.stake_public_key()); + + // Create a block using the pool that will be decommissioned, so that the utxo consumed + // during decommissioning is ProduceBlockFromStake (because it's one of the utxos for which + // input commitments v0 and v1 are different). + let block3 = Block::new( + vec![], + chain_config.genesis_block_id(), + chain_config.genesis_block().timestamp(), + ConsensusData::PoS(Box::new(PoSData::new( + vec![TxInput::Utxo(UtxoOutPoint::new( + OutPointSourceId::Transaction(pool_creation_tx_id), + 0, + ))], + vec![], + pool_id, + pos_data.vrf_private_key().produce_vrf_data(VRFTranscript::new(&[])), + common::primitives::Compact(0), + ))), + BlockReward::new(vec![TxOutput::ProduceBlockFromStake(staker_key, pool_id)]), + ) + .unwrap(); + + scan_wallet(&mut hot_wallet, BlockHeight::new(2), vec![block3]).await; + + let pool_decommission_ptx = hot_wallet + .decommission_stake_pool_request( + DEFAULT_ACCOUNT_INDEX, + pool_id, + pool_amount, + None, + FeeRate::from_amount_per_kb(Amount::from_atoms(0)), + ) + .await + .unwrap(); + + // Sanity check: the consumed utxo is ProduceBlockFromStake. + assert_eq!(pool_decommission_ptx.input_utxos().len(), 1); + let pool_decommission_utxo = pool_decommission_ptx.input_utxos()[0].clone().unwrap(); + assert_matches!( + &pool_decommission_utxo, + TxOutput::ProduceBlockFromStake(_, _) + ); + + let expected_input_commitments = pool_decommission_ptx + .make_sighash_input_commitments_at_height(&chain_config, input_commitments_v1_fork_height) + .unwrap(); + let v0_input_commitments = pool_decommission_ptx + .make_sighash_input_commitments_at_height(&chain_config, BlockHeight::zero()) + .unwrap(); + // Sanity check + assert_ne!(expected_input_commitments, v0_input_commitments); + + // Sign the tx with cold wallet + let pool_decommission_ptx_after_signing = cold_wallet + .sign_raw_transaction( + DEFAULT_ACCOUNT_INDEX, + pool_decommission_ptx.clone(), + &TokensAdditionalInfo::new(), + ) + .await + .unwrap() + .0; + assert!(pool_decommission_ptx_after_signing.all_signatures_available()); + + let pool_decommission_signed_tx = pool_decommission_ptx_after_signing.into_signed_tx().unwrap(); + + // Verify the signature using v1 input commitments. + tx_verifier::input_check::signature_only_check::verify_tx_signature( + &chain_config, + &decommission_key, + &pool_decommission_signed_tx, + &expected_input_commitments, + 0, + Some(pool_decommission_utxo), + ) + .unwrap(); + + let (_, _block4) = create_block( + &chain_config, + &mut hot_wallet, + vec![pool_decommission_signed_tx], + Amount::ZERO, + 2, + ) + .await; + + let coin_balance = get_coin_balance(&hot_wallet); + assert_eq!(coin_balance, pool_amount); +} + #[rstest] #[trace] #[case(Seed::from_entropy())] @@ -5731,7 +5954,12 @@ async fn sign_send_request_cold_wallet(#[case] seed: Seed) { // create cold wallet that is not synced let another_mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"; - let mut cold_wallet = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic).await; + let mut cold_wallet = create_wallet_with_type_and_mnemonic( + chain_config.clone(), + *[WalletType::Hot, WalletType::Cold].choose(&mut rng).unwrap(), + another_mnemonic, + ) + .await; let cold_wallet_address = cold_wallet.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; let coin_balance = get_coin_balance(&hot_wallet); diff --git a/wallet/types/src/wallet_type.rs b/wallet/types/src/wallet_type.rs index d46fda23b..5203b2b1b 100644 --- a/wallet/types/src/wallet_type.rs +++ b/wallet/types/src/wallet_type.rs @@ -30,6 +30,27 @@ pub enum WalletType { Ledger, } +impl WalletType { + pub fn to_software_wallet_type(self) -> Option { + match self { + WalletType::Cold => Some(SoftwareWalletType::Cold), + WalletType::Hot => Some(SoftwareWalletType::Hot), + #[cfg(feature = "trezor")] + WalletType::Trezor => None, + #[cfg(feature = "ledger")] + WalletType::Ledger => None, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum SoftwareWalletType { + Cold, + Hot, +} + +// Note: this is conceptually different from SoftwareWalletType, because here "Hot" includes +// hardware wallets as well. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum WalletControllerMode { Cold, diff --git a/wallet/wallet-controller/src/lib.rs b/wallet/wallet-controller/src/lib.rs index cfc0208af..ddf536225 100644 --- a/wallet/wallet-controller/src/lib.rs +++ b/wallet/wallet-controller/src/lib.rs @@ -231,6 +231,7 @@ pub struct Controller { rpc_client: T, wallet: RuntimeWallet, + wallet_mode: WalletControllerMode, staking_started: BTreeSet, @@ -260,23 +261,20 @@ where wallet: RuntimeWallet, wallet_events: W, ) -> Result> { - let mempool_events = rpc_client - .mempool_subscribe_to_events() - .await - .map_err(ControllerError::NodeCallError)?; - let mut controller = Self { - chain_config, - rpc_client, - wallet, - staking_started: BTreeSet::new(), - wallet_events, - mempool_events, - finished_initial_sync: SetFlag::new(), + let mut controller = + Self::new_unsynced(chain_config, rpc_client, wallet, wallet_events).await?; + + // In the cold mode, try_sync_once is a no-op, so it doesn't matter whether we call it. + // We omit the call to avoid printing the "Syncing the wallet" log line, which looks + // confusing in the cold mode. + match controller.wallet_mode { + WalletControllerMode::Cold => {} + WalletControllerMode::Hot => { + log::info!("Syncing the wallet..."); + controller.try_sync_once().await?; + } }; - log::info!("Syncing the wallet..."); - controller.try_sync_once().await?; - Ok(controller) } @@ -286,14 +284,18 @@ where wallet: RuntimeWallet, wallet_events: W, ) -> Result> { + let wallet_mode = rpc_client.is_cold_wallet_node().await; + let mempool_events = rpc_client .mempool_subscribe_to_events() .await .map_err(ControllerError::NodeCallError)?; + Ok(Self { chain_config, rpc_client, wallet, + wallet_mode, staking_started: BTreeSet::new(), wallet_events, mempool_events, @@ -1565,26 +1567,33 @@ where } } - // after the first successful sync to the tip fetch all mempool transactions - if !self.finished_initial_sync.test() { - let txs = self.rpc_client.mempool_get_transactions().await; - - match txs { - Ok(txs) => { - if let Err(err) = - self.wallet.add_mempool_transactions(&txs, &self.wallet_events) - { - log::error!("Error adding mempool transactions: {err}"); - } else { - self.finished_initial_sync.set(); + match self.wallet_mode { + WalletControllerMode::Hot => { + // after the first successful sync to the tip fetch all mempool transactions + if !self.finished_initial_sync.test() { + let txs = self.rpc_client.mempool_get_transactions().await; + + match txs { + Ok(txs) => { + if let Err(err) = + self.wallet.add_mempool_transactions(&txs, &self.wallet_events) + { + log::error!("Error adding mempool transactions: {err}"); + } else { + self.finished_initial_sync.set(); + } + } + Err(err) => { + log::error!( + "Failed to fetch all transactions from the mempool: {err}" + ); + tokio::time::sleep(ERROR_DELAY).await; + continue; + } } } - Err(err) => { - log::error!("Failed to fetch all transactions from the mempool: {err}"); - tokio::time::sleep(ERROR_DELAY).await; - continue; - } } + WalletControllerMode::Cold => {} } let mut delay = Box::pin(tokio::time::sleep(NORMAL_DELAY)); @@ -1599,7 +1608,7 @@ where let event = match maybe_event { Some(e) => e, None => { - log::error!("Mempool notifications channel is closed."); + log::error!("Mempool notifications channel is closed"); tokio::time::sleep(ERROR_DELAY).await; match self.rpc_client @@ -1609,7 +1618,7 @@ where self.mempool_events = events; } Err(err) => { - log::error!("Subscribing to mempool notifications failed with: {err}"); + log::error!("Re-subscribing to mempool notifications failed: {err}"); } } break @@ -1626,14 +1635,14 @@ where Ok(Some(transaction)) => { let txs = [transaction]; if let Err(err) = self.wallet.add_mempool_transactions(&txs, &self.wallet_events) { - log::error!("Tx {} failed to be added in the wallet because of an error: {err}", tx_id); + log::error!("Error adding mempool transaction {tx_id:x} to the wallet: {err}"); } } Ok(None) => { - log::warn!("Tx {} announced by mempool, but not found when fetched", tx_id); + log::warn!("Transaction {tx_id:x} announced by mempool, but not found when fetched"); } Err(err) => { - log::error!("Error while fetching a transaction from mempool {err}"); + log::error!("Error fetching transaction {tx_id:x} from mempool: {err}"); } } } @@ -1641,7 +1650,17 @@ where } } } - self.rebroadcast_txs(&mut rebroadcast_txs_timer).await; + + // Note: normally a wallet in the cold mode will not have any transactions to broadcast. However, if it was + // force-converted from a hot wallet, it may have such transactions, in which case `rebroadcast_txs` will + // repeatedly print the warning "Rebroadcasting ... failed: Method is not available in cold wallet mode". + // So we avoid calling `rebroadcast_txs` in the cold mode. + match self.wallet_mode { + WalletControllerMode::Cold => {} + WalletControllerMode::Hot => { + self.rebroadcast_txs(&mut rebroadcast_txs_timer).await; + } + } } } @@ -1658,7 +1677,7 @@ where let tx_id = tx.transaction().get_id(); let res = self.rpc_client.submit_transaction(tx, Default::default()).await; if let Err(e) = res { - log::warn!("Rebroadcasting for tx {tx_id} failed: {e}"); + log::warn!("Rebroadcasting tx {tx_id:x} failed: {e}"); } } } diff --git a/wallet/wallet-controller/src/tests/compose_transaction_tests.rs b/wallet/wallet-controller/src/tests/compose_transaction_tests.rs index 5abaaeab4..af6a57040 100644 --- a/wallet/wallet-controller/src/tests/compose_transaction_tests.rs +++ b/wallet/wallet-controller/src/tests/compose_transaction_tests.rs @@ -45,7 +45,9 @@ use wallet::{ account::TransactionToSign, wallet::test_helpers::create_wallet_with_mnemonic, wallet_events::WalletEventsNoOp, }; -use wallet_types::partially_signed_transaction::PtxAdditionalInfo; +use wallet_types::{ + partially_signed_transaction::PtxAdditionalInfo, wallet_type::WalletControllerMode, +}; use crate::{ Controller, @@ -175,6 +177,8 @@ async fn general_test(#[case] seed: Seed, #[case] use_htlc_secret: bool) { is_initial_block_download: false, }; + node_mock.expect_is_cold_wallet_node().returning(|| WalletControllerMode::Hot); + node_mock .expect_get_utxo() .returning(move |outpoint| Ok(Some(utxos_to_return.get(&outpoint).unwrap().clone()))); diff --git a/wallet/wallet-node-client/src/node_traits.rs b/wallet/wallet-node-client/src/node_traits.rs index 2b4cb4739..fa7e77c2e 100644 --- a/wallet/wallet-node-client/src/node_traits.rs +++ b/wallet/wallet-node-client/src/node_traits.rs @@ -67,6 +67,7 @@ impl NodeInterfaceError for MockNodeInterfaceError { pub trait NodeInterface { type Error: NodeInterfaceError; + // TODO: rename this, e.g. to wallet_mode. async fn is_cold_wallet_node(&self) -> WalletControllerMode; async fn chainstate_info(&self) -> Result; diff --git a/wallet/wallet-node-client/src/rpc_client/cold_wallet_client.rs b/wallet/wallet-node-client/src/rpc_client/cold_wallet_client.rs index 2a90442eb..33a74b015 100644 --- a/wallet/wallet-node-client/src/rpc_client/cold_wallet_client.rs +++ b/wallet/wallet-node-client/src/rpc_client/cold_wallet_client.rs @@ -299,7 +299,7 @@ impl NodeInterface for ColdWalletClient { } async fn mempool_subscribe_to_events(&self) -> Result { - Ok(Box::new(futures::stream::empty())) + Ok(Box::new(futures::stream::pending())) } async fn mempool_get_transaction( diff --git a/wallet/wallet-rpc-daemon/docs/RPC.md b/wallet/wallet-rpc-daemon/docs/RPC.md index cc669a58d..f350ef0a6 100644 --- a/wallet/wallet-rpc-daemon/docs/RPC.md +++ b/wallet/wallet-rpc-daemon/docs/RPC.md @@ -1,6 +1,6 @@ # RPC documentation for Mintlayer node wallet -Version `1.3.0`. +Version `1.3.1`. ## Module `WalletRpc` diff --git a/wasm-wrappers/CHANGELOG.md b/wasm-wrappers/CHANGELOG.md index a6df92611..0cd012fc8 100644 --- a/wasm-wrappers/CHANGELOG.md +++ b/wasm-wrappers/CHANGELOG.md @@ -6,6 +6,10 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/ ## [Unreleased] +## [1.3.1] - 2026-06-03 + +No changes + ## [1.3.0] - 2026-04-09 ### Added