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:
David 2019-12-16 14:54:27 +01:00 committed by s3krit
parent 5162bc2c88
commit ba1b879e9f
32 changed files with 645 additions and 182 deletions

View File

@ -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
View File

@ -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)",

View File

@ -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>"]

View File

@ -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" }

View File

@ -37,7 +37,10 @@
"eip140Transition": "0x85d9a0",
"eip211Transition": "0x85d9a0",
"eip214Transition": "0x85d9a0",
"eip658Transition": "0x85d9a0"
"eip658Transition": "0x85d9a0",
"eip145Transition": "0x921288",
"eip1014Transition": "0x921288",
"eip1052Transition": "0x921288"
},
"genesis": {
"seal": {

View File

@ -136,7 +136,8 @@
"eip100bTransition": "0x42ae50",
"difficultyBombDelays": {
"0x42ae50": "0x2dc6c0",
"0x6f1580": "0x1e8480"
"0x6f1580": "0x1e8480",
"0x8c6180": "0x3d0900"
}
}
}

View File

@ -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"

View File

@ -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
}
}
}
}
}
}

View File

@ -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
}
}
}
}
}

View File

@ -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
}
}
}
}
}

View File

@ -16,7 +16,8 @@
"eip100bTransition": "0x19f0a0",
"difficultyBombDelays": {
"0x19f0a0": "0x2dc6c0",
"0x408b70": "0x1e8480"
"0x408b70": "0x1e8480",
"0x6c993d": "0x3d0900"
}
}
}

View File

@ -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
}
}
}
}
}

View File

@ -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{

View File

@ -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(())
}

View File

@ -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();

View File

@ -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)?;

View File

@ -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};

View File

@ -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"] }

View File

@ -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#"{

View File

@ -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>;

View File

@ -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>
{

View File

@ -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

View File

@ -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;

View File

@ -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.

View 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");

View File

@ -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))?;

View File

@ -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"]

View File

@ -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)));

View File

@ -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))),

View 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(())
}
}

View File

@ -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,
})
}
}

View File

@ -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"