V2.6.7 beta (#11337)
* Enable EIP-2384 for ice age hard fork (#11281) * ethcore/res: activate agharta on classic 9573000 (#11331) * Istanbul HF in xDai (2019-12-12) (#11299) * Istanbul HF in POA Core (2019-12-19) (#11298) * Istanbul HF in POA Sokol (2019-12-05) (#11282) * Activate ecip-1061 on kotti and mordor (#11338) * Enable basic verification of local transactions (#11332) * Disallow EIP-86 style null signatures for transactions outside tests (#11335) * SecretStore database migration to v4 (#11322)
This commit is contained in:
parent
5162bc2c88
commit
ba1b879e9f
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,3 +1,20 @@
|
||||
## Parity-Ethereum [v2.6.7](https://github.com/paritytech/parity-ethereum/releases/tag/v2.6.7)
|
||||
|
||||
Parity Ethereum v2.6.7-beta is a patch release that adds Istanbul hardfork
|
||||
block numbers for POA and xDai networks, implements ECIP-1056 and implements
|
||||
EIP-2384/2387 - Muir Glacier.
|
||||
|
||||
The full list of included changes:
|
||||
* Enable EIP-2384 for ice age hard fork (#11281)
|
||||
* ethcore/res: activate agharta on classic 9573000 (#11331)
|
||||
* Istanbul HF in xDai (2019-12-12) (#11299)
|
||||
* Istanbul HF in POA Core (2019-12-19) (#11298)
|
||||
* Istanbul HF in POA Sokol (2019-12-05) (#11282)
|
||||
* Activate ecip-1061 on kotti and mordor (#11338)
|
||||
* Enable basic verification of local transactions (#11332)
|
||||
* Disallow EIP-86 style null signatures for transactions outside tests (#11335)
|
||||
* SecretStore database migration to v4 (#11322)
|
||||
|
||||
## Parity-Ethereum [v2.6.6](https://github.com/paritytech/parity-ethereum/releases/tag/v2.6.6)
|
||||
|
||||
Parity Ethereum v2.6.6-beta is an emergency patch release that adds the missing
|
||||
|
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -2626,7 +2626,7 @@ dependencies = [
|
||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jni 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"panic_hook 0.1.0",
|
||||
"parity-ethereum 2.6.6",
|
||||
"parity-ethereum 2.6.7",
|
||||
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -2673,7 +2673,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-ethereum"
|
||||
version = "2.6.6"
|
||||
version = "2.6.7"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2726,7 +2726,7 @@ dependencies = [
|
||||
"parity-runtime 0.1.0",
|
||||
"parity-updater 1.12.0",
|
||||
"parity-util-mem 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-version 2.6.6",
|
||||
"parity-version 2.6.7",
|
||||
"parity-whisper 0.1.0",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2869,7 +2869,7 @@ dependencies = [
|
||||
"parity-crypto 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-runtime 0.1.0",
|
||||
"parity-updater 1.12.0",
|
||||
"parity-version 2.6.6",
|
||||
"parity-version 2.6.7",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2968,7 +2968,7 @@ dependencies = [
|
||||
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-hash-fetch 1.12.0",
|
||||
"parity-path 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-version 2.6.6",
|
||||
"parity-version 2.6.7",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2993,7 +2993,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-version"
|
||||
version = "2.6.6"
|
||||
version = "2.6.7"
|
||||
dependencies = [
|
||||
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rlp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2,7 +2,7 @@
|
||||
description = "Parity Ethereum client"
|
||||
name = "parity-ethereum"
|
||||
# NOTE Make sure to update util/version/Cargo.toml as well
|
||||
version = "2.6.6"
|
||||
version = "2.6.7"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
|
@ -76,6 +76,7 @@ rand_xorshift = "0.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
blooms-db = { path = "../util/blooms-db" }
|
||||
common-types = { path = "types", features = ["test-helpers"] }
|
||||
criterion = "0.3"
|
||||
env_logger = "0.5"
|
||||
ethcore-accounts = { path = "../accounts" }
|
||||
|
@ -37,7 +37,10 @@
|
||||
"eip140Transition": "0x85d9a0",
|
||||
"eip211Transition": "0x85d9a0",
|
||||
"eip214Transition": "0x85d9a0",
|
||||
"eip658Transition": "0x85d9a0"
|
||||
"eip658Transition": "0x85d9a0",
|
||||
"eip145Transition": "0x921288",
|
||||
"eip1014Transition": "0x921288",
|
||||
"eip1052Transition": "0x921288"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -136,7 +136,8 @@
|
||||
"eip100bTransition": "0x42ae50",
|
||||
"difficultyBombDelays": {
|
||||
"0x42ae50": "0x2dc6c0",
|
||||
"0x6f1580": "0x1e8480"
|
||||
"0x6f1580": "0x1e8480",
|
||||
"0x8c6180": "0x3d0900"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,10 @@
|
||||
"eip658Transition": "0xaef49",
|
||||
"eip1014Transition": "0x1a064d",
|
||||
"eip1052Transition": "0x1a064d",
|
||||
"eip1283Transition": "0x1f67cf",
|
||||
"eip1344Transition": "0x1f67cf",
|
||||
"eip1706Transition": "0x1f67cf",
|
||||
"eip2028Transition": "0x1f67cf",
|
||||
"gasLimitBoundDivisor": "0x400",
|
||||
"maxCodeSize": "0x6000",
|
||||
"maxCodeSizeTransition": "0xaef49",
|
||||
@ -123,7 +127,7 @@
|
||||
"0xaef49": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 500 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"0x1f67cf": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 150 }}
|
||||
}
|
||||
@ -138,7 +142,7 @@
|
||||
"0xaef49": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 40000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"0x1f67cf": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 6000 }}
|
||||
}
|
||||
@ -153,7 +157,7 @@
|
||||
"0xaef49": {
|
||||
"price": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"0x1f67cf": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_pairing": { "base": 45000, "pair": 34000 }}
|
||||
}
|
||||
@ -161,7 +165,16 @@
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"balance": "0x1"
|
||||
"balance": "0x1",
|
||||
"builtin": {
|
||||
"name": "blake2_f",
|
||||
"activate_at": "0x1f67cf",
|
||||
"pricing": {
|
||||
"blake2_f": {
|
||||
"gas_per_round": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x000000000000000000000000000000000000000a": {
|
||||
"balance": "0x1"
|
||||
|
@ -37,7 +37,11 @@
|
||||
"eip658Transition":"0x0",
|
||||
"eip145Transition":"0x498bb",
|
||||
"eip1014Transition":"0x498bb",
|
||||
"eip1052Transition":"0x498bb"
|
||||
"eip1052Transition":"0x498bb",
|
||||
"eip1283Transition":"0xbe10b",
|
||||
"eip1344Transition":"0xbe10b",
|
||||
"eip1706Transition":"0xbe10b",
|
||||
"eip2028Transition":"0xbe10b"
|
||||
},
|
||||
"genesis":{
|
||||
"seal":{
|
||||
@ -59,7 +63,9 @@
|
||||
"enode://1813e90a0afdd7c1e4892c5376960e3577a9e6c5a4f86fa405a405c7421a4a1608248d77cc90333842f13d8954d82113dec480cfb76b4fef8cb475157cf4d5f2@10.28.224.3:30000",
|
||||
"enode://2b69a3926f36a7748c9021c34050be5e0b64346225e477fe7377070f6289bd363b2be73a06010fd516e6ea3ee90778dd0399bc007bb1281923a79374f842675a@51.15.116.226:30303",
|
||||
"enode://621e28e529146fd501709194885f50540c494f1a2985d1fb4ec8769226b5cb0b0d1a11545926077821474c2767cdd87888ead8a2509a2c9069dd5584e4b1c3b8@10.28.223.8:30000",
|
||||
"enode://a59e33ccd2b3e52d578f1fbd70c6f9babda2650f0760d6ff3b37742fdcdfdb3defba5d56d315b40c46b70198c7621e63ffa3f987389c7118634b0fefbbdfa7fd@51.15.116.226:30303"
|
||||
"enode://a59e33ccd2b3e52d578f1fbd70c6f9babda2650f0760d6ff3b37742fdcdfdb3defba5d56d315b40c46b70198c7621e63ffa3f987389c7118634b0fefbbdfa7fd@51.15.116.226:30303",
|
||||
"enode://f840b007500f50c98ea6f9c9e56dabf4690bbbbb7036d43682c531204341aff8315013547e5bee54117eb22bd3603585ae6bf713d9fa710659533fcab65d5b84@35.238.101.58:30000",
|
||||
"enode://19eda672030ad5debb98c9069b3e99d12438b96506325d9f3f82d76c5f8ce4942d345f41700a5223900e75ad48e76713b74c1b694d67a10c2112540035922256@35.238.101.58:30000"
|
||||
],
|
||||
"accounts":{
|
||||
"0x0000000000000000000000000000000000000001":{
|
||||
@ -128,7 +134,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x7fffffffffffff":{
|
||||
"0xbe10b":{
|
||||
"info":"EIP 1108 transition",
|
||||
"price":{
|
||||
"alt_bn128_const_operations":{
|
||||
@ -150,7 +156,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x7fffffffffffff":{
|
||||
"0xbe10b":{
|
||||
"info":"EIP 1108 transition",
|
||||
"price":{
|
||||
"alt_bn128_const_operations":{
|
||||
@ -173,7 +179,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x7fffffffffffff":{
|
||||
"0xbe10b":{
|
||||
"info":"EIP 1108 transition",
|
||||
"price":{
|
||||
"alt_bn128_pairing":{
|
||||
@ -184,6 +190,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"builtin": {
|
||||
"name": "blake2_f",
|
||||
"activate_at": "0xbe10b",
|
||||
"pricing": {
|
||||
"blake2_f": {
|
||||
"gas_per_round": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,12 @@
|
||||
"eip658Transition": "0x0",
|
||||
"eip145Transition": 8582254,
|
||||
"eip1014Transition": 8582254,
|
||||
"eip1052Transition": 8582254
|
||||
"eip1052Transition": 8582254,
|
||||
"eip1283Transition": 12598600,
|
||||
"eip1344Transition": 12598600,
|
||||
"eip1706Transition": 12598600,
|
||||
"eip1884Transition": 12598600,
|
||||
"eip2028Transition": 12598600
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@ -5406,57 +5411,89 @@
|
||||
"enode://96678da10ac83769ab3f63114a41b57b700476c5ac02719b878fa89909a936551bb7609aa09b068bf89903206fa03f23e1b5b9117ca278de304c2570b87dcb27@35.175.15.164:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x0", "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0000000000000000000000000000000000000006": {
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"pricing": {
|
||||
"0": {
|
||||
"price": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000006": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_add",
|
||||
"pricing": {
|
||||
"0": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 500 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"12598600": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 150 }}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0000000000000000000000000000000000000007": {
|
||||
"0x0000000000000000000000000000000000000007": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_mul",
|
||||
"pricing": {
|
||||
"0": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 40000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"12598600": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 6000 }}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0000000000000000000000000000000000000008": {
|
||||
"0x0000000000000000000000000000000000000008": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_pairing",
|
||||
"pricing": {
|
||||
"0": {
|
||||
"price": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"12598600": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_pairing": { "base": 45000, "pair": 34000 }}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"builtin": {
|
||||
"name": "blake2_f",
|
||||
"pricing": {
|
||||
"12598600": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": {
|
||||
"blake2_f": {
|
||||
"gas_per_round": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"balance": "1",
|
||||
"builtin": {
|
||||
"name": "ecrecover",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5466,9 +5503,13 @@
|
||||
"builtin": {
|
||||
"name": "sha256",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5478,9 +5519,13 @@
|
||||
"builtin": {
|
||||
"name": "ripemd160",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5490,9 +5535,13 @@
|
||||
"builtin": {
|
||||
"name": "identity",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,12 @@
|
||||
"eip1014Transition": 6464300,
|
||||
"eip1052Transition": 6464300,
|
||||
"eip1283Transition": 6464300,
|
||||
"eip1283DisableTransition": 7026400
|
||||
"eip1283DisableTransition": 7026400,
|
||||
"eip1283ReenableTransition": 12095200,
|
||||
"eip1344Transition": 12095200,
|
||||
"eip1706Transition": 12095200,
|
||||
"eip1884Transition": 12095200,
|
||||
"eip2028Transition": 12095200
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
@ -5303,6 +5308,7 @@
|
||||
]
|
||||
},
|
||||
"nodes": [
|
||||
"enode://bdcd6f875583df2bd8094f08ae58c7c2db6ed67795ca8c0e6415a30721d3657291aec9b933d15e17e0b36ad7a76424a1447ddbfc75809a04f7a0ffef5617dd56@3.91.206.172:30303",
|
||||
"enode://8e0af07c86ec36590bb6368e7ad0c45b6dc658f5fb66ec68889a614affddda5e021bd513bcf4fb2fae4a3bbe08cf0de84f037cd58478a89665dfce1ded2595c7@34.236.37.74:30303",
|
||||
"enode://f1a5100a81cb73163ae450c584d06b1f644aa4fad4486c6aeb4c384b343c54bb66c744aa5f133af66ea1b25f0f4a454f04878f3e96ee4cd2390c047396d6357b@209.97.158.4:30303",
|
||||
"enode://0d1e0372f63a3f0b82d66635ea101ecc0f6797788a078805cc933dd93e6a22f7c9fa51ab4e2d21da02d04480ef19f3bbb9a2b41dd1c262085d295a354bb8b0f9@18.217.47.209:30303",
|
||||
@ -5312,7 +5318,20 @@
|
||||
"enode://b022ff70b5fcaf9596ae5efed99a8198b4ae0578ee9d17b733609d803a75cef95d3a2a18e50dca9a7c3b26139f158c59eaf8b5fb8d1d331c9a46934a78acabe8@206.189.76.128:30303"
|
||||
],
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": "0x0", "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0000000000000000000000000000000000000005": {
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"pricing": {
|
||||
"0": {
|
||||
"price": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0000000000000000000000000000000000000006": {
|
||||
"builtin": {
|
||||
"name": "alt_bn128_add",
|
||||
@ -5320,7 +5339,7 @@
|
||||
"0": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 500 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"12095200": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 150 }}
|
||||
}
|
||||
@ -5334,7 +5353,7 @@
|
||||
"0": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 40000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"12095200": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 6000 }}
|
||||
}
|
||||
@ -5348,21 +5367,40 @@
|
||||
"0": {
|
||||
"price": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"12095200": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_pairing": { "base": 45000, "pair": 34000 }}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"builtin": {
|
||||
"name": "blake2_f",
|
||||
"pricing": {
|
||||
"12095200": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": {
|
||||
"blake2_f": {
|
||||
"gas_per_round": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"balance": "1",
|
||||
"builtin": {
|
||||
"name": "ecrecover",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5372,9 +5410,13 @@
|
||||
"builtin": {
|
||||
"name": "sha256",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5384,9 +5426,13 @@
|
||||
"builtin": {
|
||||
"name": "ripemd160",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5396,9 +5442,13 @@
|
||||
"builtin": {
|
||||
"name": "identity",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,8 @@
|
||||
"eip100bTransition": "0x19f0a0",
|
||||
"difficultyBombDelays": {
|
||||
"0x19f0a0": "0x2dc6c0",
|
||||
"0x408b70": "0x1e8480"
|
||||
"0x408b70": "0x1e8480",
|
||||
"0x6c993d": "0x3d0900"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,11 @@
|
||||
"eip1052Transition": 1604400,
|
||||
"eip1283Transition": 1604400,
|
||||
"eip1283DisableTransition": 2508800,
|
||||
"eip1283ReenableTransition": 7298030,
|
||||
"eip1344Transition": 7298030,
|
||||
"eip1706Transition": 7298030,
|
||||
"eip1884Transition": 7298030,
|
||||
"eip2028Transition": 7298030,
|
||||
"registrar": "0x1ec97dc137f5168af053c24460a1200502e1a9d2"
|
||||
},
|
||||
"genesis": {
|
||||
@ -2865,10 +2870,13 @@
|
||||
"0x0000000000000000000000000000000000000005": {
|
||||
"builtin": {
|
||||
"name": "modexp",
|
||||
"activate_at": "0x0",
|
||||
"pricing": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
"0": {
|
||||
"price": {
|
||||
"modexp": {
|
||||
"divisor": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2880,7 +2888,7 @@
|
||||
"0": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 500 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"7298030": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 150 }}
|
||||
}
|
||||
@ -2894,7 +2902,7 @@
|
||||
"0": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 40000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"7298030": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_const_operations": { "price": 6000 }}
|
||||
}
|
||||
@ -2908,21 +2916,40 @@
|
||||
"0": {
|
||||
"price": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 }}
|
||||
},
|
||||
"0x7fffffffffffff": {
|
||||
"7298030": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": { "alt_bn128_pairing": { "base": 45000, "pair": 34000 }}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000009": {
|
||||
"builtin": {
|
||||
"name": "blake2_f",
|
||||
"pricing": {
|
||||
"7298030": {
|
||||
"info": "EIP 1108 transition",
|
||||
"price": {
|
||||
"blake2_f": {
|
||||
"gas_per_round": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"balance": "1",
|
||||
"builtin": {
|
||||
"name": "ecrecover",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 3000,
|
||||
"word": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2932,9 +2959,13 @@
|
||||
"builtin": {
|
||||
"name": "sha256",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 60,
|
||||
"word": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2944,9 +2975,13 @@
|
||||
"builtin": {
|
||||
"name": "ripemd160",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 600,
|
||||
"word": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2956,9 +2991,13 @@
|
||||
"builtin": {
|
||||
"name": "identity",
|
||||
"pricing": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
"0": {
|
||||
"price": {
|
||||
"linear": {
|
||||
"base": 15,
|
||||
"word": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ impl<'a> EvmTestClient<'a> {
|
||||
) -> std::result::Result<TransactSuccess<T::Output, V::Output>, TransactErr> {
|
||||
let initial_gas = transaction.gas;
|
||||
// Verify transaction
|
||||
let is_ok = transaction.verify_basic(true, None, false);
|
||||
let is_ok = transaction.verify_basic(true, None);
|
||||
if let Err(error) = is_ok {
|
||||
return Err(
|
||||
TransactErr{
|
||||
|
@ -367,7 +367,7 @@ impl Machine {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
t.verify_basic(check_low_s, chain_id, false)?;
|
||||
t.verify_basic(check_low_s, chain_id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1709,6 +1709,30 @@ mod tests {
|
||||
assert_eq!(miner.prepare_pending_block(&client), BlockPreparationStatus::NotPrepared);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_reject_local_transaction_with_invalid_chain_id() {
|
||||
let spec = Spec::new_test();
|
||||
let miner = Miner::new_for_tests(&spec, None);
|
||||
let client = TestBlockChainClient::default();
|
||||
let chain_id = spec.chain_id();
|
||||
|
||||
// chain_id + 100500 is invalid
|
||||
let import = miner.import_claimed_local_transaction(
|
||||
&client,
|
||||
PendingTransaction::new(transaction_with_chain_id(chain_id + 10500), None),
|
||||
false,
|
||||
);
|
||||
assert_eq!(import, Err(transaction::Error::InvalidChainId));
|
||||
|
||||
// chain_id is valid
|
||||
let import = miner.import_claimed_local_transaction(
|
||||
&client,
|
||||
PendingTransaction::new(transaction_with_chain_id(chain_id), None),
|
||||
false,
|
||||
);
|
||||
assert_eq!(import, Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_prioritize_locals() {
|
||||
let client = TestBlockChainClient::default();
|
||||
|
@ -136,7 +136,12 @@ impl<'a, C: 'a> pool::client::Client for PoolClient<'a, C> where
|
||||
self.chain.transaction_block(TransactionId::Hash(*hash)).is_some()
|
||||
}
|
||||
|
||||
fn verify_transaction(&self, tx: UnverifiedTransaction)-> Result<SignedTransaction, transaction::Error> {
|
||||
fn verify_transaction_basic(&self, tx: &UnverifiedTransaction) -> Result<(), transaction::Error> {
|
||||
self.engine.verify_transaction_basic(tx, &self.best_block_header)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_transaction(&self, tx: UnverifiedTransaction) -> Result<SignedTransaction, transaction::Error> {
|
||||
self.engine.verify_transaction_basic(&tx, &self.best_block_header)?;
|
||||
let tx = self.engine.verify_transaction_unordered(tx, &self.best_block_header)?;
|
||||
|
||||
|
@ -138,6 +138,7 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
impl From<ethjson::transaction::Transaction> for SignedTransaction {
|
||||
fn from(t: ethjson::transaction::Transaction) -> Self {
|
||||
let to: Option<ethjson::hash::Address> = t.to.into();
|
||||
@ -237,7 +238,10 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Add EIP-86 compatible empty signature.
|
||||
/// Legacy EIP-86 compatible empty signature.
|
||||
/// This method is used in json tests as well as
|
||||
/// signature verification tests.
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
pub fn null_sign(self, chain_id: u64) -> SignedTransaction {
|
||||
SignedTransaction {
|
||||
transaction: UnverifiedTransaction {
|
||||
@ -295,7 +299,7 @@ impl rlp::Decodable for UnverifiedTransaction {
|
||||
v: d.val_at(6)?,
|
||||
r: d.val_at(7)?,
|
||||
s: d.val_at(8)?,
|
||||
hash: hash,
|
||||
hash,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -312,7 +316,7 @@ impl UnverifiedTransaction {
|
||||
self
|
||||
}
|
||||
|
||||
/// Checks is signature is empty.
|
||||
/// Checks if the signature is empty.
|
||||
pub fn is_unsigned(&self) -> bool {
|
||||
self.r.is_zero() && self.s.is_zero()
|
||||
}
|
||||
@ -386,17 +390,12 @@ impl UnverifiedTransaction {
|
||||
}
|
||||
|
||||
/// Verify basic signature params. Does not attempt sender recovery.
|
||||
pub fn verify_basic(&self, check_low_s: bool, chain_id: Option<u64>, allow_empty_signature: bool) -> Result<(), error::Error> {
|
||||
if check_low_s && !(allow_empty_signature && self.is_unsigned()) {
|
||||
self.check_low_s()?;
|
||||
}
|
||||
// Disallow unsigned transactions in case EIP-86 is disabled.
|
||||
if !allow_empty_signature && self.is_unsigned() {
|
||||
pub fn verify_basic(&self, check_low_s: bool, chain_id: Option<u64>) -> Result<(), error::Error> {
|
||||
if self.is_unsigned() {
|
||||
return Err(ethkey::Error::InvalidSignature.into());
|
||||
}
|
||||
// EIP-86: Transactions of this form MUST have gasprice = 0, nonce = 0, value = 0, and do NOT increment the nonce of account 0.
|
||||
if allow_empty_signature && self.is_unsigned() && !(self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero()) {
|
||||
return Err(ethkey::Error::InvalidSignature.into())
|
||||
if check_low_s {
|
||||
self.check_low_s()?;
|
||||
}
|
||||
match (self.chain_id(), chain_id) {
|
||||
(None, _) => {},
|
||||
@ -436,20 +435,15 @@ impl SignedTransaction {
|
||||
/// Try to verify transaction and recover sender.
|
||||
pub fn new(transaction: UnverifiedTransaction) -> Result<Self, ethkey::Error> {
|
||||
if transaction.is_unsigned() {
|
||||
Ok(SignedTransaction {
|
||||
transaction: transaction,
|
||||
sender: UNSIGNED_SENDER,
|
||||
public: None,
|
||||
})
|
||||
} else {
|
||||
let public = transaction.recover_public()?;
|
||||
let sender = public_to_address(&public);
|
||||
Ok(SignedTransaction {
|
||||
transaction: transaction,
|
||||
sender: sender,
|
||||
public: Some(public),
|
||||
})
|
||||
return Err(ethkey::Error::InvalidSignature);
|
||||
}
|
||||
let public = transaction.recover_public()?;
|
||||
let sender = public_to_address(&public);
|
||||
Ok(SignedTransaction {
|
||||
transaction,
|
||||
sender,
|
||||
public: Some(public),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns transaction sender.
|
||||
@ -640,6 +634,24 @@ mod tests {
|
||||
assert_eq!(t.chain_id(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_reject_null_signature() {
|
||||
let t = Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(10000000000u64),
|
||||
gas: U256::from(21000),
|
||||
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
value: U256::from(1),
|
||||
data: vec![]
|
||||
}.null_sign(1);
|
||||
|
||||
let res = SignedTransaction::new(t.transaction);
|
||||
match res {
|
||||
Err(ethkey::Error::InvalidSignature) => {}
|
||||
_ => panic!("null signature should be rejected"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_recover_from_chain_specific_signing() {
|
||||
use ethkey::{Random, Generator};
|
||||
|
@ -9,7 +9,7 @@ name = "parity-evm"
|
||||
path = "./src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
common-types = { path = "../ethcore/types" }
|
||||
common-types = { path = "../ethcore/types", features = ["test-helpers"] }
|
||||
docopt = "1.0"
|
||||
env_logger = "0.5"
|
||||
ethcore = { path = "../ethcore", features = ["test-helpers", "json-tests", "to-pod-full"] }
|
||||
|
@ -203,6 +203,28 @@ mod tests {
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialization_alt_bn128_const_operations() {
|
||||
let s = r#"{
|
||||
"name": "alt_bn128_mul",
|
||||
"pricing": {
|
||||
"100500": {
|
||||
"price": { "alt_bn128_const_operations": { "price": 123 }}
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let builtin: Builtin = serde_json::from_str::<BuiltinCompat>(s).unwrap().into();
|
||||
assert_eq!(builtin.name, "alt_bn128_mul");
|
||||
assert_eq!(builtin.pricing, map![
|
||||
100500 => PricingAt {
|
||||
info: None,
|
||||
price: Pricing::AltBn128ConstOperations(AltBn128ConstOperations {
|
||||
price: 123,
|
||||
}),
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn activate_at() {
|
||||
let s = r#"{
|
||||
|
@ -50,6 +50,15 @@ pub trait Client: fmt::Debug + Sync {
|
||||
/// Is transaction with given hash already in the blockchain?
|
||||
fn transaction_already_included(&self, hash: &H256) -> bool;
|
||||
|
||||
/// Perform basic/cheap transaction verification.
|
||||
///
|
||||
/// This should include all cheap checks that can be done before
|
||||
/// actually checking the signature, like chain-replay protection.
|
||||
///
|
||||
/// This method is currently used only for verifying local transactions.
|
||||
fn verify_transaction_basic(&self, t: &transaction::UnverifiedTransaction)
|
||||
-> Result<(), transaction::Error>;
|
||||
|
||||
/// Structurarily verify given transaction.
|
||||
fn verify_transaction(&self, tx: transaction::UnverifiedTransaction)
|
||||
-> Result<transaction::SignedTransaction, transaction::Error>;
|
||||
|
@ -103,6 +103,12 @@ impl pool::client::Client for TestClient {
|
||||
false
|
||||
}
|
||||
|
||||
fn verify_transaction_basic(&self, _tx: &UnverifiedTransaction)
|
||||
-> Result<(), transaction::Error>
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_transaction(&self, tx: UnverifiedTransaction)
|
||||
-> Result<SignedTransaction, transaction::Error>
|
||||
{
|
||||
|
@ -250,7 +250,13 @@ impl<C: Client> txpool::Verifier<Transaction> for Verifier<C, ::pool::scoring::N
|
||||
return Err(err)
|
||||
},
|
||||
},
|
||||
Transaction::Local(tx) => tx,
|
||||
Transaction::Local(tx) => match self.client.verify_transaction_basic(&**tx) {
|
||||
Ok(()) => tx,
|
||||
Err(err) => {
|
||||
warn!(target: "txqueue", "[{:?}] Rejected local tx {:?}", hash, err);
|
||||
return Err(err)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Verify RLP payload
|
||||
|
@ -20,6 +20,3 @@
|
||||
mod impls;
|
||||
|
||||
pub use self::impls::{open_db, restoration_db_handler, migrate};
|
||||
|
||||
#[cfg(feature = "secretstore")]
|
||||
pub use self::impls::open_secretstore_db;
|
||||
|
@ -208,11 +208,11 @@ pub fn migrate(path: &Path, compaction_profile: &DatabaseCompactionProfile) -> R
|
||||
|
||||
// Further migrations
|
||||
if version < CURRENT_VERSION && exists(&db_path) {
|
||||
println!("Migrating database from version {} to {}", version, CURRENT_VERSION);
|
||||
info!(target: "migration", "Migrating database from version {} to {}", version, CURRENT_VERSION);
|
||||
migrate_database(version, &db_path, consolidated_database_migrations(&compaction_profile)?)?;
|
||||
|
||||
if version < BLOOMS_DB_VERSION {
|
||||
println!("Migrating blooms to blooms-db...");
|
||||
info!(target: "migration", "Migrating blooms to blooms-db...");
|
||||
let db_config = DatabaseConfig {
|
||||
max_open_files: 64,
|
||||
memory_budget: None,
|
||||
@ -223,7 +223,7 @@ pub fn migrate(path: &Path, compaction_profile: &DatabaseCompactionProfile) -> R
|
||||
migrate_blooms(&db_path, &db_config).map_err(Error::BloomsDB)?;
|
||||
}
|
||||
|
||||
println!("Migration finished");
|
||||
info!(target: "migration", "Migration finished");
|
||||
}
|
||||
|
||||
// update version file.
|
||||
|
@ -18,6 +18,9 @@ extern crate kvdb_rocksdb;
|
||||
extern crate migration_rocksdb;
|
||||
extern crate ethcore_blockchain;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate tempdir;
|
||||
|
||||
use std::{io, fs};
|
||||
use std::sync::Arc;
|
||||
use std::path::Path;
|
||||
@ -37,13 +40,13 @@ mod helpers;
|
||||
pub use self::migration::migrate;
|
||||
|
||||
struct AppDB {
|
||||
key_value: Arc<KeyValueDB>,
|
||||
key_value: Arc<dyn KeyValueDB>,
|
||||
blooms: blooms_db::Database,
|
||||
trace_blooms: blooms_db::Database,
|
||||
}
|
||||
|
||||
impl BlockChainDB for AppDB {
|
||||
fn key_value(&self) -> &Arc<KeyValueDB> {
|
||||
fn key_value(&self) -> &Arc<dyn KeyValueDB> {
|
||||
&self.key_value
|
||||
}
|
||||
|
||||
@ -56,19 +59,8 @@ impl BlockChainDB for AppDB {
|
||||
}
|
||||
}
|
||||
|
||||
/// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path.
|
||||
#[cfg(feature = "secretstore")]
|
||||
pub fn open_secretstore_db(data_path: &str) -> Result<Arc<KeyValueDB>, String> {
|
||||
use std::path::PathBuf;
|
||||
|
||||
let mut db_path = PathBuf::from(data_path);
|
||||
db_path.push("db");
|
||||
let db_path = db_path.to_str().ok_or_else(|| "Invalid secretstore path".to_string())?;
|
||||
Ok(Arc::new(Database::open_default(&db_path).map_err(|e| format!("Error opening database: {:?}", e))?))
|
||||
}
|
||||
|
||||
/// Create a restoration db handler using the config generated by `client_path` and `client_config`.
|
||||
pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig) -> Box<BlockChainDBHandler> {
|
||||
pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig) -> Box<dyn BlockChainDBHandler> {
|
||||
let client_db_config = helpers::client_db_config(client_path, client_config);
|
||||
|
||||
struct RestorationDBHandler {
|
||||
@ -76,7 +68,7 @@ pub fn restoration_db_handler(client_path: &Path, client_config: &ClientConfig)
|
||||
}
|
||||
|
||||
impl BlockChainDBHandler for RestorationDBHandler {
|
||||
fn open(&self, db_path: &Path) -> io::Result<Arc<BlockChainDB>> {
|
||||
fn open(&self, db_path: &Path) -> io::Result<Arc<dyn BlockChainDB>> {
|
||||
open_database(&db_path.to_string_lossy(), &self.config)
|
||||
}
|
||||
}
|
||||
@ -99,7 +91,7 @@ pub fn open_db(client_path: &str, cache_config: &CacheConfig, compaction: &Datab
|
||||
open_database(client_path, &db_config)
|
||||
}
|
||||
|
||||
pub fn open_database(client_path: &str, config: &DatabaseConfig) -> io::Result<Arc<BlockChainDB>> {
|
||||
pub fn open_database(client_path: &str, config: &DatabaseConfig) -> io::Result<Arc<dyn BlockChainDB>> {
|
||||
let path = Path::new(client_path);
|
||||
|
||||
let blooms_path = path.join("blooms");
|
||||
|
@ -123,7 +123,6 @@ mod server {
|
||||
use ethcore_secretstore;
|
||||
use ethkey::KeyPair;
|
||||
use ansi_term::Colour::{Red, White};
|
||||
use db;
|
||||
use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress, Executor};
|
||||
|
||||
fn into_service_contract_address(address: ContractAddress) -> ethcore_secretstore::ContractAddress {
|
||||
@ -135,13 +134,13 @@ mod server {
|
||||
|
||||
/// Key server
|
||||
pub struct KeyServer {
|
||||
_key_server: Box<ethcore_secretstore::KeyServer>,
|
||||
_key_server: Box<dyn ethcore_secretstore::KeyServer>,
|
||||
}
|
||||
|
||||
impl KeyServer {
|
||||
/// Create new key server
|
||||
pub fn new(mut conf: Configuration, deps: Dependencies, executor: Executor) -> Result<Self, String> {
|
||||
let self_secret: Arc<ethcore_secretstore::NodeKeyPair> = match conf.self_secret.take() {
|
||||
let self_secret: Arc<dyn ethcore_secretstore::NodeKeyPair> = match conf.self_secret.take() {
|
||||
Some(NodeSecretKey::Plain(secret)) => Arc::new(ethcore_secretstore::PlainNodeKeyPair::new(
|
||||
KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)),
|
||||
#[cfg(feature = "accounts")]
|
||||
@ -202,7 +201,7 @@ mod server {
|
||||
|
||||
cconf.cluster_config.nodes.insert(self_secret.public().clone(), cconf.cluster_config.listener_address.clone());
|
||||
|
||||
let db = db::open_secretstore_db(&conf.data_path)?;
|
||||
let db = ethcore_secretstore::open_secretstore_db(&conf.data_path)?;
|
||||
let key_server = ethcore_secretstore::start(deps.client, deps.sync, deps.miner, self_secret, cconf, db, executor)
|
||||
.map_err(|e| format!("Error starting KeyServer {}: {}", key_server_name, e))?;
|
||||
|
||||
|
@ -21,6 +21,7 @@ futures = "0.1"
|
||||
hyper = { version = "0.12", default-features = false }
|
||||
keccak-hash = "0.2.0"
|
||||
kvdb = "0.1"
|
||||
kvdb-rocksdb = "0.1.5"
|
||||
lazy_static = "1.0"
|
||||
log = "0.4"
|
||||
parity-bytes = "0.1"
|
||||
@ -43,7 +44,6 @@ jsonrpc-server-utils = "14.0.3"
|
||||
env_logger = "0.5"
|
||||
ethcore = { path = "../ethcore", features = ["test-helpers"] }
|
||||
tempdir = "0.3"
|
||||
kvdb-rocksdb = "0.1.5"
|
||||
|
||||
[features]
|
||||
accounts = ["ethcore-accounts"]
|
||||
|
@ -24,11 +24,6 @@ use kvdb::KeyValueDB;
|
||||
use types::{Error, ServerKeyId, NodeId};
|
||||
use serialization::{SerializablePublic, SerializableSecret, SerializableH256, SerializableAddress};
|
||||
|
||||
/// Key of version value.
|
||||
const DB_META_KEY_VERSION: &'static [u8; 7] = b"version";
|
||||
/// Current db version.
|
||||
const CURRENT_VERSION: u8 = 3;
|
||||
|
||||
/// Encrypted key share, stored by key storage on the single key server.
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
pub struct DocumentKeyShare {
|
||||
@ -72,17 +67,17 @@ pub trait KeyStorage: Send + Sync {
|
||||
/// Check if storage contains document encryption key
|
||||
fn contains(&self, document: &ServerKeyId) -> bool;
|
||||
/// Iterate through storage
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item=(ServerKeyId, DocumentKeyShare)> + 'a>;
|
||||
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item=(ServerKeyId, DocumentKeyShare)> + 'a>;
|
||||
}
|
||||
|
||||
/// Persistent document encryption keys storage
|
||||
pub struct PersistentKeyStorage {
|
||||
db: Arc<KeyValueDB>,
|
||||
db: Arc<dyn KeyValueDB>,
|
||||
}
|
||||
|
||||
/// Persistent document encryption keys storage iterator
|
||||
pub struct PersistentKeyStorageIterator<'a> {
|
||||
iter: Box<Iterator<Item=(Box<[u8]>, Box<[u8]>)> + 'a>,
|
||||
iter: Box<dyn Iterator<Item=(Box<[u8]>, Box<[u8]>)> + 'a>,
|
||||
}
|
||||
|
||||
/// V3 of encrypted key share, as it is stored by key storage on the single key server.
|
||||
@ -115,27 +110,8 @@ struct SerializableDocumentKeyShareVersionV3 {
|
||||
|
||||
impl PersistentKeyStorage {
|
||||
/// Create new persistent document encryption keys storage
|
||||
pub fn new(db: Arc<KeyValueDB>) -> Result<Self, Error> {
|
||||
let db = upgrade_db(db)?;
|
||||
|
||||
Ok(PersistentKeyStorage {
|
||||
db: db,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn upgrade_db(db: Arc<KeyValueDB>) -> Result<Arc<KeyValueDB>, Error> {
|
||||
let version = db.get(None, DB_META_KEY_VERSION)?;
|
||||
let version = version.and_then(|v| v.get(0).cloned());
|
||||
match version {
|
||||
None => {
|
||||
let mut batch = db.transaction();
|
||||
batch.put(None, DB_META_KEY_VERSION, &[CURRENT_VERSION]);
|
||||
db.write(batch)?;
|
||||
Ok(db)
|
||||
},
|
||||
Some(CURRENT_VERSION) => Ok(db),
|
||||
_ => Err(Error::Database(format!("unsupported SecretStore database version: {:?}", version))),
|
||||
pub fn new(db: Arc<dyn KeyValueDB>) -> Result<Self, Error> {
|
||||
Ok(Self { db })
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +120,7 @@ impl KeyStorage for PersistentKeyStorage {
|
||||
let key: SerializableDocumentKeyShareV3 = key.into();
|
||||
let key = serde_json::to_vec(&key).map_err(|e| Error::Database(e.to_string()))?;
|
||||
let mut batch = self.db.transaction();
|
||||
batch.put(None, document.as_bytes(), &key);
|
||||
batch.put(Some(0), document.as_bytes(), &key);
|
||||
self.db.write(batch).map_err(Into::into)
|
||||
}
|
||||
|
||||
@ -153,7 +129,7 @@ impl KeyStorage for PersistentKeyStorage {
|
||||
}
|
||||
|
||||
fn get(&self, document: &ServerKeyId) -> Result<Option<DocumentKeyShare>, Error> {
|
||||
self.db.get(None, document.as_bytes())
|
||||
self.db.get(Some(0), document.as_bytes())
|
||||
.map_err(|e| Error::Database(e.to_string()))
|
||||
.and_then(|key| match key {
|
||||
None => Ok(None),
|
||||
@ -166,28 +142,28 @@ impl KeyStorage for PersistentKeyStorage {
|
||||
|
||||
fn remove(&self, document: &ServerKeyId) -> Result<(), Error> {
|
||||
let mut batch = self.db.transaction();
|
||||
batch.delete(None, document.as_bytes());
|
||||
batch.delete(Some(0), document.as_bytes());
|
||||
self.db.write(batch).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn clear(&self) -> Result<(), Error> {
|
||||
let mut batch = self.db.transaction();
|
||||
for (key, _) in self.iter() {
|
||||
batch.delete(None, key.as_bytes());
|
||||
batch.delete(Some(0), key.as_bytes());
|
||||
}
|
||||
self.db.write(batch)
|
||||
.map_err(|e| Error::Database(e.to_string()))
|
||||
}
|
||||
|
||||
fn contains(&self, document: &ServerKeyId) -> bool {
|
||||
self.db.get(None, document.as_bytes())
|
||||
self.db.get(Some(0), document.as_bytes())
|
||||
.map(|k| k.is_some())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item=(ServerKeyId, DocumentKeyShare)> + 'a> {
|
||||
Box::new(PersistentKeyStorageIterator {
|
||||
iter: self.db.iter(None),
|
||||
iter: self.db.iter(Some(0)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -297,7 +273,7 @@ pub mod tests {
|
||||
use parking_lot::RwLock;
|
||||
use self::tempdir::TempDir;
|
||||
use ethkey::{Random, Generator, Public};
|
||||
use kvdb_rocksdb::Database;
|
||||
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||
use types::{Error, ServerKeyId};
|
||||
use super::{KeyStorage, PersistentKeyStorage, DocumentKeyShare, DocumentKeyShareVersion};
|
||||
|
||||
@ -336,7 +312,7 @@ pub mod tests {
|
||||
self.keys.read().contains_key(document)
|
||||
}
|
||||
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item=(ServerKeyId, DocumentKeyShare)> + 'a> {
|
||||
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item=(ServerKeyId, DocumentKeyShare)> + 'a> {
|
||||
Box::new(self.keys.read().clone().into_iter())
|
||||
}
|
||||
}
|
||||
@ -376,7 +352,8 @@ pub mod tests {
|
||||
};
|
||||
let key3 = ServerKeyId::from_low_u64_be(3);
|
||||
|
||||
let db = Database::open_default(&tempdir.path().display().to_string()).unwrap();
|
||||
let db_config = DatabaseConfig::with_columns(Some(1));
|
||||
let db = Database::open(&db_config, &tempdir.path().display().to_string()).unwrap();
|
||||
|
||||
let key_storage = PersistentKeyStorage::new(Arc::new(db)).unwrap();
|
||||
key_storage.insert(key1.clone(), value1.clone()).unwrap();
|
||||
@ -386,7 +363,7 @@ pub mod tests {
|
||||
assert_eq!(key_storage.get(&key3), Ok(None));
|
||||
drop(key_storage);
|
||||
|
||||
let db = Database::open_default(&tempdir.path().display().to_string()).unwrap();
|
||||
let db = Database::open(&db_config, &tempdir.path().display().to_string()).unwrap();
|
||||
|
||||
let key_storage = PersistentKeyStorage::new(Arc::new(db)).unwrap();
|
||||
assert_eq!(key_storage.get(&key1), Ok(Some(value1)));
|
||||
|
@ -25,6 +25,7 @@ extern crate ethkey;
|
||||
extern crate hyper;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate kvdb;
|
||||
extern crate kvdb_rocksdb;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate parity_crypto as crypto;
|
||||
extern crate parity_runtime;
|
||||
@ -56,7 +57,7 @@ extern crate log;
|
||||
#[cfg(test)]
|
||||
extern crate env_logger;
|
||||
#[cfg(test)]
|
||||
extern crate kvdb_rocksdb;
|
||||
extern crate tempdir;
|
||||
|
||||
#[cfg(feature = "accounts")]
|
||||
extern crate ethcore_accounts as accounts;
|
||||
@ -74,9 +75,11 @@ mod key_server_set;
|
||||
mod node_key_pair;
|
||||
mod listener;
|
||||
mod trusted_client;
|
||||
mod migration;
|
||||
|
||||
use std::sync::Arc;
|
||||
use kvdb::KeyValueDB;
|
||||
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||
use ethcore::client::Client;
|
||||
use ethcore::miner::Miner;
|
||||
use sync::SyncProvider;
|
||||
@ -89,12 +92,26 @@ pub use self::node_key_pair::PlainNodeKeyPair;
|
||||
#[cfg(feature = "accounts")]
|
||||
pub use self::node_key_pair::KeyStoreNodeKeyPair;
|
||||
|
||||
/// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path.
|
||||
pub fn open_secretstore_db(data_path: &str) -> Result<Arc<dyn KeyValueDB>, String> {
|
||||
use std::path::PathBuf;
|
||||
|
||||
migration::upgrade_db(data_path).map_err(|e| e.to_string())?;
|
||||
|
||||
let mut db_path = PathBuf::from(data_path);
|
||||
db_path.push("db");
|
||||
let db_path = db_path.to_str().ok_or_else(|| "Invalid secretstore path".to_string())?;
|
||||
|
||||
let config = DatabaseConfig::with_columns(Some(1));
|
||||
Ok(Arc::new(Database::open(&config, &db_path).map_err(|e| format!("Error opening database: {:?}", e))?))
|
||||
}
|
||||
|
||||
/// Start new key server instance
|
||||
pub fn start(client: Arc<Client>, sync: Arc<SyncProvider>, miner: Arc<Miner>, self_key_pair: Arc<NodeKeyPair>, mut config: ServiceConfiguration,
|
||||
db: Arc<KeyValueDB>, executor: Executor) -> Result<Box<KeyServer>, Error>
|
||||
pub fn start(client: Arc<Client>, sync: Arc<dyn SyncProvider>, miner: Arc<Miner>, self_key_pair: Arc<dyn NodeKeyPair>, mut config: ServiceConfiguration,
|
||||
db: Arc<dyn KeyValueDB>, executor: Executor) -> Result<Box<dyn KeyServer>, Error>
|
||||
{
|
||||
let trusted_client = trusted_client::TrustedClient::new(self_key_pair.clone(), client.clone(), sync, miner);
|
||||
let acl_storage: Arc<acl_storage::AclStorage> = match config.acl_check_contract_address.take() {
|
||||
let acl_storage: Arc<dyn acl_storage::AclStorage> = match config.acl_check_contract_address.take() {
|
||||
Some(acl_check_contract_address) => acl_storage::OnChainAclStorage::new(trusted_client.clone(), acl_check_contract_address)?,
|
||||
None => Arc::new(acl_storage::DummyAclStorage::default()),
|
||||
};
|
||||
@ -105,7 +122,7 @@ pub fn start(client: Arc<Client>, sync: Arc<SyncProvider>, miner: Arc<Miner>, se
|
||||
let key_server = Arc::new(key_server::KeyServerImpl::new(&config.cluster_config, key_server_set.clone(), self_key_pair.clone(),
|
||||
acl_storage.clone(), key_storage.clone(), executor.clone())?);
|
||||
let cluster = key_server.cluster();
|
||||
let key_server: Arc<KeyServer> = key_server;
|
||||
let key_server: Arc<dyn KeyServer> = key_server;
|
||||
|
||||
// prepare HTTP listener
|
||||
let http_listener = match config.listener_address {
|
||||
@ -122,7 +139,7 @@ pub fn start(client: Arc<Client>, sync: Arc<SyncProvider>, miner: Arc<Miner>, se
|
||||
address,
|
||||
self_key_pair.clone()));
|
||||
|
||||
let mut contracts: Vec<Arc<listener::service_contract::ServiceContract>> = Vec::new();
|
||||
let mut contracts: Vec<Arc<dyn listener::service_contract::ServiceContract>> = Vec::new();
|
||||
config.service_contract_address.map(|address|
|
||||
create_service_contract(address,
|
||||
listener::service_contract::SERVICE_CONTRACT_REGISTRY_NAME.to_owned(),
|
||||
@ -149,7 +166,7 @@ pub fn start(client: Arc<Client>, sync: Arc<SyncProvider>, miner: Arc<Miner>, se
|
||||
listener::ApiMask { document_key_shadow_retrieval_requests: true, ..Default::default() }))
|
||||
.map(|l| contracts.push(l));
|
||||
|
||||
let contract: Option<Arc<listener::service_contract::ServiceContract>> = match contracts.len() {
|
||||
let contract: Option<Arc<dyn listener::service_contract::ServiceContract>> = match contracts.len() {
|
||||
0 => None,
|
||||
1 => Some(contracts.pop().expect("contract.len() is 1; qed")),
|
||||
_ => Some(Arc::new(listener::service_contract_aggregate::OnChainServiceContractAggregate::new(contracts))),
|
||||
|
206
secret-store/src/migration.rs
Normal file
206
secret-store/src/migration.rs
Normal file
@ -0,0 +1,206 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity Ethereum.
|
||||
|
||||
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Secret Store DB migration module.
|
||||
|
||||
|
||||
use std::fmt::{Display, Error as FmtError, Formatter};
|
||||
use std::fs;
|
||||
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read as _, Write as _};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use kvdb::DBTransaction;
|
||||
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||
|
||||
/// We used to store the version in the database (until version 4).
|
||||
const LEGACY_DB_META_KEY_VERSION: &[u8; 7] = b"version";
|
||||
/// Current db version.
|
||||
const CURRENT_VERSION: u8 = 4;
|
||||
/// Database is assumed to be at the default version, when no version file is found.
|
||||
const DEFAULT_VERSION: u8 = 3;
|
||||
/// Version file name.
|
||||
const VERSION_FILE_NAME: &str = "db_version";
|
||||
|
||||
/// Migration related erorrs.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Returned when current version cannot be read or guessed.
|
||||
UnknownDatabaseVersion,
|
||||
/// Existing DB is newer than the known one.
|
||||
FutureDBVersion,
|
||||
/// Migration was completed succesfully,
|
||||
/// but there was a problem with io.
|
||||
Io(IoError),
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
||||
let out = match *self {
|
||||
Error::UnknownDatabaseVersion =>
|
||||
"Current Secret Store database version cannot be read".into(),
|
||||
Error::FutureDBVersion =>
|
||||
"Secret Store database was created with newer client version.\
|
||||
Upgrade your client or delete DB and resync.".into(),
|
||||
Error::Io(ref err) =>
|
||||
format!("Unexpected io error on Secret Store database migration: {}.", err),
|
||||
};
|
||||
write!(f, "{}", out)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IoError> for Error {
|
||||
fn from(err: IoError) -> Self {
|
||||
Error::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
fn other_io_err<E>(e: E) -> IoError where E: Into<Box<std::error::Error + Send + Sync>> {
|
||||
IoError::new(std::io::ErrorKind::Other, e)
|
||||
}
|
||||
|
||||
|
||||
// Moves "default" column to column 0 in preparation for a kvdb-rocksdb 0.3 migration.
|
||||
fn migrate_to_v4(parent_dir: &str) -> Result<(), Error> {
|
||||
// Naïve implementation until
|
||||
// https://github.com/facebook/rocksdb/issues/6130 is resolved
|
||||
let old_db_config = DatabaseConfig::with_columns(Some(1));
|
||||
let new_db_config = DatabaseConfig::with_columns(Some(1));
|
||||
const BATCH_SIZE: usize = 1024;
|
||||
|
||||
let old_dir = db_dir(parent_dir);
|
||||
let new_dir = migration_dir(parent_dir);
|
||||
let old_db = Database::open(&old_db_config, &old_dir)?;
|
||||
let new_db = Database::open(&new_db_config, &new_dir)?;
|
||||
|
||||
const OLD_COLUMN: Option<u32> = None;
|
||||
const NEW_COLUMN: Option<u32> = Some(0);
|
||||
|
||||
// remove legacy version key
|
||||
{
|
||||
let mut batch = DBTransaction::with_capacity(1);
|
||||
batch.delete(OLD_COLUMN, LEGACY_DB_META_KEY_VERSION);
|
||||
if let Err(err) = old_db.write(batch) {
|
||||
error!(target: "migration", "Failed to delete db version {}", &err);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
|
||||
let mut batch = DBTransaction::with_capacity(BATCH_SIZE);
|
||||
let old_db_iter = old_db.iter(OLD_COLUMN).ok_or_else(|| {
|
||||
IoError::new(std::io::ErrorKind::Other, "No database available to iterate over – shutting down?")
|
||||
})?;
|
||||
for (i, (key, value)) in old_db_iter.enumerate() {
|
||||
batch.put(NEW_COLUMN, &key, &value);
|
||||
if i % BATCH_SIZE == 0 {
|
||||
new_db.write(batch)?;
|
||||
batch = DBTransaction::with_capacity(BATCH_SIZE);
|
||||
info!(target: "migration", "Migrating Secret Store DB: {} keys written", i);
|
||||
}
|
||||
}
|
||||
new_db.write(batch)?;
|
||||
drop(new_db);
|
||||
old_db.restore(&new_dir)?;
|
||||
|
||||
info!(target: "migration", "Secret Store migration finished");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Apply all migrations if possible.
|
||||
pub fn upgrade_db(db_path: &str) -> Result<(), Error> {
|
||||
match current_version(db_path)? {
|
||||
old_version if old_version < CURRENT_VERSION => {
|
||||
migrate_to_v4(db_path)?;
|
||||
update_version(db_path)?;
|
||||
Ok(())
|
||||
},
|
||||
CURRENT_VERSION => Ok(()),
|
||||
_ => Err(Error::FutureDBVersion),
|
||||
}
|
||||
}
|
||||
|
||||
fn db_dir(path: &str) -> String {
|
||||
let mut dir = PathBuf::from(path);
|
||||
dir.push("db");
|
||||
dir.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
fn migration_dir(path: &str) -> String {
|
||||
let mut dir = PathBuf::from(path);
|
||||
dir.push("migration");
|
||||
dir.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
/// Returns the version file path.
|
||||
fn version_file_path(path: &str) -> PathBuf {
|
||||
let mut file_path = PathBuf::from(path);
|
||||
file_path.push(VERSION_FILE_NAME);
|
||||
file_path
|
||||
}
|
||||
|
||||
/// Reads current database version from the file at given path.
|
||||
/// If the file does not exist returns `DEFAULT_VERSION`.
|
||||
fn current_version(path: &str) -> Result<u8, Error> {
|
||||
match fs::File::open(version_file_path(path)) {
|
||||
Err(ref err) if err.kind() == IoErrorKind::NotFound => Ok(DEFAULT_VERSION),
|
||||
Err(err) => Err(err.into()),
|
||||
Ok(mut file) => {
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)?;
|
||||
u8::from_str_radix(&s, 10).map_err(|_| Error::UnknownDatabaseVersion)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes current database version to the file.
|
||||
/// Creates a new file if the version file does not exist yet.
|
||||
fn update_version(path: &str) -> Result<(), Error> {
|
||||
let mut file = fs::File::create(version_file_path(path))?;
|
||||
file.write_all(format!("{}", CURRENT_VERSION).as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[test]
|
||||
fn migration_works() -> Result<(), Error> {
|
||||
let parent = TempDir::new("secret_store_migration")?.into_path();
|
||||
|
||||
let mut db_path = parent.clone();
|
||||
db_path.push("db");
|
||||
let db_path = db_path.to_str().unwrap();
|
||||
let parent_path = parent.to_str().unwrap();
|
||||
|
||||
let old_db = Database::open(&DatabaseConfig::with_columns(None), db_path)?;
|
||||
|
||||
let mut batch = old_db.transaction();
|
||||
batch.put(None, b"key1", b"value1");
|
||||
batch.put(None, b"key2", b"value2");
|
||||
old_db.write(batch)?;
|
||||
drop(old_db);
|
||||
|
||||
upgrade_db(parent_path)?;
|
||||
let migrated = Database::open(&DatabaseConfig::with_columns(Some(1)), db_path)?;
|
||||
|
||||
assert_eq!(migrated.get(Some(0), b"key1")?.expect("key1"), b"value1".to_vec());
|
||||
assert_eq!(migrated.get(Some(0), b"key2")?.expect("key2"), b"value2".to_vec());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -74,10 +74,10 @@ mod accounts {
|
||||
pub fn new(account_provider: Arc<AccountProvider>, address: Address, password: Password) -> Result<Self, EthKeyError> {
|
||||
let public = account_provider.account_public(address.clone(), &password).map_err(|e| EthKeyError::Custom(format!("{}", e)))?;
|
||||
Ok(KeyStoreNodeKeyPair {
|
||||
account_provider: account_provider,
|
||||
address: address,
|
||||
public: public,
|
||||
password: password,
|
||||
account_provider,
|
||||
address,
|
||||
public,
|
||||
password,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
[package]
|
||||
name = "parity-version"
|
||||
# NOTE: this value is used for Parity Ethereum version string (via env CARGO_PKG_VERSION)
|
||||
version = "2.6.6"
|
||||
version = "2.6.7"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user