diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 3b8d60af8..336d6a0fc 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -39,7 +39,7 @@ keccak-hasher = { path = "../util/keccak-hasher" } kvdb = "0.1" kvdb-memorydb = "0.1" kvdb-rocksdb = { version = "0.1.3", optional = true } -lazy_static = "1.0" +lazy_static = "1.2.0" len-caching-lock = { path = "../util/len-caching-lock" } log = "0.4" lru-cache = "0.1" diff --git a/ethcore/res/ethereum/goerli.json b/ethcore/res/ethereum/goerli.json new file mode 100644 index 000000000..e3ba75927 --- /dev/null +++ b/ethcore/res/ethereum/goerli.json @@ -0,0 +1,911 @@ +{ + "name": "Görli Testnet", + "dataDir": "goerli", + "engine": { + "clique": { + "params": { + "period": 15, + "epoch": 30000 + } + } + }, + "params": { + "accountStartNonce": "0x0", + "chainID": "0x5", + "eip140Transition": "0x0", + "eip145Transition": "0x0", + "eip150Transition": "0x0", + "eip155Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0", + "eip1014Transition": "0x0", + "eip1052Transition": "0x0", + "eip1283Transition": "0x0", + "eip1283DisableTransition": "0x0", + "gasLimitBoundDivisor": "0x400", + "maxCodeSize": "0x6000", + "maxCodeSizeTransition": "0x0", + "maximumExtraDataSize": "0xffff", + "minGasLimit": "0x1388", + "networkID": "0x5" + }, + "genesis": { + "author": "0x0000000000000000000000000000000000000000", + "difficulty": "0x1", + "extraData": "0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0xa00000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "seal": { + "ethereum": { + "nonce": "0x0000000000000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "timestamp": "0x5c51a607" + }, + "nodes": [ + "enode://011f758e6552d105183b1761c5e2dea0111bc20fd5f6422bc7f91e0fabbec9a6595caf6239b37feb773dddd3f87240d99d859431891e4a642cf2a0a9e6cbb98a@51.141.78.53:30303", + "enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303" + ], + "accounts": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "0x1", + "builtin": { + "name": "ecrecover", + "pricing": { + "linear": { + "base": 3000, + "word": 0 + } + } + } + }, + "0x0000000000000000000000000000000000000002": { + "balance": "0x1", + "builtin": { + "name": "sha256", + "pricing": { + "linear": { + "base": 60, + "word": 12 + } + } + } + }, + "0x0000000000000000000000000000000000000003": { + "balance": "0x1", + "builtin": { + "name": "ripemd160", + "pricing": { + "linear": { + "base": 600, + "word": 120 + } + } + } + }, + "0x0000000000000000000000000000000000000004": { + "balance": "0x1", + "builtin": { + "name": "identity", + "pricing": { + "linear": { + "base": 15, + "word": 3 + } + } + } + }, + "0x0000000000000000000000000000000000000005": { + "balance": "0x1", + "builtin": { + "name": "modexp", + "activate_at": "0x0", + "pricing": { + "modexp": { + "divisor": 20 + } + } + } + }, + "0x0000000000000000000000000000000000000006": { + "balance": "0x1", + "builtin": { + "name": "alt_bn128_add", + "activate_at": "0x0", + "pricing": { + "linear": { + "base": 500, + "word": 0 + } + } + } + }, + "0x0000000000000000000000000000000000000007": { + "balance": "0x1", + "builtin": { + "name": "alt_bn128_mul", + "activate_at": "0x0", + "pricing": { + "linear": { + "base": 40000, + "word": 0 + } + } + } + }, + "0x0000000000000000000000000000000000000008": { + "balance": "0x1", + "builtin": { + "name": "alt_bn128_pairing", + "activate_at": "0x0", + "pricing": { + "alt_bn128_pairing": { + "base": 100000, + "pair": 80000 + } + } + } + }, + "0x0000000000000000000000000000000000000009": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "0x1" + }, + "0x4c2ae482593505f0163cdefc073e81c63cda4107": { + "balance": "0x152d02c7e14af6800000" + }, + "0xa8e8f14732658e4b51e8711931053a8a69baf2b1": { + "balance": "0x152d02c7e14af6800000" + }, + "0xd9a5179f091d85051d3c982785efd1455cec8699": { + "balance": "0x84595161401484a000000" + }, + "0xe0a2bd4258d2768837baa26a28fe71dc079f84c7": { + "balance": "0x4a47e3c12448f4ad000000" + } + } +} diff --git a/ethcore/res/ethereum/kotti.json b/ethcore/res/ethereum/kotti.json new file mode 100644 index 000000000..06d1d31ea --- /dev/null +++ b/ethcore/res/ethereum/kotti.json @@ -0,0 +1,855 @@ +{ + "name": "Kotti Testnet", + "dataDir": "kotti", + "engine": { + "clique": { + "params": { + "period": 15, + "epoch": 30000 + } + } + }, + "params": { + "accountStartNonce": "0x0", + "chainID": "0x6", + "eip150Transition": "0x0", + "eip155Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff", + "gasLimitBoundDivisor": "0x400", + "maximumExtraDataSize": "0xffff", + "minGasLimit": "0x1388", + "networkID": "0x6" + }, + "genesis": { + "author": "0x0000000000000000000000000000000000000000", + "difficulty": "0x1", + "extraData": "0x000000000000000000000000000000000000000000000000000000000000000025b7955e43adf9c2a01a9475908702cce67f302a6aaf8cba3c9255a2b863415d4db7bae4f4bbca020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0xa00000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "seal": { + "ethereum": { + "nonce": "0x0000000000000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "timestamp": "0x5c2d2287" + }, + "nodes": [ + "enode://06333009fc9ef3c9e174768e495722a7f98fe7afd4660542e983005f85e556028410fd03278944f44cfe5437b1750b5e6bd1738f700fe7da3626d52010d2954c@51.141.15.254:30303", + "enode://ae8658da8d255d1992c3ec6e62e11d6e1c5899aa1566504bc1ff96a0c9c8bd44838372be643342553817f5cc7d78f1c83a8093dee13d77b3b0a583c050c81940@18.232.185.151:30303" + ], + "accounts": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "0x1", + "builtin": { + "name": "ecrecover", + "pricing": { + "linear": { + "base": 3000, + "word": 0 + } + } + } + }, + "0x0000000000000000000000000000000000000002": { + "balance": "0x1", + "builtin": { + "name": "sha256", + "pricing": { + "linear": { + "base": 60, + "word": 12 + } + } + } + }, + "0x0000000000000000000000000000000000000003": { + "balance": "0x1", + "builtin": { + "name": "ripemd160", + "pricing": { + "linear": { + "base": 600, + "word": 120 + } + } + } + }, + "0x0000000000000000000000000000000000000004": { + "balance": "0x1", + "builtin": { + "name": "identity", + "pricing": { + "linear": { + "base": 15, + "word": 3 + } + } + } + }, + "0x0000000000000000000000000000000000000005": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "0x1" + }, + "0x25b7955e43adf9c2a01a9475908702cce67f302a": { + "balance": "0x84595161401484a000000" + }, + "0x6aaf8cba3c9255a2b863415d4db7bae4f4bbca02": { + "balance": "0x4a723dc6b40b8a9a000000" + } + } +} diff --git a/ethcore/res/ethereum/rinkeby.json b/ethcore/res/ethereum/rinkeby.json new file mode 100644 index 000000000..7d9cc8023 --- /dev/null +++ b/ethcore/res/ethereum/rinkeby.json @@ -0,0 +1,902 @@ +{ + "name": "Rinkeby", + "dataDir": "rinkeby", + "engine": { + "clique": { + "params": { + "period": 15, + "epoch": 30000 + } + } + }, + "params": { + "accountStartNonce": "0x0", + "chainID": "0x4", + "eip140Transition": "0xfcc25", + "eip145Transition": "0x37db77", + "eip150Transition": "0x2", + "eip155Transition": "0x3", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip211Transition": "0xfcc25", + "eip214Transition": "0xfcc25", + "eip658Transition": "0xfcc25", + "eip1014Transition": "0x37db77", + "eip1052Transition": "0x37db77", + "eip1283Transition": "0x37db77", + "gasLimitBoundDivisor": "0x400", + "maxCodeSize": "0x6000", + "maxCodeSizeTransition": "0x0", + "maximumExtraDataSize": "0xffff", + "minGasLimit": "0x1388", + "networkID": "0x4" + }, + "genesis": { + "author": "0x0000000000000000000000000000000000000000", + "difficulty": "0x1", + "extraData": "0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x47b760", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "seal": { + "ethereum": { + "nonce": "0x0000000000000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "timestamp": "0x58ee40ba" + }, + "nodes": [ + "enode://a24ac7c5484ef4ed0c5eb2d36620ba4e4aa13b8c84684e1b4aab0cebea2ae45cb4d375b77eab56516d34bfbd3c1a833fc51296ff084b770b94fb9028c4d25ccf@52.169.42.101:30303", + "enode://343149e4feefa15d882d9fe4ac7d88f885bd05ebb735e547f12e12080a9fa07c8014ca6fd7f373123488102fe5e34111f8509cf0b7de3f5b44339c9f25e87cb8@52.3.158.184:30303", + "enode://b6b28890b006743680c52e64e0d16db57f28124885595fa03a562be1d2bf0f3a1da297d56b13da25fb992888fd556d4c1a27b1f39d531bde7de1921c90061cc6@159.89.28.211:30303" + ], + "accounts": { + "0x0000000000000000000000000000000000000000": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "0x1", + "builtin": { + "name": "ecrecover", + "pricing": { + "linear": { + "base": 3000, + "word": 0 + } + } + } + }, + "0x0000000000000000000000000000000000000002": { + "balance": "0x1", + "builtin": { + "name": "sha256", + "pricing": { + "linear": { + "base": 60, + "word": 12 + } + } + } + }, + "0x0000000000000000000000000000000000000003": { + "balance": "0x1", + "builtin": { + "name": "ripemd160", + "pricing": { + "linear": { + "base": 600, + "word": 120 + } + } + } + }, + "0x0000000000000000000000000000000000000004": { + "balance": "0x1", + "builtin": { + "name": "identity", + "pricing": { + "linear": { + "base": 15, + "word": 3 + } + } + } + }, + "0x0000000000000000000000000000000000000005": { + "balance": "0x1", + "builtin": { + "name": "modexp", + "activate_at": "0xfcc25", + "pricing": { + "modexp": { + "divisor": 20 + } + } + } + }, + "0x0000000000000000000000000000000000000006": { + "balance": "0x1", + "builtin": { + "name": "alt_bn128_add", + "activate_at": "0xfcc25", + "pricing": { + "linear": { + "base": 500, + "word": 0 + } + } + } + }, + "0x0000000000000000000000000000000000000007": { + "balance": "0x1", + "builtin": { + "name": "alt_bn128_mul", + "activate_at": "0xfcc25", + "pricing": { + "linear": { + "base": 40000, + "word": 0 + } + } + } + }, + "0x0000000000000000000000000000000000000008": { + "balance": "0x1", + "builtin": { + "name": "alt_bn128_pairing", + "activate_at": "0xfcc25", + "pricing": { + "alt_bn128_pairing": { + "base": 100000, + "pair": 80000 + } + } + } + }, + "0x0000000000000000000000000000000000000009": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "0x1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "0x1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "0x1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "0x1" + }, + "0x31b98d14007bdee637298086988a0bbd31184523": { + "balance": "0x200000000000000000000000000000000000000000000000000000000000000" + } + } +} diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index c5311cbe0..56cfc1c4c 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -284,7 +284,6 @@ impl<'x> OpenBlock<'x> { self.block.header.set_difficulty(*header.difficulty()); self.block.header.set_gas_limit(*header.gas_limit()); self.block.header.set_timestamp(header.timestamp()); - self.block.header.set_author(*header.author()); self.block.header.set_uncles_hash(*header.uncles_hash()); self.block.header.set_transactions_root(*header.transactions_root()); // TODO: that's horrible. set only for backwards compatibility @@ -405,15 +404,20 @@ impl LockedBlock { /// Provide a valid seal in order to turn this into a `SealedBlock`. /// /// NOTE: This does not check the validity of `seal` with the engine. - pub fn seal(self, engine: &EthEngine, seal: Vec) -> Result { - let expected_seal_fields = engine.seal_fields(&self.block.header); + pub fn seal(self, engine: &EthEngine, seal: Vec) -> Result { + let expected_seal_fields = engine.seal_fields(&self.header); let mut s = self; if seal.len() != expected_seal_fields { - return Err(BlockError::InvalidSealArity( - Mismatch { expected: expected_seal_fields, found: seal.len() })); + Err(BlockError::InvalidSealArity(Mismatch { + expected: expected_seal_fields, + found: seal.len() + }))?; } + s.block.header.set_seal(seal); + engine.on_seal_block(&mut s.block)?; s.block.header.compute_hash(); + Ok(SealedBlock { block: s.block }) @@ -422,6 +426,7 @@ impl LockedBlock { /// Provide a valid seal in order to turn this into a `SealedBlock`. /// This does check the validity of `seal` with the engine. /// Returns the `ClosedBlock` back again if the seal is no good. + /// TODO(https://github.com/paritytech/parity-ethereum/issues/10407): This is currently only used in POW chain call paths, we should really merge it with seal() above. pub fn try_seal( self, engine: &EthEngine, @@ -463,7 +468,7 @@ impl Drain for SealedBlock { } /// Enact the block given by block header, transactions and uncles -fn enact( +pub(crate) fn enact( header: Header, transactions: Vec, uncles: Vec
, @@ -476,13 +481,12 @@ fn enact( is_epoch_begin: bool, ancestry: &mut Iterator, ) -> Result { - { - if ::log::max_level() >= ::log::Level::Trace { - let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(parent.number() + 1), factories.clone())?; - trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n", - header.number(), s.root(), header.author(), s.balance(&header.author())?); - } - } + // For trace log + let trace_state = if log_enabled!(target: "enact", ::log::Level::Trace) { + Some(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(parent.number() + 1), factories.clone())?) + } else { + None + }; let mut b = OpenBlock::new( engine, @@ -491,13 +495,23 @@ fn enact( db, parent, last_hashes, - Address::new(), + // Engine such as Clique will calculate author from extra_data. + // this is only important for executing contracts as the 'executive_author'. + engine.executive_author(&header)?, (3141562.into(), 31415620.into()), vec![], is_epoch_begin, ancestry, )?; + if let Some(ref s) = trace_state { + let env = b.env_info(); + let root = s.root(); + let author_balance = s.balance(&env.author)?; + trace!(target: "enact", "num={}, root={}, author={}, author_balance={}\n", + b.block.header.number(), root, env.author, author_balance); + } + b.populate_from(&header); b.push_transactions(transactions)?; @@ -563,6 +577,7 @@ mod tests { last_hashes: Arc, factories: Factories, ) -> Result { + let block = Unverified::from_rlp(block_bytes)?; let header = block.header; let transactions: Result, Error> = block @@ -617,7 +632,7 @@ mod tests { ) -> Result { let header = Unverified::from_rlp(block_bytes.clone())?.header; Ok(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)? - .seal(engine, header.seal().to_vec())?) + .seal(engine, header.seal().to_vec())?) } #[test] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 9680c19df..193f48b20 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -399,6 +399,7 @@ impl Importer { let db = client.state_db.read().boxed_clone_canon(header.parent_hash()); let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some(); + let enact_result = enact_verified( block, engine, @@ -2515,7 +2516,11 @@ impl SnapshotClient for Client {} impl Drop for Client { fn drop(&mut self) { - self.engine.stop(); + if let Some(c) = Arc::get_mut(&mut self.engine) { + c.stop() + } else { + warn!(target: "shutdown", "unable to get mut ref for engine for shutdown."); + } } } diff --git a/ethcore/src/engines/clique/block_state.rs b/ethcore/src/engines/clique/block_state.rs new file mode 100644 index 000000000..4257076c0 --- /dev/null +++ b/ethcore/src/engines/clique/block_state.rs @@ -0,0 +1,369 @@ +// Copyright 2015-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 . + +use std::collections::{HashMap, BTreeSet, VecDeque}; +use std::fmt; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +use engines::EngineError; +use engines::clique::util::{extract_signers, recover_creator}; +use engines::clique::{VoteType, DIFF_INTURN, DIFF_NOTURN, NULL_AUTHOR, SIGNING_DELAY_NOTURN_MS}; +use error::{Error, BlockError}; +use ethereum_types::{Address, H64}; +use rand::Rng; +use types::BlockNumber; +use types::header::Header; +use unexpected::Mismatch; + +#[cfg(not(feature = "time_checked_add"))] +use time_utils::CheckedSystemTime; + +/// Type that keeps track of the state for a given vote +// Votes that go against the proposal aren't counted since it's equivalent to not voting +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct VoteState { + kind: VoteType, + votes: u64, +} + +/// Type that represent a vote +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub struct Vote { + block_number: BlockNumber, + beneficiary: Address, + kind: VoteType, + signer: Address, + reverted: bool, +} + +/// Type that represent a pending vote +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd)] +pub struct PendingVote { + signer: Address, + beneficiary: Address, +} + +/// Clique state for each block. +#[cfg(not(test))] +#[derive(Clone, Debug, Default)] +pub struct CliqueBlockState { + /// Current votes for a beneficiary + votes: HashMap, + /// A list of all votes for the given epoch + votes_history: Vec, + /// a list of all valid signer, sorted by ascending order. + signers: BTreeSet
, + /// a deque of recent signer, new entry should be pushed front, apply() modifies this. + recent_signers: VecDeque
, + /// inturn signing should wait until this time + pub next_timestamp_inturn: Option, + /// noturn signing should wait until this time + pub next_timestamp_noturn: Option, +} + +#[cfg(test)] +#[derive(Clone, Debug, Default)] +pub struct CliqueBlockState { + /// All recorded votes for a given signer, `Vec` is a stack of votes + pub votes: HashMap, + /// A list of all votes for the given epoch + pub votes_history: Vec, + /// a list of all valid signer, sorted by ascending order. + pub signers: BTreeSet
, + /// a deque of recent signer, new entry should be pushed front, apply() modifies this. + pub recent_signers: VecDeque
, + /// inturn signing should wait until this time + pub next_timestamp_inturn: Option, + /// noturn signing should wait until this time + pub next_timestamp_noturn: Option, +} + +impl fmt::Display for CliqueBlockState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let signers: Vec = self.signers.iter() + .map(|s| + format!("{} {:?}", + s, + self.votes.iter().map(|(v, s)| format!("[beneficiary {}, votes: {}]", v.beneficiary, s.votes)) + .collect::>() + ) + ) + .collect(); + + let recent_signers: Vec = self.recent_signers.iter().map(|s| format!("{}", s)).collect(); + let num_votes = self.votes_history.len(); + let add_votes = self.votes_history.iter().filter(|v| v.kind == VoteType::Add).count(); + let rm_votes = self.votes_history.iter().filter(|v| v.kind == VoteType::Remove).count(); + let reverted_votes = self.votes_history.iter().filter(|v| v.reverted).count(); + + write!(f, + "Votes {{ \n signers: {:?} \n recent_signers: {:?} \n number of votes: {} \n number of add votes {} + \r number of remove votes {} \n number of reverted votes: {}}}", + signers, recent_signers, num_votes, add_votes, rm_votes, reverted_votes) + } +} + +impl CliqueBlockState { + /// Create new state with given information, this is used creating new state from Checkpoint block. + pub fn new(signers: BTreeSet
) -> Self { + CliqueBlockState { + signers, + ..Default::default() + } + } + + // see https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L474 + fn verify(&self, header: &Header) -> Result { + let creator = recover_creator(header)?.clone(); + + // The signer is not authorized + if !self.signers.contains(&creator) { + trace!(target: "engine", "current state: {}", self); + Err(EngineError::NotAuthorized(creator))? + } + + // The signer has signed a block too recently + if self.recent_signers.contains(&creator) { + trace!(target: "engine", "current state: {}", self); + Err(EngineError::CliqueTooRecentlySigned(creator))? + } + + // Wrong difficulty + let inturn = self.is_inturn(header.number(), &creator); + + if inturn && *header.difficulty() != DIFF_INTURN { + Err(BlockError::InvalidDifficulty(Mismatch { + expected: DIFF_INTURN, + found: *header.difficulty(), + }))? + } + + if !inturn && *header.difficulty() != DIFF_NOTURN { + Err(BlockError::InvalidDifficulty(Mismatch { + expected: DIFF_NOTURN, + found: *header.difficulty(), + }))? + } + + Ok(creator) + } + + /// Verify and apply a new header to current state + pub fn apply(&mut self, header: &Header, is_checkpoint: bool) -> Result { + let creator = self.verify(header)?; + self.recent_signers.push_front(creator); + self.rotate_recent_signers(); + + if is_checkpoint { + // checkpoint block should not affect previous tallying, so we check that. + let signers = extract_signers(header)?; + if self.signers != signers { + let invalid_signers: Vec = signers.into_iter() + .filter(|s| !self.signers.contains(s)) + .map(|s| format!("{}", s)) + .collect(); + Err(EngineError::CliqueFaultyRecoveredSigners(invalid_signers))? + }; + + // TODO(niklasad1): I'm not sure if we should shrink here because it is likely that next epoch + // will need some memory and might be better for allocation algorithm to decide whether to shrink or not + // (typically doubles or halves the allocted memory when necessary) + self.votes.clear(); + self.votes_history.clear(); + self.votes.shrink_to_fit(); + self.votes_history.shrink_to_fit(); + } + + // Contains vote + if *header.author() != NULL_AUTHOR { + let decoded_seal = header.decode_seal::>()?; + if decoded_seal.len() != 2 { + Err(BlockError::InvalidSealArity(Mismatch { expected: 2, found: decoded_seal.len() }))? + } + + let nonce: H64 = decoded_seal[1].into(); + self.update_signers_on_vote(VoteType::from_nonce(nonce)?, creator, *header.author(), header.number())?; + } + + Ok(creator) + } + + fn update_signers_on_vote( + &mut self, + kind: VoteType, + signer: Address, + beneficiary: Address, + block_number: u64 + ) -> Result<(), Error> { + + trace!(target: "engine", "Attempt vote {:?} {:?}", kind, beneficiary); + + let pending_vote = PendingVote { signer, beneficiary }; + + let reverted = if self.is_valid_vote(&beneficiary, kind) { + self.add_vote(pending_vote, kind) + } else { + // This case only happens if a `signer` wants to revert their previous vote + // (does nothing if no previous vote was found) + self.revert_vote(pending_vote) + }; + + // Add all votes to the history + self.votes_history.push( + Vote { + block_number, + beneficiary, + kind, + signer, + reverted, + }); + + // If no vote was found for the beneficiary return `early` but don't propogate an error + let (votes, vote_kind) = match self.get_current_votes_and_kind(beneficiary) { + Some((v, k)) => (v, k), + None => return Ok(()), + }; + let threshold = self.signers.len() / 2; + + debug!(target: "engine", "{}/{} votes to have consensus", votes, threshold + 1); + trace!(target: "engine", "votes: {:?}", votes); + + if votes > threshold { + match vote_kind { + VoteType::Add => { + if self.signers.insert(beneficiary) { + debug!(target: "engine", "added new signer: {}", beneficiary); + } + } + VoteType::Remove => { + if self.signers.remove(&beneficiary) { + debug!(target: "engine", "removed signer: {}", beneficiary); + } + } + } + + self.rotate_recent_signers(); + self.remove_all_votes_from(beneficiary); + } + + Ok(()) + } + + /// Calculate the next timestamp for `inturn` and `noturn` fails if any of them can't be represented as + /// `SystemTime` + // TODO(niklasad1): refactor this method to be in constructor of `CliqueBlockState` instead. + // This is a quite bad API because we must mutate both variables even when already `inturn` fails + // That's why we can't return early and must have the `if-else` in the end + pub fn calc_next_timestamp(&mut self, timestamp: u64, period: u64) -> Result<(), Error> { + let inturn = UNIX_EPOCH.checked_add(Duration::from_secs(timestamp.saturating_add(period))); + + self.next_timestamp_inturn = inturn; + + let delay = Duration::from_millis( + rand::thread_rng().gen_range(0u64, (self.signers.len() as u64 / 2 + 1) * SIGNING_DELAY_NOTURN_MS)); + self.next_timestamp_noturn = inturn.map(|inturn| { + inturn + delay + }); + + if self.next_timestamp_inturn.is_some() && self.next_timestamp_noturn.is_some() { + Ok(()) + } else { + Err(BlockError::TimestampOverflow)? + } + } + + /// Returns true if the block difficulty should be `inturn` + pub fn is_inturn(&self, current_block_number: u64, author: &Address) -> bool { + if let Some(pos) = self.signers.iter().position(|x| *author == *x) { + return current_block_number % self.signers.len() as u64 == pos as u64; + } + false + } + + /// Returns whether the signer is authorized to sign a block + pub fn is_authorized(&self, author: &Address) -> bool { + self.signers.contains(author) && !self.recent_signers.contains(author) + } + + /// Returns whether it makes sense to cast the specified vote in the + /// current state (e.g. don't try to add an already authorized signer). + pub fn is_valid_vote(&self, address: &Address, vote_type: VoteType) -> bool { + let in_signer = self.signers.contains(address); + match vote_type { + VoteType::Add => !in_signer, + VoteType::Remove => in_signer, + } + } + + /// Returns the list of current signers + pub fn signers(&self) -> &BTreeSet
{ + &self.signers + } + + // Note this method will always return `true` but it is intended for a uniform `API` + fn add_vote(&mut self, pending_vote: PendingVote, kind: VoteType) -> bool { + + self.votes.entry(pending_vote) + .and_modify(|state| { + state.votes = state.votes.saturating_add(1); + }) + .or_insert_with(|| VoteState { kind, votes: 1 }); + true + } + + fn revert_vote(&mut self, pending_vote: PendingVote) -> bool { + let mut revert = false; + let mut remove = false; + + self.votes.entry(pending_vote).and_modify(|state| { + if state.votes.saturating_sub(1) == 0 { + remove = true; + } + revert = true; + }); + + if remove { + self.votes.remove(&pending_vote); + } + + revert + } + + fn get_current_votes_and_kind(&self, beneficiary: Address) -> Option<(usize, VoteType)> { + let kind = self.votes.iter() + .find(|(v, _t)| v.beneficiary == beneficiary) + .map(|(_v, t)| t.kind)?; + + let votes = self.votes.keys() + .filter(|vote| vote.beneficiary == beneficiary) + .count(); + + Some((votes, kind)) + } + + fn rotate_recent_signers(&mut self) { + if self.recent_signers.len() >= ( self.signers.len() / 2 ) + 1 { + self.recent_signers.pop_back(); + } + } + + fn remove_all_votes_from(&mut self, beneficiary: Address) { + self.votes = std::mem::replace(&mut self.votes, HashMap::new()) + .into_iter() + .filter(|(v, _t)| v.signer != beneficiary && v.beneficiary != beneficiary) + .collect(); + } +} diff --git a/ethcore/src/engines/clique/mod.rs b/ethcore/src/engines/clique/mod.rs new file mode 100644 index 000000000..f5e83440d --- /dev/null +++ b/ethcore/src/engines/clique/mod.rs @@ -0,0 +1,768 @@ +// Copyright 2015-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 . + +//! Implementation of the Clique PoA Engine. +//! +//! File structure: +//! - mod.rs -> Provides the engine API implementation, with additional block state tracking +//! - block_state.rs -> Records the Clique state for given block. +//! - params.rs -> Contains the parameters for the Clique engine. +//! - step_service.rs -> An event loop to trigger sealing. +//! - util.rs -> Various standalone utility functions. +//! - tests.rs -> Consensus tests as defined in EIP-225. + +/// How syncing works: +/// +/// 1. Client will call: +/// - `Clique::verify_block_basic()` +/// - `Clique::verify_block_unordered()` +/// - `Clique::verify_block_family()` +/// 2. Using `Clique::state()` we try and retrieve the parent state. If this isn't found +/// we need to back-fill it from the last known checkpoint. +/// 3. Once we have a good state, we can record it using `CliqueBlockState::apply()`. + +/// How sealing works: +/// +/// 1. Set a signer using `Engine::set_signer()`. If a miner account was set up through +/// a config file or CLI flag `MinerService::set_author()` will eventually set the signer +/// 2. We check that the engine seals internally through `Clique::seals_internally()` +/// Note: This is always true for Clique +/// 3. Calling `Clique::new()` will spawn a `StepService` thread. This thread will call `Engine::step()` +/// periodically. Internally, the Clique `step()` function calls `Client::update_sealing()`, which is +/// what makes and seals a block. +/// 4. `Clique::generate_seal()` will then be called by `miner`. This will return a `Seal` which +/// is either a `Seal::None` or `Seal:Regular`. The following shows how a `Seal` variant is chosen: +/// a. We return `Seal::None` if no signer is available or the signer is not authorized. +/// b. If period == 0 and block has transactions, we return `Seal::Regular`, otherwise return `Seal::None`. +/// c. If we're `INTURN`, wait for at least `period` since last block before trying to seal. +/// d. If we're not `INTURN`, we wait for a random amount of time using the algorithm specified +/// in EIP-225 before trying to seal again. +/// 5. Miner will create new block, in process it will call several engine methods to do following: +/// a. `Clique::open_block_header_timestamp()` must set timestamp correctly. +/// b. `Clique::populate_from_parent()` must set difficulty to correct value. +/// Note: `Clique::populate_from_parent()` is used in both the syncing and sealing code paths. +/// 6. We call `Clique::on_seal_block()` which will allow us to modify the block header during seal generation. +/// 7. Finally, `Clique::verify_local_seal()` is called. After this, the syncing code path will be followed +/// in order to import the new block. + +use std::cmp; +use std::collections::HashMap; +use std::collections::VecDeque; +use std::sync::{Arc, Weak}; +use std::thread; +use std::time; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +use block::ExecutedBlock; +use client::{BlockId, EngineClient}; +use engines::clique::util::{extract_signers, recover_creator}; +use engines::{Engine, EngineError, Seal}; +use error::{BlockError, Error}; +use ethereum_types::{Address, H64, H160, H256, U256}; +use ethkey::Signature; +use hash::KECCAK_EMPTY_LIST_RLP; +use itertools::Itertools; +use lru_cache::LruCache; +use machine::{Call, EthereumMachine}; +use parking_lot::RwLock; +use rand::Rng; +use super::signer::EngineSigner; +use unexpected::{Mismatch, OutOfBounds}; +use types::BlockNumber; +use types::header::{ExtendedHeader, Header}; + +#[cfg(not(feature = "time_checked_add"))] +use time_utils::CheckedSystemTime; + +use self::block_state::CliqueBlockState; +use self::params::CliqueParams; +use self::step_service::StepService; + +mod params; +mod block_state; +mod step_service; +mod util; + +// TODO(niklasad1): extract tester types into a separate mod to be shared in the code base +#[cfg(test)] +mod tests; + +// Protocol constants +/// Fixed number of extra-data prefix bytes reserved for signer vanity +pub const VANITY_LENGTH: usize = 32; +/// Fixed number of extra-data suffix bytes reserved for signer signature +pub const SIGNATURE_LENGTH: usize = 65; +/// Address length of signer +pub const ADDRESS_LENGTH: usize = 20; +/// Nonce value for DROP vote +pub const NONCE_DROP_VOTE: H64 = H64([0; 8]); +/// Nonce value for AUTH vote +pub const NONCE_AUTH_VOTE: H64 = H64([0xff; 8]); +/// Difficulty for INTURN block +pub const DIFF_INTURN: U256 = U256([2, 0, 0, 0]); +/// Difficulty for NOTURN block +pub const DIFF_NOTURN: U256 = U256([1, 0, 0, 0]); +/// Default empty author field value +pub const NULL_AUTHOR: Address = H160([0x00; 20]); +/// Default empty nonce value +pub const NULL_NONCE: H64 = NONCE_DROP_VOTE; +/// Default value for mixhash +pub const NULL_MIXHASH: H256 = H256([0; 32]); +/// Default value for uncles hash +pub const NULL_UNCLES_HASH: H256 = KECCAK_EMPTY_LIST_RLP; +/// Default noturn block wiggle factor defined in spec. +pub const SIGNING_DELAY_NOTURN_MS: u64 = 500; + +/// How many CliqueBlockState to cache in the memory. +pub const STATE_CACHE_NUM: usize = 128; + +/// Vote to add or remove the beneficiary +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub enum VoteType { + Add, + Remove, +} + +impl VoteType { + /// Try to construct a `Vote` from a nonce + pub fn from_nonce(nonce: H64) -> Result { + if nonce == NONCE_AUTH_VOTE { + Ok(VoteType::Add) + } else if nonce == NONCE_DROP_VOTE { + Ok(VoteType::Remove) + } else { + Err(EngineError::CliqueInvalidNonce(nonce))? + } + } + + /// Get the rlp encoding of the vote + pub fn as_rlp(&self) -> Vec> { + match self { + VoteType::Add => vec![rlp::encode(&NULL_MIXHASH), rlp::encode(&NONCE_AUTH_VOTE)], + VoteType::Remove => vec![rlp::encode(&NULL_MIXHASH), rlp::encode(&NONCE_DROP_VOTE)], + } + } +} + +/// Clique Engine implementation +// block_state_by_hash -> block state indexed by header hash. +#[cfg(not(test))] +pub struct Clique { + epoch_length: u64, + period: u64, + machine: EthereumMachine, + client: RwLock>>, + block_state_by_hash: RwLock>, + proposals: RwLock>, + signer: RwLock>>, + step_service: Option>, +} + +#[cfg(test)] +/// Test version of `CliqueEngine` to make all fields public +pub struct Clique { + pub epoch_length: u64, + pub period: u64, + pub machine: EthereumMachine, + pub client: RwLock>>, + pub block_state_by_hash: RwLock>, + pub proposals: RwLock>, + pub signer: RwLock>>, + pub step_service: Option>, +} + +impl Clique { + /// Initialize Clique engine from empty state. + pub fn new(our_params: CliqueParams, machine: EthereumMachine) -> Result, Error> { + let mut engine = Clique { + epoch_length: our_params.epoch, + period: our_params.period, + client: Default::default(), + block_state_by_hash: RwLock::new(LruCache::new(STATE_CACHE_NUM)), + proposals: Default::default(), + signer: Default::default(), + machine, + step_service: None, + }; + + let res = Arc::new(engine); + + if our_params.period > 0 { + engine.step_service = Some(StepService::start(Arc::downgrade(&res) as Weak>)); + } + + Ok(res) + } + + #[cfg(test)] + /// Initialize test variant of `CliqueEngine`, + /// Note we need to `mock` the miner and it is introduced to test block verification to trigger new blocks + /// to mainly test consensus edge cases + pub fn with_test(epoch_length: u64, period: u64) -> Self { + use spec::Spec; + + Self { + epoch_length, + period, + client: Default::default(), + block_state_by_hash: RwLock::new(LruCache::new(STATE_CACHE_NUM)), + proposals: Default::default(), + signer: Default::default(), + machine: Spec::new_test_machine(), + step_service: None, + } + } + + fn sign_header(&self, header: &Header) -> Result<(Signature, H256), Error> { + + match self.signer.read().as_ref() { + None => { + Err(EngineError::RequiresSigner)? + } + Some(signer) => { + let digest = header.hash(); + match signer.sign(digest) { + Ok(sig) => Ok((sig, digest)), + Err(e) => Err(EngineError::Custom(e.into()))?, + } + } + } + } + + /// Construct an new state from given checkpoint header. + fn new_checkpoint_state(&self, header: &Header) -> Result { + debug_assert_eq!(header.number() % self.epoch_length, 0); + + let mut state = CliqueBlockState::new( + extract_signers(header)?); + + // TODO(niklasad1): refactor to perform this check in the `CliqueBlockState` constructor instead + state.calc_next_timestamp(header.timestamp(), self.period)?; + + Ok(state) + } + + fn state_no_backfill(&self, hash: &H256) -> Option { + self.block_state_by_hash.write().get_mut(hash).cloned() + } + + /// Get `CliqueBlockState` for given header, backfill from last checkpoint if needed. + fn state(&self, header: &Header) -> Result { + let mut block_state_by_hash = self.block_state_by_hash.write(); + if let Some(state) = block_state_by_hash.get_mut(&header.hash()) { + return Ok(state.clone()); + } + // If we are looking for an checkpoint block state, we can directly reconstruct it. + if header.number() % self.epoch_length == 0 { + let state = self.new_checkpoint_state(header)?; + block_state_by_hash.insert(header.hash(), state.clone()); + return Ok(state); + } + // BlockState is not found in memory, which means we need to reconstruct state from last checkpoint. + match self.client.read().as_ref().and_then(|w| w.upgrade()) { + None => { + return Err(EngineError::RequiresClient)?; + } + Some(c) => { + let last_checkpoint_number = header.number() - header.number() % self.epoch_length as u64; + debug_assert_ne!(last_checkpoint_number, header.number()); + + let mut chain: &mut VecDeque
= &mut VecDeque::with_capacity( + (header.number() - last_checkpoint_number + 1) as usize); + + // Put ourselves in. + chain.push_front(header.clone()); + + // populate chain to last checkpoint + loop { + let (last_parent_hash, last_num) = { + let l = chain.front().expect("chain has at least one element; qed"); + (*l.parent_hash(), l.number()) + }; + + if last_num == last_checkpoint_number + 1 { + break; + } + match c.block_header(BlockId::Hash(last_parent_hash)) { + None => { + return Err(BlockError::UnknownParent(last_parent_hash))?; + } + Some(next) => { + chain.push_front(next.decode()?); + } + } + } + + // Catching up state, note that we don't really store block state for intermediary blocks, + // for speed. + let backfill_start = time::Instant::now(); + trace!(target: "engine", + "Back-filling block state. last_checkpoint_number: {}, target: {}({}).", + last_checkpoint_number, header.number(), header.hash()); + + // Get the state for last checkpoint. + let last_checkpoint_hash = *chain.front() + .expect("chain has at least one element; qed") + .parent_hash(); + + let last_checkpoint_header = match c.block_header(BlockId::Hash(last_checkpoint_hash)) { + None => return Err(EngineError::CliqueMissingCheckpoint(last_checkpoint_hash))?, + Some(header) => header.decode()?, + }; + + let last_checkpoint_state = match block_state_by_hash.get_mut(&last_checkpoint_hash) { + Some(state) => state.clone(), + None => self.new_checkpoint_state(&last_checkpoint_header)?, + }; + + block_state_by_hash.insert(last_checkpoint_header.hash(), last_checkpoint_state.clone()); + + // Backfill! + let mut new_state = last_checkpoint_state.clone(); + for item in chain { + new_state.apply(item, false)?; + } + new_state.calc_next_timestamp(header.timestamp(), self.period)?; + block_state_by_hash.insert(header.hash(), new_state.clone()); + + let elapsed = backfill_start.elapsed(); + trace!(target: "engine", "Back-filling succeed, took {} ms.", elapsed.as_millis()); + Ok(new_state) + } + } + } +} + +impl Engine for Clique { + fn name(&self) -> &str { "Clique" } + + fn machine(&self) -> &EthereumMachine { &self.machine } + + // Clique use same fields, nonce + mixHash + fn seal_fields(&self, _header: &Header) -> usize { 2 } + + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 } + + fn on_new_block( + &self, + _block: &mut ExecutedBlock, + _epoch_begin: bool, + _ancestry: &mut Iterator, + ) -> Result<(), Error> { + Ok(()) + } + + // Clique has no block reward. + fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> { + Ok(()) + } + + fn on_seal_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { + trace!(target: "engine", "on_seal_block"); + + let header = &mut block.header; + + let state = self.state_no_backfill(header.parent_hash()) + .ok_or_else(|| BlockError::UnknownParent(*header.parent_hash()))?; + + let is_checkpoint = header.number() % self.epoch_length == 0; + + header.set_author(NULL_AUTHOR); + + // Cast a random Vote if not checkpoint + if !is_checkpoint { + // TODO(niklasad1): this will always be false because `proposals` is never written to + let votes = self.proposals.read().iter() + .filter(|(address, vote_type)| state.is_valid_vote(*address, **vote_type)) + .map(|(address, vote_type)| (*address, *vote_type)) + .collect_vec(); + + if !votes.is_empty() { + // Pick a random vote. + let random_vote = rand::thread_rng().gen_range(0 as usize, votes.len()); + let (beneficiary, vote_type) = votes[random_vote]; + + trace!(target: "engine", "Casting vote: beneficiary {}, type {:?} ", beneficiary, vote_type); + + header.set_author(beneficiary); + header.set_seal(vote_type.as_rlp()); + } + } + + // Work on clique seal. + + let mut seal: Vec = Vec::with_capacity(VANITY_LENGTH + SIGNATURE_LENGTH); + + // At this point, extra_data should only contain miner vanity. + if header.extra_data().len() != VANITY_LENGTH { + Err(BlockError::ExtraDataOutOfBounds(OutOfBounds { + min: Some(VANITY_LENGTH), + max: Some(VANITY_LENGTH), + found: header.extra_data().len() + }))?; + } + // vanity + { + seal.extend_from_slice(&header.extra_data()[0..VANITY_LENGTH]); + } + + // If we are building an checkpoint block, add all signers now. + if is_checkpoint { + seal.reserve(state.signers().len() * 20); + state.signers().iter().foreach(|addr| { + seal.extend_from_slice(&addr[..]); + }); + } + + header.set_extra_data(seal.clone()); + + // append signature onto extra_data + let (sig, _msg) = self.sign_header(&header)?; + seal.extend_from_slice(&sig[..]); + header.set_extra_data(seal.clone()); + + header.compute_hash(); + + // locally sealed block don't go through valid_block_family(), so we have to record state here. + let mut new_state = state.clone(); + new_state.apply(&header, is_checkpoint)?; + new_state.calc_next_timestamp(header.timestamp(), self.period)?; + self.block_state_by_hash.write().insert(header.hash(), new_state); + + trace!(target: "engine", "on_seal_block: finished, final header: {:?}", header); + + Ok(()) + } + + /// Clique doesn't require external work to seal, so we always return true here. + fn seals_internally(&self) -> Option { + Some(true) + } + + /// Returns if we are ready to seal, the real sealing (signing extra_data) is actually done in `on_seal_block()`. + fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal { + trace!(target: "engine", "tried to generate_seal"); + let null_seal = util::null_seal(); + + if block.header.number() == 0 { + trace!(target: "engine", "attempted to seal genesis block"); + return Seal::None; + } + + // if sealing period is 0, and not an checkpoint block, refuse to seal + if self.period == 0 { + if block.transactions.is_empty() && block.header.number() % self.epoch_length != 0 { + return Seal::None; + } + return Seal::Regular(null_seal); + } + + // Check we actually have authority to seal. + if let Some(author) = self.signer.read().as_ref().map(|x| x.address()) { + + // ensure the voting state exists + match self.state(&parent) { + Err(e) => { + warn!(target: "engine", "generate_seal: can't get parent state(number: {}, hash: {}): {} ", + parent.number(), parent.hash(), e); + return Seal::None; + } + Ok(state) => { + // Are we authorized to seal? + if !state.is_authorized(&author) { + trace!(target: "engine", "generate_seal: Not authorized to sign right now."); + // wait for one third of period to try again. + thread::sleep(Duration::from_secs(self.period / 3 + 1)); + return Seal::None; + } + + let inturn = state.is_inturn(block.header.number(), &author); + + let now = SystemTime::now(); + + let limit = match inturn { + true => state.next_timestamp_inturn.unwrap_or(now), + false => state.next_timestamp_noturn.unwrap_or(now), + }; + + // Wait for the right moment. + if now < limit { + trace!(target: "engine", + "generate_seal: sleeping to sign: inturn: {}, now: {:?}, to: {:?}.", + inturn, now, limit); + match limit.duration_since(SystemTime::now()) { + Ok(duration) => { + thread::sleep(duration); + }, + Err(e) => { + warn!(target:"engine", "generate_seal: unable to sleep, err: {}", e); + return Seal::None; + } + } + } + + trace!(target: "engine", "generate_seal: seal ready for block {}, txs: {}.", + block.header.number(), block.transactions.len()); + return Seal::Regular(null_seal); + } + } + } + Seal::None + } + + fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> { Ok(()) } + + fn verify_block_basic(&self, header: &Header) -> Result<(), Error> { + // Largely same as https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L275 + + // Ignore genesis block. + if header.number() == 0 { + return Ok(()); + } + + // Don't waste time checking blocks from the future + { + let limit = SystemTime::now().checked_add(Duration::from_secs(self.period)) + .ok_or(BlockError::TimestampOverflow)?; + + // This should succeed under the contraints that the system clock works + let limit_as_dur = limit.duration_since(UNIX_EPOCH).map_err(|e| { + Box::new(format!("Converting SystemTime to Duration failed: {}", e)) + })?; + + let hdr = Duration::from_secs(header.timestamp()); + if hdr > limit_as_dur { + let found = UNIX_EPOCH.checked_add(hdr).ok_or(BlockError::TimestampOverflow)?; + + Err(BlockError::TemporarilyInvalid(OutOfBounds { + min: None, + max: Some(limit), + found, + }))? + } + } + + let is_checkpoint = header.number() % self.epoch_length == 0; + + if is_checkpoint && *header.author() != NULL_AUTHOR { + return Err(EngineError::CliqueWrongAuthorCheckpoint(Mismatch { + expected: 0.into(), + found: *header.author(), + }))?; + } + + let seal_fields = header.decode_seal::>()?; + if seal_fields.len() != 2 { + Err(BlockError::InvalidSealArity(Mismatch { + expected: 2, + found: seal_fields.len(), + }))? + } + + let mixhash: H256 = seal_fields[0].into(); + let nonce: H64 = seal_fields[1].into(); + + // Nonce must be 0x00..0 or 0xff..f + if nonce != NONCE_DROP_VOTE && nonce != NONCE_AUTH_VOTE { + Err(EngineError::CliqueInvalidNonce(nonce))?; + } + + if is_checkpoint && nonce != NULL_NONCE { + Err(EngineError::CliqueInvalidNonce(nonce))?; + } + + // Ensure that the mix digest is zero as Clique don't have fork protection currently + if mixhash != NULL_MIXHASH { + Err(BlockError::MismatchedH256SealElement(Mismatch { + expected: NULL_MIXHASH, + found: mixhash, + }))? + } + + let extra_data_len = header.extra_data().len(); + + if extra_data_len < VANITY_LENGTH { + Err(EngineError::CliqueMissingVanity)? + } + + if extra_data_len < VANITY_LENGTH + SIGNATURE_LENGTH { + Err(EngineError::CliqueMissingSignature)? + } + + let signers = extra_data_len - (VANITY_LENGTH + SIGNATURE_LENGTH); + + // Checkpoint blocks must at least contain one signer + if is_checkpoint && signers == 0 { + Err(EngineError::CliqueCheckpointNoSigner)? + } + + // Addresses must be be divisable by 20 + if is_checkpoint && signers % ADDRESS_LENGTH != 0 { + Err(EngineError::CliqueCheckpointInvalidSigners(signers))? + } + + // Ensure that the block doesn't contain any uncles which are meaningless in PoA + if *header.uncles_hash() != NULL_UNCLES_HASH { + Err(BlockError::InvalidUnclesHash(Mismatch { + expected: NULL_UNCLES_HASH, + found: *header.uncles_hash(), + }))? + } + + // Ensure that the block's difficulty is meaningful (may not be correct at this point) + if *header.difficulty() != DIFF_INTURN && *header.difficulty() != DIFF_NOTURN { + Err(BlockError::DifficultyOutOfBounds(OutOfBounds { + min: Some(DIFF_NOTURN), + max: Some(DIFF_INTURN), + found: *header.difficulty(), + }))? + } + + // All basic checks passed, continue to next phase + Ok(()) + } + + fn verify_block_unordered(&self, _header: &Header) -> Result<(), Error> { + // Nothing to check here. + Ok(()) + } + + /// Verify block family by looking up parent state (backfill if needed), then try to apply current header. + /// see https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L338 + fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> { + // Ignore genesis block. + if header.number() == 0 { + return Ok(()); + } + + // parent sanity check + if parent.hash() != *header.parent_hash() || header.number() != parent.number() + 1 { + Err(BlockError::UnknownParent(parent.hash()))? + } + + // Ensure that the block's timestamp isn't too close to it's parent + let limit = parent.timestamp().saturating_add(self.period); + if limit > header.timestamp() { + let max = UNIX_EPOCH.checked_add(Duration::from_secs(header.timestamp())); + let found = UNIX_EPOCH.checked_add(Duration::from_secs(limit)) + .ok_or(BlockError::TimestampOverflow)?; + + Err(BlockError::InvalidTimestamp(OutOfBounds { + min: None, + max, + found, + }))? + } + + // Retrieve the parent state + let parent_state = self.state(&parent)?; + // Try to apply current state, apply() will further check signer and recent signer. + let mut new_state = parent_state.clone(); + new_state.apply(header, header.number() % self.epoch_length == 0)?; + new_state.calc_next_timestamp(header.timestamp(), self.period)?; + self.block_state_by_hash.write().insert(header.hash(), new_state); + + Ok(()) + } + + fn genesis_epoch_data(&self, header: &Header, _call: &Call) -> Result, String> { + let mut state = self.new_checkpoint_state(header).expect("Unable to parse genesis data."); + state.calc_next_timestamp(header.timestamp(), self.period).map_err(|e| format!("{}", e))?; + self.block_state_by_hash.write().insert(header.hash(), state); + + // no proof. + Ok(Vec::new()) + } + + // Our task here is to set difficulty + fn populate_from_parent(&self, header: &mut Header, parent: &Header) { + // TODO(https://github.com/paritytech/parity-ethereum/issues/10410): this is a horrible hack, + // it is due to the fact that enact and miner both use OpenBlock::new() which will both call + // this function. more refactoring is definitely needed. + if header.extra_data().len() < VANITY_LENGTH + SIGNATURE_LENGTH { + trace!(target: "engine", "populate_from_parent in sealing"); + + // It's unclear how to prevent creating new blocks unless we are authorized, the best way (and geth does this too) + // it's just to ignore setting an correct difficulty here, we will check authorization in next step in generate_seal anyway. + if let Some(signer) = self.signer.read().as_ref() { + let state = match self.state(&parent) { + Err(e) => { + trace!(target: "engine", "populate_from_parent: Unable to find parent state: {}, ignored.", e); + return; + } + Ok(state) => state, + }; + + if state.is_authorized(&signer.address()) { + if state.is_inturn(header.number(), &signer.address()) { + header.set_difficulty(DIFF_INTURN); + } else { + header.set_difficulty(DIFF_NOTURN); + } + } + } else { + trace!(target: "engine", "populate_from_parent: no signer registered"); + } + } + } + + fn set_signer(&self, signer: Box) { + trace!(target: "engine", "set_signer: {}", signer.address()); + *self.signer.write() = Some(signer); + } + + fn register_client(&self, client: Weak) { + *self.client.write() = Some(client.clone()); + } + + fn step(&self) { + if self.signer.read().is_some() { + if let Some(ref weak) = *self.client.read() { + if let Some(c) = weak.upgrade() { + c.update_sealing(); + } + } + } + } + + fn stop(&mut self) { + if let Some(mut s) = self.step_service.as_mut() { + Arc::get_mut(&mut s).map(|x| x.stop()); + } else { + warn!(target: "engine", "Stopping `CliqueStepService` failed requires mutable access"); + } + } + + /// Clique timestamp is set to parent + period , or current time which ever is higher. + fn open_block_header_timestamp(&self, parent_timestamp: u64) -> u64 { + let now = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap_or_default(); + cmp::max(now.as_secs() as u64, parent_timestamp.saturating_add(self.period)) + } + + fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { + header_timestamp >= parent_timestamp.saturating_add(self.period) + } + + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + super::total_difficulty_fork_choice(new, current) + } + + // Clique uses the author field for voting, the real author is hidden in the `extra_data` field. + // So when executing tx's (like in `enact()`) we want to use the executive author + fn executive_author(&self, header: &Header) -> Result { + recover_creator(header) + } +} diff --git a/ethcore/src/engines/clique/params.rs b/ethcore/src/engines/clique/params.rs new file mode 100644 index 000000000..e24edfcba --- /dev/null +++ b/ethcore/src/engines/clique/params.rs @@ -0,0 +1,41 @@ +// Copyright 2015-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 . + +//! Clique specific parameters. + +use ethjson; + +/// `Clique` params. +pub struct CliqueParams { + /// Period as defined in EIP + pub period: u64, + /// Epoch length as defined in EIP + pub epoch: u64, +} + +impl From for CliqueParams { + fn from(p: ethjson::spec::CliqueParams) -> Self { + let period = p.period.map_or_else(|| 30000 as u64, Into::into); + let epoch = p.epoch.map_or_else(|| 15 as u64, Into::into); + + assert!(epoch > 0); + + CliqueParams { + period, + epoch, + } + } +} diff --git a/ethcore/src/engines/clique/step_service.rs b/ethcore/src/engines/clique/step_service.rs new file mode 100644 index 000000000..7a4b5269d --- /dev/null +++ b/ethcore/src/engines/clique/step_service.rs @@ -0,0 +1,77 @@ +// Copyright 2015-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 . + + +use std::sync::Weak; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Duration; +use std::thread; +use std::sync::Arc; + +use engines::Engine; +use machine::Machine; + +/// Service that is managing the engine +pub struct StepService { + shutdown: Arc, + thread: Option>, +} + +impl StepService { + /// Start the `StepService` + pub fn start(engine: Weak>) -> Arc { + let shutdown = Arc::new(AtomicBool::new(false)); + let s = shutdown.clone(); + + let thread = thread::Builder::new() + .name("CliqueStepService".into()) + .spawn(move || { + // startup delay. + thread::sleep(Duration::from_secs(5)); + + loop { + // see if we are in shutdown. + if shutdown.load(Ordering::Acquire) { + trace!(target: "miner", "CliqueStepService: received shutdown signal!"); + break; + } + + trace!(target: "miner", "CliqueStepService: triggering sealing"); + + // Try sealing + engine.upgrade().map(|x| x.step()); + + // Yield + thread::sleep(Duration::from_millis(2000)); + } + trace!(target: "miner", "CliqueStepService: shutdown."); + }).expect("CliqueStepService thread failed"); + + Arc::new(StepService { + shutdown: s, + thread: Some(thread), + }) + } + + /// Stop the `StepService` + pub fn stop(&mut self) { + trace!(target: "miner", "CliqueStepService: shutting down."); + self.shutdown.store(true, Ordering::Release); + if let Some(t) = self.thread.take() { + t.join().expect("CliqueStepService thread panicked!"); + } + } +} diff --git a/ethcore/src/engines/clique/tests.rs b/ethcore/src/engines/clique/tests.rs new file mode 100644 index 000000000..c7916192d --- /dev/null +++ b/ethcore/src/engines/clique/tests.rs @@ -0,0 +1,804 @@ +// Copyright 2015-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 . + +//! Consensus tests for `PoA Clique Engine`, see http://eips.ethereum.org/EIPS/eip-225 for more information + +use block::*; +use engines::Engine; +use error::{Error, ErrorKind}; +use ethereum_types::{Address, H256}; +use ethkey::{Secret, KeyPair}; +use state_db::StateDB; +use super::*; +use test_helpers::get_temp_state_db; + +use std::sync::Arc; +use std::collections::HashMap; + +/// Possible signers +pub const SIGNER_TAGS: [char; 6] = ['A', 'B', 'C', 'D', 'E', 'F']; + +/// Clique block types +pub enum CliqueBlockType { + /// Epoch transition block must contain list of signers + Checkpoint, + /// Block with no votes + Empty, + /// Vote + Vote(VoteType), +} + +/// Clique tester +pub struct CliqueTester { + /// Mocked Clique + pub clique: Clique, + /// Mocked genesis state + pub genesis: Header, + /// StateDB + pub db: StateDB, + /// List of signers + pub signers: HashMap, +} + +impl CliqueTester { + /// Create a `Clique` tester with settings + pub fn with(epoch: u64, period: u64, initial_signers: Vec) -> Self { + assert_eq!(initial_signers.iter().all(|s| SIGNER_TAGS.contains(s)), true, + "Not all the initial signers is in SIGNER_TAGS, possible keys are 'A' ..= 'F'"); + + let clique = Clique::with_test(epoch, period); + let mut genesis = Header::default(); + let mut signers = HashMap::new(); + + let call = |_a, _b| { + unimplemented!("Clique doesn't use Engine::Call"); + }; + + let mut extra_data = vec![0; VANITY_LENGTH]; + + for &signer in SIGNER_TAGS.iter() { + let secret = Secret::from(H256::from(signer as u64)); + let keypair = KeyPair::from_secret(secret).unwrap(); + if initial_signers.contains(&signer) { + extra_data.extend(&*keypair.address()); + } + signers.insert(signer, keypair); + } + + // append dummy signature + extra_data.extend(std::iter::repeat(0).take(SIGNATURE_LENGTH)); + + genesis.set_extra_data(extra_data); + genesis.set_gas_limit(U256::from(0xa00000)); + genesis.set_difficulty(U256::from(1)); + genesis.set_seal(util::null_seal()); + + clique.genesis_epoch_data(&genesis, &call).expect("Create genesis failed"); + Self {clique, genesis, db: get_temp_state_db(), signers} + } + + /// Get difficulty for a given block + pub fn get_difficulty(&self, block_num: BlockNumber, header: &Header, signer: &Address) -> U256 { + let state = self.clique.state(header).unwrap(); + if state.is_inturn(block_num, signer) { + DIFF_INTURN + } else { + DIFF_NOTURN + } + } + + /// Get the state of a given block + // Note, this will read the cache and `will` not work with more than 128 blocks + pub fn get_state_at_block(&self, hash: &H256) -> CliqueBlockState { + self.clique.block_state_by_hash.write() + .get_mut(hash) + .expect("CliqueBlockState not found tested failed") + .clone() + } + + /// Get signers after a certain state + // This is generally used to fetch the state after a test has been executed and checked against + // the intial list of signers provided in the test + pub fn clique_signers(&self, hash: &H256) -> impl Iterator { + self.get_state_at_block(hash).signers().clone().into_iter() + } + + /// Fetches all addresses at current `block` and converts them back to `tags (char)` and sorts them + /// Addresses are supposed sorted based on address but these tests are using `tags` just for simplicity + /// and the order is not important! + pub fn into_tags>(&self, addr: T) -> Vec { + let mut tags: Vec = addr.filter_map(|addr| { + for (t, kp) in self.signers.iter() { + if addr == kp.address() { + return Some(*t) + } + } + None + }) + .collect(); + + tags.sort(); + tags + } + + /// Create a new `Clique` block and import + pub fn new_block_and_import( + &self, + block_type: CliqueBlockType, + last_header: &Header, + beneficary: Option
, + signer: char, + ) -> Result { + + let mut extra_data = vec![0; VANITY_LENGTH]; + let mut seal = util::null_seal(); + let last_hash = last_header.hash(); + + match block_type { + CliqueBlockType::Checkpoint => { + let signers = self.clique.state(&last_header).unwrap().signers().clone(); + for signer in signers { + extra_data.extend(&*signer); + } + } + CliqueBlockType::Vote(v) => seal = v.as_rlp(), + CliqueBlockType::Empty => (), + }; + + let db = self.db.boxed_clone(); + + let mut block = OpenBlock::new( + &self.clique, + Default::default(), + false, + db, + &last_header.clone(), + Arc::new(vec![last_hash]), + beneficary.unwrap_or_default(), + (3141562.into(), 31415620.into()), + extra_data, + false, + None, + ).unwrap(); + + { + let difficulty = self.get_difficulty(block.header.number(), last_header, &self.signers[&signer].address()); + let b = block.block_mut(); + b.header.set_timestamp(last_header.timestamp() + self.clique.period); + b.header.set_difficulty(difficulty); + b.header.set_seal(seal); + + let sign = ethkey::sign(self.signers[&signer].secret(), &b.header.hash()).unwrap(); + let mut extra_data = b.header.extra_data().clone(); + extra_data.extend_from_slice(&*sign); + b.header.set_extra_data(extra_data); + } + + let current_header = &block.header; + self.clique.verify_block_basic(current_header)?; + self.clique.verify_block_family(current_header, &last_header)?; + + Ok(current_header.clone()) + } +} + +#[test] +fn one_signer_with_no_votes() { + let tester = CliqueTester::with(10, 1, vec!['A']); + + let empty_block = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'A').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&empty_block.hash())); + assert_eq!(&tags, &['A']); +} + +#[test] +fn one_signer_two_votes() { + let tester = CliqueTester::with(10, 1, vec!['A']); + + // Add a vote for `B` signed by `A` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis, + Some(tester.signers[&'B'].address()), 'A').unwrap(); + let tags = tester.into_tags(tester.clique_signers(&vote.hash())); + assert_eq!(&tags, &['A', 'B']); + + // Add a empty block signed by `B` + let empty = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap(); + + // Add vote for `C` signed by A but should not be accepted + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &empty, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&vote.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn two_signers_six_votes_deny_last() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B']); + + let mut prev_header = tester.genesis.clone(); + + // Add two votes for `C` signed by `A` and `B` + for &signer in SIGNER_TAGS.iter().take(2) { + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header, + Some(tester.signers[&'C'].address()), signer).unwrap(); + prev_header = vote.clone(); + } + + // Add two votes for `D` signed by `A` and `B` + for &signer in SIGNER_TAGS.iter().take(2) { + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header, + Some(tester.signers[&'D'].address()), signer).unwrap(); + prev_header = vote.clone(); + } + + // Add a empty block signed by `C` + let empty = tester.new_block_and_import(CliqueBlockType::Empty, &prev_header, None, 'C').unwrap(); + prev_header = empty.clone(); + + // Add two votes for `E` signed by `A` and `B` + for &signer in SIGNER_TAGS.iter().take(2) { + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header, + Some(tester.signers[&'E'].address()), signer).unwrap(); + prev_header = vote.clone(); + } + + let tags = tester.into_tags(tester.clique_signers(&prev_header.hash())); + assert_eq!(&tags, &['A', 'B', 'C', 'D']); +} + +#[test] +fn one_signer_dropping_itself() { + let tester = CliqueTester::with(10, 1, vec!['A']); + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'A'].address()), 'A').unwrap(); + let signers = tester.clique_signers(&vote.hash()); + assert!(signers.count() == 0); +} + +#[test] +fn two_signers_one_remove_vote_no_consensus() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B']); + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'B'].address()), 'A').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&vote.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn two_signers_consensus_remove_b() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B']); + let first_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'B'].address()), 'A').unwrap(); + let second_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &first_vote, + Some(tester.signers[&'B'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&second_vote.hash())); + assert_eq!(&tags, &['A']); +} + +#[test] +fn three_signers_consensus_remove_c() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B', 'C']); + let first_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + let second_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &first_vote, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&second_vote.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn four_signers_half_no_consensus() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B', 'C', 'D']); + let first_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + let second_vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &first_vote, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&second_vote.hash())); + assert_eq!(&tags, &['A', 'B', 'C', 'D']); +} + +#[test] +fn four_signers_three_consensus_rm() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B', 'C', 'D']); + + let mut prev_header = tester.genesis.clone(); + + // Three votes to remove `D` signed by ['A', 'B', 'C'] + for signer in SIGNER_TAGS.iter().take(3) { + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header, + Some(tester.signers[&'D'].address()), *signer).unwrap(); + prev_header = vote.clone(); + } + + let tags = tester.into_tags(tester.clique_signers(&prev_header.hash())); + assert_eq!(&tags, &['A', 'B', 'C']); +} + +#[test] +fn vote_add_only_counted_once_per_signer() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B']); + + // Add a vote for `C` signed by `A` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + // Empty block signed by B` + let empty = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap(); + + // Add a vote for `C` signed by `A` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &empty, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + // Empty block signed by `B` + let empty = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap(); + + // Add a vote for `C` signed by `A` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &empty, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&vote.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn vote_add_concurrently_is_permitted() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B']); + + // Add a vote for `C` signed by `A` + let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + // Empty block signed by `B` + let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'B').unwrap(); + + // Add a vote for `D` signed by `A` + let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &b, + Some(tester.signers[&'D'].address()), 'A').unwrap(); + + // Empty block signed by `B` + let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'B').unwrap(); + + // Empty block signed by `A` + let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'A').unwrap(); + + // Add a vote for `D` signed by `B` + let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &b, + Some(tester.signers[&'D'].address()), 'B').unwrap(); + + // Empty block signed by `A` + let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'A').unwrap(); + + // Add a vote for `C` signed by `B` + let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &b, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&b.hash())); + assert_eq!(&tags, &['A', 'B', 'C', 'D']); +} + +#[test] +fn vote_rm_only_counted_once_per_signer() { + let tester = CliqueTester::with(10, 1, vec!['A', 'B']); + + let mut prev_header = tester.genesis.clone(); + + for _ in 0..2 { + // Vote to remove `B` signed by `A` + let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header, + Some(tester.signers[&'B'].address()), 'A').unwrap(); + // Empty block signed by `B` + let b = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'B').unwrap(); + + prev_header = b.clone(); + } + + // Add a vote for `B` signed by `A` + let b = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header, + Some(tester.signers[&'B'].address()), 'A').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&b.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn vote_rm_concurrently_is_permitted() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']); + + // Add a vote for `C` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + // Empty block signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap(); + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + + // Add a vote for `D` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'A').unwrap(); + + // Empty block signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap(); + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + // Empty block signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap(); + + // Add a vote for `D` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'B').unwrap(); + // Add a vote for `D` signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'C').unwrap(); + + // Empty block signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap(); + // Add a vote for `C` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn vote_to_rm_are_immediate_and_ensure_votes_are_rm() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C']); + + // Vote to remove `B` signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'B'].address()), 'C').unwrap(); + // Vote to remove `C` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + // Vote to remove `C` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + // Vote to remove `B` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'B'].address()), 'A').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn vote_to_rm_are_immediate_and_votes_should_be_dropped_from_kicked_signer() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C']); + + // Vote to add `D` signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis, + Some(tester.signers[&'D'].address()), 'C').unwrap(); + // Vote to remove `C` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + // Vote to remove `C` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + // Vote to add `D` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block, + Some(tester.signers[&'D'].address()), 'A').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn cascading_not_allowed() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']); + + // Vote against `C` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + // Empty block signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap(); + + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + + // Vote against `D` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'A').unwrap(); + + // Vote against `C` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + + // Empty block signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap(); + + // Vote against `D` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'B').unwrap(); + + // Vote against `D` signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'C').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B', 'C']); +} + +#[test] +fn consensus_out_of_bounds_consensus_execute_on_touch() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']); + + // Vote against `C` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + // Empty block signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap(); + + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + + // Vote against `D` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'A').unwrap(); + + // Vote against `C` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + + // Empty block signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap(); + + // Vote against `D` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'B').unwrap(); + + // Vote against `D` signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'C').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B', 'C'], "D should have been removed after 3/4 remove votes"); + + // Empty block signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap(); + + // Vote for `C` signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block, + Some(tester.signers[&'C'].address()), 'C').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B']); +} + +#[test] +fn consensus_out_of_bounds_first_touch() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']); + + // Vote against `C` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + // Empty block signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap(); + + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + + // Vote against `D` signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'A').unwrap(); + + // Vote against `C` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + // Empty block signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'C').unwrap(); + + // Empty block signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap(); + + // Vote against `D` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'B').unwrap(); + + // Vote against `D` signed by `C` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &block, + Some(tester.signers[&'D'].address()), 'C').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B', 'C']); + + // Empty block signed by `A` + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap(); + + // Vote for `C` signed by `B` + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B', 'C']); +} + +#[test] +fn pending_votes_doesnt_survive_authorization_changes() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D', 'E']); + + let mut prev_header = tester.genesis.clone(); + + // Vote for `F` from [`A`, `B`, `C`] + for sign in SIGNER_TAGS.iter().take(3) { + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header, + Some(tester.signers[&'F'].address()), *sign).unwrap(); + prev_header = block.clone(); + } + + let tags = tester.into_tags(tester.clique_signers(&prev_header.hash())); + assert_eq!(&tags, &['A', 'B', 'C', 'D', 'E', 'F'], "F should have been added"); + + // Vote against `F` from [`D`, `E`, `B`, `C`] + for sign in SIGNER_TAGS.iter().skip(3).chain(SIGNER_TAGS.iter().skip(1).take(2)) { + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header, + Some(tester.signers[&'F'].address()), *sign).unwrap(); + prev_header = block.clone(); + } + + let tags = tester.into_tags(tester.clique_signers(&prev_header.hash())); + assert_eq!(&tags, &['A', 'B', 'C', 'D', 'E'], "F should have been removed"); + + // Vote for `F` from [`D`, `E`] + for sign in SIGNER_TAGS.iter().skip(3).take(2) { + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header, + Some(tester.signers[&'F'].address()), *sign).unwrap(); + prev_header = block.clone(); + } + + // Vote against `A` from [`B`, `C`, `D`] + for sign in SIGNER_TAGS.iter().skip(1).take(3) { + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Remove), &prev_header, + Some(tester.signers[&'A'].address()), *sign).unwrap(); + prev_header = block.clone(); + } + + let tags = tester.into_tags(tester.clique_signers(&prev_header.hash())); + assert_eq!(&tags, &['B', 'C', 'D', 'E'], "A should have been removed"); + + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &prev_header, + Some(tester.signers[&'F'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['B', 'C', 'D', 'E', 'F'], "F should have been added again"); +} + +#[test] +fn epoch_transition_reset_all_votes() { + let tester = CliqueTester::with(3, 1, vec!['A', 'B']); + + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis, + Some(tester.signers[&'C'].address()), 'A').unwrap(); + + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap(); + let block = tester.new_block_and_import(CliqueBlockType::Checkpoint, &block, None, 'A').unwrap(); + + let block = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &block, + Some(tester.signers[&'C'].address()), 'B').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&block.hash())); + assert_eq!(&tags, &['A', 'B'], "Votes should have been reset after checkpoint"); +} + +#[test] +fn unauthorized_signer_should_not_be_able_to_sign_block() { + let tester = CliqueTester::with(3, 1, vec!['A']); + let err = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'B').unwrap_err(); + + match err.kind() { + ErrorKind::Engine(EngineError::NotAuthorized(_)) => (), + _ => assert!(true == false, "Wrong error kind"), + } +} + +#[test] +fn signer_should_not_be_able_to_sign_two_consequtive_blocks() { + let tester = CliqueTester::with(3, 1, vec!['A', 'B']); + let b = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'A').unwrap(); + let err = tester.new_block_and_import(CliqueBlockType::Empty, &b, None, 'A').unwrap_err(); + + match err.kind() { + ErrorKind::Engine(EngineError::CliqueTooRecentlySigned(_)) => (), + _ => assert!(true == false, "Wrong error kind"), + } +} + + +#[test] +fn recent_signers_should_not_reset_on_checkpoint() { + let tester = CliqueTester::with(3, 1, vec!['A', 'B', 'C']); + + let block = tester.new_block_and_import(CliqueBlockType::Empty, &tester.genesis, None, 'A').unwrap(); + let block = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'B').unwrap(); + let block = tester.new_block_and_import(CliqueBlockType::Checkpoint, &block, None, 'A').unwrap(); + + let err = tester.new_block_and_import(CliqueBlockType::Empty, &block, None, 'A').unwrap_err(); + + match err.kind() { + ErrorKind::Engine(EngineError::CliqueTooRecentlySigned(_)) => (), + _ => assert!(true == false, "Wrong error kind"), + } +} + +// Not part of http://eips.ethereum.org/EIPS/eip-225 +#[test] +fn bonus_consensus_should_keep_track_of_votes_before_latest_per_signer() { + let tester = CliqueTester::with(100, 1, vec!['A', 'B', 'C', 'D']); + + // Add a vote for `E` signed by `A` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &tester.genesis, + Some(tester.signers[&'E'].address()), 'A').unwrap(); + // Empty block signed by `B` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'B').unwrap(); + + // Empty block signed by `C` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'C').unwrap(); + + // Empty block signed by `D` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'D').unwrap(); + + // Add a vote for `F` signed by `A` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote, + Some(tester.signers[&'F'].address()), 'A').unwrap(); + // Empty block signed by `C` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'C').unwrap(); + + // Empty block signed by `D` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'D').unwrap(); + + // Add a vote for `E` signed by `B` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote, + Some(tester.signers[&'E'].address()), 'B').unwrap(); + // Empty block signed by `A` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'A').unwrap(); + + // Empty block signed by `C` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'C').unwrap(); + + // Empty block signed by `D` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'D').unwrap(); + + // Add a vote for `F` signed by `B` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote, + Some(tester.signers[&'F'].address()), 'B').unwrap(); + + // Empty block signed by A` + let vote = tester.new_block_and_import(CliqueBlockType::Empty, &vote, None, 'A').unwrap(); + + // Add a vote for `E` signed by `C` + let vote = tester.new_block_and_import(CliqueBlockType::Vote(VoteType::Add), &vote, + Some(tester.signers[&'E'].address()), 'C').unwrap(); + + let tags = tester.into_tags(tester.clique_signers(&vote.hash())); + assert_eq!(&tags, &['A', 'B', 'C', 'D', 'E']); +} diff --git a/ethcore/src/engines/clique/util.rs b/ethcore/src/engines/clique/util.rs new file mode 100644 index 000000000..3f75289e9 --- /dev/null +++ b/ethcore/src/engines/clique/util.rs @@ -0,0 +1,115 @@ +// Copyright 2015-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 . + +use std::collections::BTreeSet; + +use engines::EngineError; +use engines::clique::{ADDRESS_LENGTH, SIGNATURE_LENGTH, VANITY_LENGTH, NULL_NONCE, NULL_MIXHASH}; +use error::Error; +use ethereum_types::{Address, H256}; +use ethkey::{public_to_address, recover as ec_recover, Signature}; +use lru_cache::LruCache; +use parking_lot::RwLock; +use rlp::encode; +use types::header::Header; + +/// How many recovered signature to cache in the memory. +pub const CREATOR_CACHE_NUM: usize = 4096; +lazy_static! { + /// key: header hash + /// value: creator address + static ref CREATOR_BY_HASH: RwLock> = RwLock::new(LruCache::new(CREATOR_CACHE_NUM)); +} + +/// Recover block creator from signature +pub fn recover_creator(header: &Header) -> Result { + // Initialization + let mut cache = CREATOR_BY_HASH.write(); + + if let Some(creator) = cache.get_mut(&header.hash()) { + return Ok(*creator); + } + + let data = header.extra_data(); + if data.len() < VANITY_LENGTH { + Err(EngineError::CliqueMissingVanity)? + } + + if data.len() < VANITY_LENGTH + SIGNATURE_LENGTH { + Err(EngineError::CliqueMissingSignature)? + } + + // Split `signed_extra data` and `signature` + let (signed_data_slice, signature_slice) = data.split_at(data.len() - SIGNATURE_LENGTH); + + // convert `&[u8]` to `[u8; 65]` + let signature = { + let mut s = [0; SIGNATURE_LENGTH]; + s.copy_from_slice(signature_slice); + s + }; + + // modify header and hash it + let unsigned_header = &mut header.clone(); + unsigned_header.set_extra_data(signed_data_slice.to_vec()); + let msg = unsigned_header.hash(); + + let pubkey = ec_recover(&Signature::from(signature), &msg)?; + let creator = public_to_address(&pubkey); + + cache.insert(header.hash(), creator.clone()); + Ok(creator) +} + +/// Extract signer list from extra_data. +/// +/// Layout of extra_data: +/// ---- +/// VANITY: 32 bytes +/// Signers: N * 32 bytes as hex encoded (20 characters) +/// Signature: 65 bytes +/// -- +pub fn extract_signers(header: &Header) -> Result, Error> { + let data = header.extra_data(); + + if data.len() <= VANITY_LENGTH + SIGNATURE_LENGTH { + Err(EngineError::CliqueCheckpointNoSigner)? + } + + // extract only the portion of extra_data which includes the signer list + let signers_raw = &data[(VANITY_LENGTH)..data.len() - (SIGNATURE_LENGTH)]; + + if signers_raw.len() % ADDRESS_LENGTH != 0 { + Err(EngineError::CliqueCheckpointInvalidSigners(signers_raw.len()))? + } + + let num_signers = signers_raw.len() / 20; + + let signers: BTreeSet
= (0..num_signers) + .map(|i| { + let start = i * ADDRESS_LENGTH; + let end = start + ADDRESS_LENGTH; + signers_raw[start..end].into() + }) + .collect(); + + Ok(signers) +} + +/// Retrieve `null_seal` +pub fn null_seal() -> Vec> { + vec![encode(&NULL_MIXHASH.to_vec()), encode(&NULL_NONCE.to_vec())] +} diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 06e6b522b..5124f079d 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -18,6 +18,7 @@ mod authority_round; mod basic_authority; +mod clique; mod instant_seal; mod null_engine; mod validator_set; @@ -30,6 +31,7 @@ pub use self::basic_authority::BasicAuthority; pub use self::instant_seal::{InstantSeal, InstantSealParams}; pub use self::null_engine::NullEngine; pub use self::signer::EngineSigner; +pub use self::clique::Clique; // TODO [ToDr] Remove re-export (#10130) pub use types::engines::ForkChoice; @@ -50,7 +52,7 @@ use types::transaction::{self, UnverifiedTransaction, SignedTransaction}; use ethkey::{Signature}; use machine::{self, Machine, AuxiliaryRequest, AuxiliaryData}; -use ethereum_types::{H256, U256, Address}; +use ethereum_types::{H64, H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; use bytes::Bytes; use types::ancestry_action::AncestryAction; @@ -85,12 +87,45 @@ pub enum EngineError { RequiresClient, /// Invalid engine specification or implementation. InvalidEngine, + /// Requires signer ref, but none registered. + RequiresSigner, + /// Checkpoint is missing + CliqueMissingCheckpoint(H256), + /// Missing vanity data + CliqueMissingVanity, + /// Missing signature + CliqueMissingSignature, + /// Missing signers + CliqueCheckpointNoSigner, + /// List of signers is invalid + CliqueCheckpointInvalidSigners(usize), + /// Wrong author on a checkpoint + CliqueWrongAuthorCheckpoint(Mismatch
), + /// Wrong checkpoint authors recovered + CliqueFaultyRecoveredSigners(Vec), + /// Invalid nonce (should contain vote) + CliqueInvalidNonce(H64), + /// The signer signed a block to recently + CliqueTooRecentlySigned(Address), + /// Custom + Custom(String), } impl fmt::Display for EngineError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::EngineError::*; let msg = match *self { + CliqueMissingCheckpoint(ref hash) => format!("Missing checkpoint block: {}", hash), + CliqueMissingVanity => format!("Extra data is missing vanity data"), + CliqueMissingSignature => format!("Extra data is missing signature"), + CliqueCheckpointInvalidSigners(len) => format!("Checkpoint block list was of length: {} of checkpoint but + it needs to be bigger than zero and a divisible by 20", len), + CliqueCheckpointNoSigner => format!("Checkpoint block list of signers was empty"), + CliqueInvalidNonce(ref mis) => format!("Unexpected nonce {} expected {} or {}", mis, 0_u64, u64::max_value()), + CliqueWrongAuthorCheckpoint(ref oob) => format!("Unexpected checkpoint author: {}", oob), + CliqueFaultyRecoveredSigners(ref mis) => format!("Faulty recovered signers {:?}", mis), + CliqueTooRecentlySigned(ref address) => format!("The signer: {} has signed a block too recently", address), + Custom(ref s) => s.clone(), DoubleVote(ref address) => format!("Author {} issued too many blocks.", address), NotProposer(ref mis) => format!("Author is not a current proposer: {}", mis), NotAuthorized(ref address) => format!("Signer {} is not authorized.", address), @@ -100,6 +135,7 @@ impl fmt::Display for EngineError { FailedSystemCall(ref msg) => format!("Failed to make system call: {}", msg), MalformedMessage(ref msg) => format!("Received malformed consensus message: {}", msg), RequiresClient => format!("Call requires client but none registered"), + RequiresSigner => format!("Call requires signer but none registered"), InvalidEngine => format!("Invalid engine specification or implementation"), }; @@ -120,7 +156,7 @@ pub enum Seal { Proposal(Vec), /// Regular block seal; should be part of the blockchain. Regular(Vec), - /// Engine does generate seal for this block right now. + /// Engine does not generate seal for this block right now. None, } @@ -263,6 +299,9 @@ pub trait Engine: Sync + Send { Ok(()) } + /// Allow mutating the header during seal generation. Currently only used by Clique. + fn on_seal_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> { Ok(()) } + /// None means that it requires external input (e.g. PoW) to seal a block. /// Some(true) means the engine is currently prime for seal generation (i.e. node is the current validator). /// Some(false) means that the node might seal internally but is not qualified now. @@ -387,7 +426,7 @@ pub trait Engine: Sync + Send { fn step(&self) {} /// Stops any services that the may hold the Engine and makes it safe to drop. - fn stop(&self) {} + fn stop(&mut self) {} /// Create a factory for building snapshot chunks and restoring from them. /// Returning `None` indicates that this engine doesn't support snapshot creation. @@ -421,6 +460,11 @@ pub trait Engine: Sync + Send { /// Check whether the given new block is the best block, after finalization check. fn fork_choice(&self, new: &ExtendedHeader, best: &ExtendedHeader) -> ForkChoice; + + /// Returns author should used when executing tx's for this block. + fn executive_author(&self, header: &Header) -> Result { + Ok(*header.author()) + } } /// Check whether a given block is the best block based on the default total difficulty rule. diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index b7c60789a..d37ca9b4f 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -94,6 +94,11 @@ pub fn new_mix<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/mix.json")) } +/// Create a new Callisto chain spec +pub fn new_callisto<'a, T: Into>>(params: T) -> Spec { + load(params.into(), include_bytes!("../../res/ethereum/callisto.json")) +} + /// Create a new Morden testnet chain spec. pub fn new_morden<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/morden.json")) @@ -109,16 +114,26 @@ pub fn new_kovan<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/kovan.json")) } +/// Create a new Rinkeby testnet chain spec. +pub fn new_rinkeby<'a, T: Into>>(params: T) -> Spec { + load(params.into(), include_bytes!("../../res/ethereum/rinkeby.json")) +} + +/// Create a new Görli testnet chain spec. +pub fn new_goerli<'a, T: Into>>(params: T) -> Spec { + load(params.into(), include_bytes!("../../res/ethereum/goerli.json")) +} + +/// Create a new Kotti testnet chain spec. +pub fn new_kotti<'a, T: Into>>(params: T) -> Spec { + load(params.into(), include_bytes!("../../res/ethereum/kotti.json")) +} + /// Create a new POA Sokol testnet chain spec. pub fn new_sokol<'a, T: Into>>(params: T) -> Spec { load(params.into(), include_bytes!("../../res/ethereum/poasokol.json")) } -/// Create a new Callisto chaun spec -pub fn new_callisto<'a, T: Into>>(params: T) -> Spec { - load(params.into(), include_bytes!("../../res/ethereum/callisto.json")) -} - // For tests /// Create a new Foundation Frontier-era chain spec as though it never changes to Homestead. diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index ce1c9ef6e..adaeff087 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -214,7 +214,6 @@ impl Author { } } - struct SealingWork { queue: UsingQueue, enabled: bool, @@ -630,7 +629,10 @@ impl Miner { } } - /// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal. + // TODO: (https://github.com/paritytech/parity-ethereum/issues/10407) + // This is only used in authority_round path, and should be refactored to merge with the other seal() path. + // Attempts to perform internal sealing (one that does not require work) and handles the result depending on the + // type of Seal. fn seal_and_import_block_internally(&self, chain: &C, block: ClosedBlock) -> bool where C: BlockChain + SealedBlockImporter, { @@ -1142,7 +1144,7 @@ impl miner::MinerService for Miner { if block.header.number() == 1 { if let Some(name) = self.engine.params().nonzero_bugfix_hard_fork() { warn!("Your chain specification contains one or more hard forks which are required to be \ - on by default. Please remove these forks and start your chain again: {}.", name); + on by default. Please remove these forks and start your chain again: {}.", name); return; } } diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 82dd5da5c..fe32c0d87 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -35,7 +35,7 @@ use vm::{EnvInfo, CallType, ActionValue, ActionParams, ParamsType}; use builtin::Builtin; use engines::{ - EthEngine, NullEngine, InstantSeal, InstantSealParams, BasicAuthority, + EthEngine, NullEngine, InstantSeal, InstantSealParams, BasicAuthority, Clique, AuthorityRound, DEFAULT_BLOCKHASH_CONTRACT }; use error::Error; @@ -99,9 +99,9 @@ pub struct CommonParams { pub validate_receipts_transition: BlockNumber, /// Validate transaction chain id. pub validate_chain_id_transition: BlockNumber, - /// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin. + /// Number of first block where EIP-140 rules begin. pub eip140_transition: BlockNumber, - /// Number of first block where EIP-210 (Metropolis: BLOCKHASH changes) rules begin. + /// Number of first block where EIP-210 rules begin. pub eip210_transition: BlockNumber, /// EIP-210 Blockhash contract address. pub eip210_contract_address: Address, @@ -109,8 +109,7 @@ pub struct CommonParams { pub eip210_contract_code: Bytes, /// Gas allocated for EIP-210 blockhash update. pub eip210_contract_gas: U256, - /// Number of first block where EIP-211 (Metropolis: RETURNDATASIZE/RETURNDATACOPY) rules - /// begin. + /// Number of first block where EIP-211 rules begin. pub eip211_transition: BlockNumber, /// Number of first block where EIP-214 rules begin. pub eip214_transition: BlockNumber, @@ -611,6 +610,8 @@ impl Spec { ethjson::spec::Engine::InstantSeal(Some(instant_seal)) => Arc::new(InstantSeal::new(instant_seal.params.into(), machine)), ethjson::spec::Engine::InstantSeal(None) => Arc::new(InstantSeal::new(InstantSealParams::default(), machine)), ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(basic_authority.params.into(), machine)), + ethjson::spec::Engine::Clique(clique) => Clique::new(clique.params.into(), machine) + .expect("Failed to start Clique consensus engine."), ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(authority_round.params.into(), machine) .expect("Failed to start AuthorityRound consensus engine."), } @@ -827,7 +828,6 @@ impl Spec { ethjson::spec::Spec::load(reader) .map_err(fmt_err) .map(load_machine_from) - } /// Loads spec from json file. Provide factories for executing contracts and ensuring diff --git a/json/src/spec/clique.rs b/json/src/spec/clique.rs new file mode 100644 index 000000000..64be9c569 --- /dev/null +++ b/json/src/spec/clique.rs @@ -0,0 +1,57 @@ +// Copyright 2015-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 . + +//! Clique params deserialization. + +use std::num::NonZeroU64; + +/// Clique params deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct CliqueParams { + /// period as defined in EIP + pub period: Option, + /// epoch length as defined in EIP + pub epoch: Option +} + +/// Clique engine deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Clique { + /// CliqueEngine params + pub params: CliqueParams, +} + +#[cfg(test)] +mod tests { + use serde_json; + use uint::Uint; + use ethereum_types::U256; + use super::*; + + #[test] + fn clique_deserialization() { + let s = r#"{ + "params": { + "period": 5, + "epoch": 30000 + } + }"#; + + let deserialized: Clique = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized.params.period, Some(5u64)); + assert_eq!(deserialized.params.epoch, NonZeroU64::new(30000)); + } +} diff --git a/json/src/spec/engine.rs b/json/src/spec/engine.rs index 8941f89e1..cfa1d8caf 100644 --- a/json/src/spec/engine.rs +++ b/json/src/spec/engine.rs @@ -16,7 +16,7 @@ //! Engine deserialization. -use super::{Ethash, BasicAuthority, AuthorityRound, NullEngine, InstantSeal}; +use super::{Ethash, BasicAuthority, AuthorityRound, NullEngine, InstantSeal, Clique}; /// Engine deserialization. #[derive(Debug, PartialEq, Deserialize)] @@ -34,6 +34,8 @@ pub enum Engine { BasicAuthority(BasicAuthority), /// AuthorityRound engine. AuthorityRound(AuthorityRound), + /// Clique engine. + Clique(Clique) } #[cfg(test)] @@ -130,5 +132,19 @@ mod tests { Engine::AuthorityRound(_) => {}, // AuthorityRound is unit tested in its own file. _ => panic!(), }; + + let s = r#"{ + "clique": { + "params": { + "period": 15, + "epoch": 30000 + } + } + }"#; + let deserialized: Engine = serde_json::from_str(s).unwrap(); + match deserialized { + Engine::Clique(_) => {}, // Clique is unit tested in its own file. + _ => panic!(), + }; } } diff --git a/json/src/spec/mod.rs b/json/src/spec/mod.rs index 1d6815d37..f1145be2e 100644 --- a/json/src/spec/mod.rs +++ b/json/src/spec/mod.rs @@ -31,6 +31,7 @@ pub mod authority_round; pub mod null_engine; pub mod instant_seal; pub mod hardcoded_sync; +pub mod clique; pub use self::account::Account; pub use self::builtin::{Builtin, Pricing, Linear}; @@ -44,6 +45,7 @@ pub use self::ethash::{Ethash, EthashParams, BlockReward}; pub use self::validator_set::ValidatorSet; pub use self::basic_authority::{BasicAuthority, BasicAuthorityParams}; pub use self::authority_round::{AuthorityRound, AuthorityRoundParams}; +pub use self::clique::{Clique, CliqueParams}; pub use self::null_engine::{NullEngine, NullEngineParams}; pub use self::instant_seal::{InstantSeal, InstantSealParams}; pub use self::hardcoded_sync::HardcodedSync; diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index c372e9bff..01f4469bb 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -300,7 +300,7 @@ usage! { ARG arg_chain: (String) = "foundation", or |c: &Config| c.parity.as_ref()?.chain.clone(), "--chain=[CHAIN]", - "Specify the blockchain type. CHAIN may be either a JSON chain specification file or ethereum, classic, poacore, tobalaba, expanse, musicoin, ellaism, easthub, social, mix, callisto, morden, ropsten, kovan, poasokol, testnet, or dev.", + "Specify the blockchain type. CHAIN may be either a JSON chain specification file or ethereum, classic, poacore, tobalaba, expanse, musicoin, ellaism, easthub, social, mix, callisto, morden, ropsten, kovan, rinkeby, goerli, kotti, poasokol, testnet, or dev.", ARG arg_keys_path: (String) = "$BASE/keys", or |c: &Config| c.parity.as_ref()?.keys_path.clone(), "--keys-path=[PATH]", @@ -926,7 +926,7 @@ usage! { "--whisper", "Enable the Whisper network.", - ARG arg_whisper_pool_size: (usize) = 10usize, or |c: &Config| c.whisper.as_ref()?.pool_size.clone(), + ARG arg_whisper_pool_size: (usize) = 10usize, or |c: &Config| c.whisper.as_ref()?.pool_size.clone(), "--whisper-pool-size=[MB]", "Target size of the whisper message pool in megabytes.", diff --git a/parity/params.rs b/parity/params.rs index a916d05a7..389b708ce 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -47,6 +47,9 @@ pub enum SpecType { Morden, Ropsten, Kovan, + Rinkeby, + Goerli, + Kotti, Sokol, Dev, Custom(String), @@ -77,6 +80,9 @@ impl str::FromStr for SpecType { "morden" | "classic-testnet" => SpecType::Morden, "ropsten" => SpecType::Ropsten, "kovan" | "testnet" => SpecType::Kovan, + "rinkeby" => SpecType::Rinkeby, + "goerli" | "görli" => SpecType::Goerli, + "kotti" => SpecType::Kotti, "sokol" | "poasokol" => SpecType::Sokol, "dev" => SpecType::Dev, other => SpecType::Custom(other.into()), @@ -102,6 +108,9 @@ impl fmt::Display for SpecType { SpecType::Morden => "morden", SpecType::Ropsten => "ropsten", SpecType::Kovan => "kovan", + SpecType::Rinkeby => "rinkeby", + SpecType::Goerli => "goerli", + SpecType::Kotti => "kotti", SpecType::Sokol => "sokol", SpecType::Dev => "dev", SpecType::Custom(ref custom) => custom, @@ -127,6 +136,9 @@ impl SpecType { SpecType::Morden => Ok(ethereum::new_morden(params)), SpecType::Ropsten => Ok(ethereum::new_ropsten(params)), SpecType::Kovan => Ok(ethereum::new_kovan(params)), + SpecType::Rinkeby => Ok(ethereum::new_rinkeby(params)), + SpecType::Goerli => Ok(ethereum::new_goerli(params)), + SpecType::Kotti => Ok(ethereum::new_kotti(params)), SpecType::Sokol => Ok(ethereum::new_sokol(params)), SpecType::Dev => Ok(Spec::new_instant()), SpecType::Custom(ref filename) => { @@ -385,6 +397,10 @@ mod tests { assert_eq!(SpecType::Ropsten, "ropsten".parse().unwrap()); assert_eq!(SpecType::Kovan, "kovan".parse().unwrap()); assert_eq!(SpecType::Kovan, "testnet".parse().unwrap()); + assert_eq!(SpecType::Rinkeby, "rinkeby".parse().unwrap()); + assert_eq!(SpecType::Goerli, "goerli".parse().unwrap()); + assert_eq!(SpecType::Goerli, "görli".parse().unwrap()); + assert_eq!(SpecType::Kotti, "kotti".parse().unwrap()); assert_eq!(SpecType::Sokol, "sokol".parse().unwrap()); assert_eq!(SpecType::Sokol, "poasokol".parse().unwrap()); } @@ -410,6 +426,9 @@ mod tests { assert_eq!(format!("{}", SpecType::Morden), "morden"); assert_eq!(format!("{}", SpecType::Ropsten), "ropsten"); assert_eq!(format!("{}", SpecType::Kovan), "kovan"); + assert_eq!(format!("{}", SpecType::Rinkeby), "rinkeby"); + assert_eq!(format!("{}", SpecType::Goerli), "goerli"); + assert_eq!(format!("{}", SpecType::Kotti), "kotti"); assert_eq!(format!("{}", SpecType::Sokol), "sokol"); assert_eq!(format!("{}", SpecType::Dev), "dev"); assert_eq!(format!("{}", SpecType::Custom("foo/bar".into())), "foo/bar"); diff --git a/util/version/Cargo.toml b/util/version/Cargo.toml index 870005054..890b4e0a8 100644 --- a/util/version/Cargo.toml +++ b/util/version/Cargo.toml @@ -19,6 +19,7 @@ track = "nightly" foundation = { forkBlock = 7280000, critical = false } ropsten = { forkBlock = 4939394, critical = false } kovan = { forkBlock = 10255201, critical = false } +goerli = { forkBlock = 0, critical = false } [dependencies] parity-bytes = "0.1"