diff --git a/Makefile b/Makefile index fb93908cc..bfbc28070 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ $(PY_SPEC_PHASE_0_TARGETS): $(PY_SPEC_PHASE_0_DEPS) python3 $(SCRIPT_DIR)/build_spec.py -p0 $(SPEC_DIR)/core/0_beacon-chain.md $(SPEC_DIR)/core/0_fork-choice.md $(SPEC_DIR)/validator/0_beacon-chain-validator.md $@ $(PY_SPEC_DIR)/eth2spec/phase1/spec.py: $(PY_SPEC_PHASE_1_DEPS) - python3 $(SCRIPT_DIR)/build_spec.py -p1 $(SPEC_DIR)/core/0_beacon-chain.md $(SPEC_DIR)/core/0_fork-choice.md $(SPEC_DIR)/core/1_custody-game.md $(SPEC_DIR)/core/1_shard-data-chains.md $(SPEC_DIR)/light_client/merkle_proofs.md $@ + python3 $(SCRIPT_DIR)/build_spec.py -p1 $(SPEC_DIR)/core/0_beacon-chain.md $(SPEC_DIR)/core/0_fork-choice.md $(SPEC_DIR)/light_client/merkle_proofs.md $(SPEC_DIR)/core/1_custody-game.md $(SPEC_DIR)/core/1_shard-data-chains.md $(SPEC_DIR)/core/1_beacon-chain-misc.md $@ CURRENT_DIR = ${CURDIR} diff --git a/README.md b/README.md index 6fbd38aa4..fdfbd1c5e 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Core specifications for Eth 2.0 client validation can be found in [specs/core](s ### Phase 1 * [Custody Game](specs/core/1_custody-game.md) * [Shard Data Chains](specs/core/1_shard-data-chains.md) +* [Misc beacon chain updates](specs/core/1_beacon-chain-misc.md) ### Phase 2 @@ -34,8 +35,6 @@ See the [Eth 2.0 Phase 2 Wiki](https://hackmd.io/UzysWse1Th240HELswKqVA?view) fo * [General test format](specs/test_formats/README.md) * [Merkle proof formats](specs/light_client/merkle_proofs.md) * [Light client syncing protocol](specs/light_client/sync_protocol.md) -* [Beacon node API for validator](specs/validator/0_beacon-node-validator-api.md) - ## Additional specifications for client implementers diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index d4e69dab5..c11f1e54c 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -60,7 +60,7 @@ SLOTS_PER_EPOCH: 64 # 2**0 (= 1) epochs 6.4 minutes MIN_SEED_LOOKAHEAD: 1 # 2**2 (= 4) epochs 25.6 minutes -ACTIVATION_EXIT_DELAY: 4 +MAX_SEED_LOOKAHEAD: 4 # 2**10 (= 1,024) slots ~1.7 hours SLOTS_PER_ETH1_VOTING_PERIOD: 1024 # 2**13 (= 8,192) slots ~13 hours @@ -123,8 +123,8 @@ MAX_TRANSFERS: 0 # Signature domains # --------------------------------------------------------------- DOMAIN_BEACON_PROPOSER: 0x00000000 -DOMAIN_RANDAO: 0x01000000 -DOMAIN_ATTESTATION: 0x02000000 +DOMAIN_BEACON_ATTESTER: 0x01000000 +DOMAIN_RANDAO: 0x02000000 DOMAIN_DEPOSIT: 0x03000000 DOMAIN_VOLUNTARY_EXIT: 0x04000000 DOMAIN_TRANSFER: 0x05000000 diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 15b749b9d..4c32eae4d 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -59,7 +59,7 @@ SLOTS_PER_EPOCH: 8 # 2**0 (= 1) epochs MIN_SEED_LOOKAHEAD: 1 # 2**2 (= 4) epochs -ACTIVATION_EXIT_DELAY: 4 +MAX_SEED_LOOKAHEAD: 4 # [customized] higher frequency new deposits from eth1 for testing SLOTS_PER_ETH1_VOTING_PERIOD: 16 # [customized] smaller state @@ -125,8 +125,8 @@ MAX_TRANSFERS: 0 # Signature domains # --------------------------------------------------------------- DOMAIN_BEACON_PROPOSER: 0x00000000 -DOMAIN_RANDAO: 0x01000000 -DOMAIN_ATTESTATION: 0x02000000 +DOMAIN_BEACON_ATTESTER: 0x01000000 +DOMAIN_RANDAO: 0x02000000 DOMAIN_DEPOSIT: 0x03000000 DOMAIN_VOLUNTARY_EXIT: 0x04000000 DOMAIN_TRANSFER: 0x05000000 @@ -141,5 +141,5 @@ SHARD_SLOTS_PER_BEACON_SLOT: 2 EPOCHS_PER_SHARD_PERIOD: 4 # PHASE_1_FORK_EPOCH >= EPOCHS_PER_SHARD_PERIOD * 2 PHASE_1_FORK_EPOCH: 8 -# PHASE_1_FORK_SLOT = PHASE_1_FORK_EPOCH * SHARD_SLOTS_PER_BEACON_SLOT * SLOTS_PER_EPOCH -PHASE_1_FORK_SLOT: 128 +# PHASE_1_FORK_SLOT = PHASE_1_FORK_EPOCH * SLOTS_PER_EPOCH +PHASE_1_FORK_SLOT: 64 diff --git a/deposit_contract/contracts/validator_registration.json b/deposit_contract/contracts/validator_registration.json index 3a6bfb2d8..fbf20e74c 100644 --- a/deposit_contract/contracts/validator_registration.json +++ b/deposit_contract/contracts/validator_registration.json @@ -1 +1 @@ -{"abi": [{"name": "DepositEvent", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_hash_tree_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 91674}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 10433}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}], "constant": false, "payable": true, "type": "function", "gas": 1334417}], "bytecode": "0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6101406000601f818352015b600061014051602081106100b757600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e357600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012157600080fd5b60c0519050606051600161014051018060405190131561014057600080fd5b809190121561014e57600080fd5b6020811061015b57600080fd5b600260c052602060c02001555b81516001018083528114156100a4575b50506112f956600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63863a311b600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c561064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b61017f6112f90361017f60003961017f6112f9036000f3"} \ No newline at end of file +{"abi": [{"name": "DepositEvent", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_deposit_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 95389}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 17683}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}, {"type": "bytes32", "name": "deposit_data_root"}], "constant": false, "payable": true, "type": "function", "gas": 1754607}], "bytecode": "0x740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009857600080fd5b6101406000601f818352015b600061014051602081106100b757600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e357600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012157600080fd5b60c0519050606051600161014051018060405190131561014057600080fd5b809190121561014e57600080fd5b6020811061015b57600080fd5b600260c052602060c02001555b81516001018083528114156100a4575b50506111d656600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610265575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506103206102c0516020818352015b60206103205111156101f15761020d565b6000610320516102e001535b81516001018083528114156101e0575b505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102415761025d565b602061028051036102a00151602061028051036102805261022f565b610160515650005b63c5f2892f60005114156104f757341561027e57600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103205760006101a051602081106102c157600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161031257600080fd5b60c05190506101605261038e565b6000610160516020826101c00101526020810190506101a0516020811061034657600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161038457600080fd5b60c0519050610160525b610180600261039c57600080fd5b60028151048152505b815160010180835281141561029f575b505060006101605160208261046001015260208101905061014051610160516101805163806732896102e05260015461030052610300516006580161009b565b506103605260006103c0525b6103605160206001820306601f82010390506103c0511015156104235761043c565b6103c05161038001526103c0516020016103c052610401565b61018052610160526101405261036060088060208461046001018260208501600060046012f150508051820191505060006018602082066103e0016020828401111561048757600080fd5b60208061040082610140600060046015f150508181528090509050905060188060208461046001018260208501600060046014f150508051820191505080610460526104609050602060c0825160208401600060025af16104e757600080fd5b60c051905060005260206000f350005b63621fd13060005114156105f857341561051057600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561055b57610574565b610220516101e001526102205160200161022052610539565b6101c0805160200180610280828460006004600a8704601201f161059757600080fd5b50506102e0610280516020818352015b60206102e05111156105b8576105d4565b60006102e0516102a001535b81516001018083528114156105a7575b50506020610260526040610280510160206001820306601f8201039050610260f350005b6322895118600051141561105157605060043560040161014037603060043560040135111561062657600080fd5b60406024356004016101c037602060243560040135111561064657600080fd5b608060443560040161022037606060443560040135111561066657600080fd5b63ffffffff6001541061067857600080fd5b633b9aca006102e0526102e05161068e57600080fd5b6102e05134046102c052633b9aca006102c05110156106ac57600080fd5b603061014051146106bc57600080fd5b60206101c051146106cc57600080fd5b606061022051146106dc57600080fd5b610140610360525b61036051516020610360510161036052610360610360511015610706576106e4565b6380673289610380526102c0516103a0526103a0516006580161009b565b50610400526000610460525b6104005160206001820306601f8201039050610460511015156107525761076b565b6104605161042001526104605160200161046052610730565b610340610360525b610360515260206103605103610360526101406103605110151561079657610773565b610400805160200180610300828460006004600a8704601201f16107b957600080fd5b5050610140610480525b610480515160206104805101610480526104806104805110156107e5576107c3565b63806732896104a0526001546104c0526104c0516006580161009b565b50610520526000610580525b6105205160206001820306601f82010390506105805110151561083057610849565b610580516105400152610580516020016105805261080e565b610460610480525b610480515260206104805103610480526101406104805110151561087457610851565b6105208051602001806105a0828460006004600a8704601201f161089757600080fd5b505060a06106205261062051610660526101408051602001806106205161066001828460006004600a8704601201f16108cf57600080fd5b5050610600610620516106600151610240818352015b6102406106005111156108f757610918565b600061060051610620516106800101535b81516001018083528114156108e5575b5050602061062051610660015160206001820306601f82010390506106205101016106205261062051610680526101c08051602001806106205161066001828460006004600a8704601201f161096d57600080fd5b5050610600610620516106600151610240818352015b610240610600511115610995576109b6565b600061060051610620516106800101535b8151600101808352811415610983575b5050602061062051610660015160206001820306601f820103905061062051010161062052610620516106a0526103008051602001806106205161066001828460006004600a8704601201f1610a0b57600080fd5b5050610600610620516106600151610240818352015b610240610600511115610a3357610a54565b600061060051610620516106800101535b8151600101808352811415610a21575b5050602061062051610660015160206001820306601f820103905061062051010161062052610620516106c0526102208051602001806106205161066001828460006004600a8704601201f1610aa957600080fd5b5050610600610620516106600151610240818352015b610240610600511115610ad157610af2565b600061060051610620516106800101535b8151600101808352811415610abf575b5050602061062051610660015160206001820306601f820103905061062051010161062052610620516106e0526105a08051602001806106205161066001828460006004600a8704601201f1610b4757600080fd5b5050610600610620516106600151610240818352015b610240610600511115610b6f57610b90565b600061060051610620516106800101535b8151600101808352811415610b5d575b5050602061062051610660015160206001820306601f8201039050610620510101610620527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c561062051610660a160006107005260006101406030806020846107c001018260208501600060046016f150508051820191505060006010602082066107400160208284011115610c2557600080fd5b60208061076082610700600060046015f15050818152809050905090506010806020846107c001018260208501600060046013f1505080518201915050806107c0526107c09050602060c0825160208401600060025af1610c8557600080fd5b60c0519050610720526000600060406020820661086001610220518284011115610cae57600080fd5b606080610880826020602088068803016102200160006004601bf1505081815280905090509050602060c0825160208401600060025af1610cee57600080fd5b60c0519050602082610a600101526020810190506000604060206020820661092001610220518284011115610d2257600080fd5b606080610940826020602088068803016102200160006004601bf15050818152809050905090506020806020846109e001018260208501600060046015f1505080518201915050610700516020826109e0010152602081019050806109e0526109e09050602060c0825160208401600060025af1610d9f57600080fd5b60c0519050602082610a6001015260208101905080610a6052610a609050602060c0825160208401600060025af1610dd657600080fd5b60c0519050610840526000600061072051602082610b000101526020810190506101c0602080602084610b0001018260208501600060046015f150508051820191505080610b0052610b009050602060c0825160208401600060025af1610e3c57600080fd5b60c0519050602082610c800101526020810190506000610300600880602084610c0001018260208501600060046012f15050805182019150506000601860208206610b800160208284011115610e9157600080fd5b602080610ba082610700600060046015f1505081815280905090509050601880602084610c0001018260208501600060046014f150508051820191505061084051602082610c0001015260208101905080610c0052610c009050602060c0825160208401600060025af1610f0457600080fd5b60c0519050602082610c8001015260208101905080610c8052610c809050602060c0825160208401600060025af1610f3b57600080fd5b60c0519050610ae052606435610ae05114610f5557600080fd5b6001805460018254011015610f6957600080fd5b6001815401815550600154610d0052610d2060006020818352015b60016001610d0051161415610fb957610ae051610d205160208110610fa857600080fd5b600060c052602060c020015561104d565b6000610d205160208110610fcc57600080fd5b600060c052602060c0200154602082610d40010152602081019050610ae051602082610d4001015260208101905080610d4052610d409050602060c0825160208401600060025af161101d57600080fd5b60c0519050610ae052610d00600261103457600080fd5b60028151048152505b8151600101808352811415610f84575b5050005b60006000fd5b61017f6111d60361017f60003961017f6111d6036000f3"} \ No newline at end of file diff --git a/deposit_contract/contracts/validator_registration.v.py b/deposit_contract/contracts/validator_registration.v.py index bad619b07..6ee27db7a 100644 --- a/deposit_contract/contracts/validator_registration.v.py +++ b/deposit_contract/contracts/validator_registration.v.py @@ -1,10 +1,11 @@ +# Vyper target 0.1.0b12 MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000 # Gwei DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32 MAX_DEPOSIT_COUNT: constant(uint256) = 4294967295 # 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1 PUBKEY_LENGTH: constant(uint256) = 48 # bytes WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32 # bytes -AMOUNT_LENGTH: constant(uint256) = 8 # bytes SIGNATURE_LENGTH: constant(uint256) = 96 # bytes +AMOUNT_LENGTH: constant(uint256) = 8 # bytes DepositEvent: event({ pubkey: bytes[48], @@ -42,7 +43,7 @@ def to_little_endian_64(value: uint256) -> bytes[8]: @public @constant -def get_hash_tree_root() -> bytes32: +def get_deposit_root() -> bytes32: zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 node: bytes32 = zero_bytes32 size: uint256 = self.deposit_count @@ -65,13 +66,16 @@ def get_deposit_count() -> bytes[8]: @public def deposit(pubkey: bytes[PUBKEY_LENGTH], withdrawal_credentials: bytes[WITHDRAWAL_CREDENTIALS_LENGTH], - signature: bytes[SIGNATURE_LENGTH]): + signature: bytes[SIGNATURE_LENGTH], + deposit_data_root: bytes32): # Avoid overflowing the Merkle tree (and prevent edge case in computing `self.branch`) assert self.deposit_count < MAX_DEPOSIT_COUNT - # Validate deposit data + # Check deposit amount deposit_amount: uint256 = msg.value / as_wei_value(1, "gwei") assert deposit_amount >= MIN_DEPOSIT_AMOUNT + + # Length checks to facilitate formal verification (see https://github.com/ethereum/eth2.0-specs/pull/1362/files#r320361859) assert len(pubkey) == PUBKEY_LENGTH assert len(withdrawal_credentials) == WITHDRAWAL_CREDENTIALS_LENGTH assert len(signature) == SIGNATURE_LENGTH @@ -80,7 +84,7 @@ def deposit(pubkey: bytes[PUBKEY_LENGTH], amount: bytes[8] = self.to_little_endian_64(deposit_amount) log.DepositEvent(pubkey, withdrawal_credentials, amount, signature, self.to_little_endian_64(self.deposit_count)) - # Compute `DepositData` hash tree root + # Compute deposit data root (`DepositData` hash tree root) zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 pubkey_root: bytes32 = sha256(concat(pubkey, slice(zero_bytes32, start=0, len=64 - PUBKEY_LENGTH))) signature_root: bytes32 = sha256(concat( @@ -91,8 +95,10 @@ def deposit(pubkey: bytes[PUBKEY_LENGTH], sha256(concat(pubkey_root, withdrawal_credentials)), sha256(concat(amount, slice(zero_bytes32, start=0, len=32 - AMOUNT_LENGTH), signature_root)), )) + # Verify computed and expected deposit data roots match + assert node == deposit_data_root - # Add `DepositData` hash tree root to Merkle tree (update a single `branch` node) + # Add deposit data root to Merkle tree (update a single `branch` node) self.deposit_count += 1 size: uint256 = self.deposit_count for height in range(DEPOSIT_CONTRACT_TREE_DEPTH): diff --git a/deposit_contract/requirements-testing.txt b/deposit_contract/requirements-testing.txt index 280d7e527..0b3d9d22c 100644 --- a/deposit_contract/requirements-testing.txt +++ b/deposit_contract/requirements-testing.txt @@ -1,5 +1,5 @@ eth-tester[py-evm]==0.1.0b39 -vyper==0.1.0b10 +vyper==0.1.0b12 web3==5.0.0b2 pytest==3.6.1 ../test_libs/pyspec diff --git a/deposit_contract/tests/contracts/test_deposit.py b/deposit_contract/tests/contracts/test_deposit.py index 1c96d074e..01586d070 100644 --- a/deposit_contract/tests/contracts/test_deposit.py +++ b/deposit_contract/tests/contracts/test_deposit.py @@ -6,7 +6,6 @@ import pytest import eth_utils from tests.contracts.conftest import ( - DEPOSIT_CONTRACT_TREE_DEPTH, FULL_DEPOSIT_AMOUNT, MIN_DEPOSIT_AMOUNT, ) @@ -14,29 +13,42 @@ from tests.contracts.conftest import ( from eth2spec.phase0.spec import ( DepositData, ) -from eth2spec.utils.hash_function import hash from eth2spec.utils.ssz.ssz_typing import List from eth2spec.utils.ssz.ssz_impl import ( hash_tree_root, ) +SAMPLE_PUBKEY = b'\x11' * 48 +SAMPLE_WITHDRAWAL_CREDENTIALS = b'\x22' * 32 +SAMPLE_VALID_SIGNATURE = b'\x33' * 96 + + @pytest.fixture -def deposit_input(): +def deposit_input(amount): """ pubkey: bytes[48] withdrawal_credentials: bytes[32] signature: bytes[96] + deposit_data_root: bytes[32] """ return ( - b'\x11' * 48, - b'\x22' * 32, - b'\x33' * 96, + SAMPLE_PUBKEY, + SAMPLE_WITHDRAWAL_CREDENTIALS, + SAMPLE_VALID_SIGNATURE, + hash_tree_root( + DepositData( + pubkey=SAMPLE_PUBKEY, + withdrawal_credentials=SAMPLE_WITHDRAWAL_CREDENTIALS, + amount=amount, + signature=SAMPLE_VALID_SIGNATURE, + ), + ) ) @pytest.mark.parametrize( - 'success,deposit_amount', + ('success', 'amount'), [ (True, FULL_DEPOSIT_AMOUNT), (True, MIN_DEPOSIT_AMOUNT), @@ -47,18 +59,24 @@ def deposit_input(): def test_deposit_amount(registration_contract, w3, success, - deposit_amount, + amount, assert_tx_failed, deposit_input): call = registration_contract.functions.deposit(*deposit_input) if success: - assert call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) + assert call.transact({"value": amount * eth_utils.denoms.gwei}) else: assert_tx_failed( - lambda: call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) + lambda: call.transact({"value": amount * eth_utils.denoms.gwei}) ) +@pytest.mark.parametrize( + 'amount', + [ + (FULL_DEPOSIT_AMOUNT) + ] +) @pytest.mark.parametrize( 'invalid_pubkey,invalid_withdrawal_credentials,invalid_signature,success', [ @@ -71,38 +89,62 @@ def test_deposit_amount(registration_contract, def test_deposit_inputs(registration_contract, w3, assert_tx_failed, - deposit_input, + amount, invalid_pubkey, invalid_withdrawal_credentials, invalid_signature, success): - pubkey = deposit_input[0][2:] if invalid_pubkey else deposit_input[0] - if invalid_withdrawal_credentials: # this one is different to satisfy linter - withdrawal_credentials = deposit_input[1][2:] - else: - withdrawal_credentials = deposit_input[1] - signature = deposit_input[2][2:] if invalid_signature else deposit_input[2] + pubkey = SAMPLE_PUBKEY[2:] if invalid_pubkey else SAMPLE_PUBKEY + withdrawal_credentials = ( + SAMPLE_WITHDRAWAL_CREDENTIALS[2:] if invalid_withdrawal_credentials + else SAMPLE_WITHDRAWAL_CREDENTIALS + ) + signature = SAMPLE_VALID_SIGNATURE[2:] if invalid_signature else SAMPLE_VALID_SIGNATURE call = registration_contract.functions.deposit( pubkey, withdrawal_credentials, signature, + hash_tree_root( + DepositData( + pubkey=SAMPLE_PUBKEY if invalid_pubkey else pubkey, + withdrawal_credentials=( + SAMPLE_WITHDRAWAL_CREDENTIALS if invalid_withdrawal_credentials + else withdrawal_credentials + ), + amount=amount, + signature=SAMPLE_VALID_SIGNATURE if invalid_signature else signature, + ), + ) ) if success: - assert call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) + assert call.transact({"value": amount * eth_utils.denoms.gwei}) else: assert_tx_failed( - lambda: call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) + lambda: call.transact({"value": amount * eth_utils.denoms.gwei}) ) -def test_deposit_event_log(registration_contract, a0, w3, deposit_input): +def test_deposit_event_log(registration_contract, a0, w3): log_filter = registration_contract.events.DepositEvent.createFilter( fromBlock='latest', ) - deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(3)] + for i in range(3): + deposit_input = ( + SAMPLE_PUBKEY, + SAMPLE_WITHDRAWAL_CREDENTIALS, + SAMPLE_VALID_SIGNATURE, + hash_tree_root( + DepositData( + pubkey=SAMPLE_PUBKEY, + withdrawal_credentials=SAMPLE_WITHDRAWAL_CREDENTIALS, + amount=deposit_amount_list[i], + signature=SAMPLE_VALID_SIGNATURE, + ), + ) + ) registration_contract.functions.deposit( *deposit_input, ).transact({"value": deposit_amount_list[i] * eth_utils.denoms.gwei}) @@ -118,7 +160,7 @@ def test_deposit_event_log(registration_contract, a0, w3, deposit_input): assert log['index'] == i.to_bytes(8, 'little') -def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input): +def test_deposit_tree(registration_contract, w3, assert_tx_failed): log_filter = registration_contract.events.DepositEvent.createFilter( fromBlock='latest', ) @@ -126,6 +168,20 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(10)] deposit_data_list = [] for i in range(0, 10): + deposit_data = DepositData( + pubkey=SAMPLE_PUBKEY, + withdrawal_credentials=SAMPLE_WITHDRAWAL_CREDENTIALS, + amount=deposit_amount_list[i], + signature=SAMPLE_VALID_SIGNATURE, + ) + deposit_input = ( + SAMPLE_PUBKEY, + SAMPLE_WITHDRAWAL_CREDENTIALS, + SAMPLE_VALID_SIGNATURE, + hash_tree_root(deposit_data), + ) + deposit_data_list.append(deposit_data) + tx_hash = registration_contract.functions.deposit( *deposit_input, ).transact({"value": deposit_amount_list[i] * eth_utils.denoms.gwei}) @@ -138,12 +194,8 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input assert log["index"] == i.to_bytes(8, 'little') - deposit_data_list.append(DepositData( - pubkey=deposit_input[0], - withdrawal_credentials=deposit_input[1], - amount=deposit_amount_list[i], - signature=deposit_input[2], - )) - + # Check deposit count and root + count = len(deposit_data_list).to_bytes(8, 'little') + assert count == registration_contract.functions.get_deposit_count().call() root = hash_tree_root(List[DepositData, 2**32](*deposit_data_list)) - assert root == registration_contract.functions.get_hash_tree_root().call() + assert root == registration_contract.functions.get_deposit_root().call() diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 5b1fa6fcf..ffdbda505 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -289,18 +289,20 @@ def build_phase0_spec(phase0_sourcefile: str, fork_choice_sourcefile: str, return spec -def build_phase1_spec(phase0_sourcefile: str, - fork_choice_sourcefile: str, +def build_phase1_spec(phase0_beacon_sourcefile: str, + phase0_fork_choice_sourcefile: str, + merkle_proofs_sourcefile: str, phase1_custody_sourcefile: str, phase1_shard_sourcefile: str, - merkle_proofs_sourcefile: str, + phase1_beacon_misc_sourcefile: str, outfile: str=None) -> Optional[str]: all_sourcefiles = ( - phase0_sourcefile, - fork_choice_sourcefile, + phase0_beacon_sourcefile, + phase0_fork_choice_sourcefile, + merkle_proofs_sourcefile, phase1_custody_sourcefile, phase1_shard_sourcefile, - merkle_proofs_sourcefile, + phase1_beacon_misc_sourcefile, ) all_spescs = [get_spec(spec) for spec in all_sourcefiles] for spec in all_spescs: @@ -327,10 +329,11 @@ If building phase 0: If building phase 1: 1st argument is input /core/0_beacon-chain.md 2nd argument is input /core/0_fork-choice.md - 3rd argument is input /core/1_custody-game.md - 4th argument is input /core/1_shard-data-chains.md - 5th argument is input /light_client/merkle_proofs.md - 6th argument is output spec.py + 3rd argument is input /light_client/merkle_proofs.md + 4th argument is input /core/1_custody-game.md + 5th argument is input /core/1_shard-data-chains.md + 6th argument is input /core/1_beacon-chain-misc.md + 7th argument is output spec.py ''' parser = ArgumentParser(description=description) parser.add_argument("-p", "--phase", dest="phase", type=int, default=0, help="Build for phase #") @@ -343,14 +346,14 @@ If building phase 1: else: print(" Phase 0 requires spec, forkchoice, and v-guide inputs as well as an output file.") elif args.phase == 1: - if len(args.files) == 6: + if len(args.files) == 7: build_phase1_spec(*args.files) else: print( " Phase 1 requires input files as well as an output file:\n" "\t core/phase_0: (0_beacon-chain.md, 0_fork-choice.md)\n" - "\t core/phase_1: (1_custody-game.md, 1_shard-data-chains.md)\n" "\t light_client: (merkle_proofs.md)\n" + "\t core/phase_1: (1_custody-game.md, 1_shard-data-chains.md, 1_beacon-chain-misc.md)\n" "\t and output.py" ) else: diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 01a6ca352..681d82457 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -19,7 +19,7 @@ - [State list lengths](#state-list-lengths) - [Rewards and penalties](#rewards-and-penalties) - [Max operations per block](#max-operations-per-block) - - [Signature domain types](#signature-domain-types) + - [Domain types](#domain-types) - [Containers](#containers) - [Misc dependencies](#misc-dependencies) - [`Fork`](#fork) @@ -67,6 +67,7 @@ - [`is_valid_merkle_branch`](#is_valid_merkle_branch) - [Misc](#misc-1) - [`compute_shuffled_index`](#compute_shuffled_index) + - [`compute_proposer_index`](#compute_proposer_index) - [`compute_committee`](#compute_committee) - [`compute_epoch_of_slot`](#compute_epoch_of_slot) - [`compute_start_slot_of_epoch`](#compute_start_slot_of_epoch) @@ -147,7 +148,7 @@ We define the following Python custom types for type hinting and readability: | `Gwei` | `uint64` | an amount in Gwei | | `Hash` | `Bytes32` | a hash | | `Version` | `Bytes4` | a fork version number | -| `DomainType` | `Bytes4` | a signature domain type | +| `DomainType` | `Bytes4` | a domain type | | `Domain` | `Bytes8` | a signature domain | | `BLSPubkey` | `Bytes48` | a BLS12-381 public key | | `BLSSignature` | `Bytes96` | a BLS12-381 signature | @@ -209,7 +210,7 @@ The following values are (non-configurable) constants used throughout the specif | `MIN_ATTESTATION_INCLUSION_DELAY` | `2**0` (= 1) | slots | 6 seconds | | `SLOTS_PER_EPOCH` | `2**6` (= 64) | slots | 6.4 minutes | | `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes | -| `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes | +| `MAX_SEED_LOOKAHEAD` | `2**2` (= 4) | epochs | 25.6 minutes | | `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours | | `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours | | `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours | @@ -249,15 +250,15 @@ The following values are (non-configurable) constants used throughout the specif | `MAX_VOLUNTARY_EXITS` | `2**4` (= 16) | | `MAX_TRANSFERS` | `0` | -### Signature domain types +### Domain types The following types are defined, mapping into `DomainType` (little endian): | Name | Value | | - | - | | `DOMAIN_BEACON_PROPOSER` | `0` | -| `DOMAIN_RANDAO` | `1` | -| `DOMAIN_ATTESTATION` | `2` | +| `DOMAIN_BEACON_ATTESTER` | `1` | +| `DOMAIN_RANDAO` | `2` | | `DOMAIN_DEPOSIT` | `3` | | `DOMAIN_VOLUNTARY_EXIT` | `4` | | `DOMAIN_TRANSFER` | `5` | @@ -670,7 +671,7 @@ def is_valid_indexed_attestation(state: BeaconState, indexed_attestation: Indexe hash_tree_root(AttestationDataAndCustodyBit(data=indexed_attestation.data, custody_bit=0b1)), ], signature=indexed_attestation.signature, - domain=get_domain(state, DOMAIN_ATTESTATION, indexed_attestation.data.target.epoch), + domain=get_domain(state, DOMAIN_BEACON_ATTESTER, indexed_attestation.data.target.epoch), ): return False return True @@ -717,6 +718,25 @@ def compute_shuffled_index(index: ValidatorIndex, index_count: uint64, seed: Has return ValidatorIndex(index) ``` +#### `compute_proposer_index` + +```python +def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Hash) -> ValidatorIndex: + """ + Return from ``indices`` a random index sampled by effective balance. + """ + assert len(indices) > 0 + MAX_RANDOM_BYTE = 2**8 - 1 + i = 0 + while True: + candidate_index = indices[compute_shuffled_index(ValidatorIndex(i % len(indices)), len(indices), seed)] + random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32] + effective_balance = state.validators[candidate_index].effective_balance + if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: + return ValidatorIndex(candidate_index) + i += 1 +``` + #### `compute_committee` ```python @@ -759,7 +779,7 @@ def compute_activation_exit_epoch(epoch: Epoch) -> Epoch: """ Return the epoch during which validator activations and exits initiated in ``epoch`` take effect. """ - return Epoch(epoch + 1 + ACTIVATION_EXIT_DELAY) + return Epoch(epoch + 1 + MAX_SEED_LOOKAHEAD) ``` #### `compute_domain` @@ -850,12 +870,12 @@ def get_validator_churn_limit(state: BeaconState) -> uint64: #### `get_seed` ```python -def get_seed(state: BeaconState, epoch: Epoch) -> Hash: +def get_seed(state: BeaconState, epoch: Epoch, domain_type: DomainType) -> Hash: """ Return the seed at ``epoch``. """ mix = get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD - 1)) # Avoid underflow - return hash(mix + int_to_bytes(epoch, length=32)) + return hash(domain_type + int_to_bytes(epoch, length=8) + mix) ``` #### `get_committee_count` @@ -881,7 +901,7 @@ def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard) -> S """ return compute_committee( indices=get_active_validator_indices(state, epoch), - seed=get_seed(state, epoch), + seed=get_seed(state, epoch, DOMAIN_BEACON_ATTESTER), index=(shard + SHARD_COUNT - get_start_shard(state, epoch)) % SHARD_COUNT, count=get_committee_count(state, epoch), ) @@ -921,20 +941,9 @@ def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex: Return the beacon proposer index at the current slot. """ epoch = get_current_epoch(state) - committees_per_slot = get_committee_count(state, epoch) // SLOTS_PER_EPOCH - offset = committees_per_slot * (state.slot % SLOTS_PER_EPOCH) - shard = Shard((get_start_shard(state, epoch) + offset) % SHARD_COUNT) - first_committee = get_crosslink_committee(state, epoch, shard) - MAX_RANDOM_BYTE = 2**8 - 1 - seed = get_seed(state, epoch) - i = 0 - while True: - candidate_index = first_committee[(epoch + i) % len(first_committee)] - random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32] - effective_balance = state.validators[candidate_index].effective_balance - if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: - return ValidatorIndex(candidate_index) - i += 1 + seed = hash(get_seed(state, epoch, DOMAIN_BEACON_PROPOSER) + int_to_bytes(state.slot, length=8)) + indices = get_active_validator_indices(state, epoch) + return compute_proposer_index(state, indices, seed) ``` #### `get_attestation_data_slot` @@ -1196,6 +1205,7 @@ def process_epoch(state: BeaconState) -> None: # @process_reveal_deadlines # @process_challenge_deadlines process_slashings(state) + # @update_period_committee process_final_updates(state) # @after_process_final_updates ``` @@ -1549,6 +1559,7 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: (body.deposits, process_deposit), (body.voluntary_exits, process_voluntary_exit), (body.transfers, process_transfer), + # @process_shard_receipt_proofs ): for operation in operations: function(state, operation) @@ -1559,9 +1570,8 @@ def process_operations(state: BeaconState, body: BeaconBlockBody) -> None: ```python def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None: proposer = state.validators[proposer_slashing.proposer_index] - # Verify that the epoch is the same - assert (compute_epoch_of_slot(proposer_slashing.header_1.slot) - == compute_epoch_of_slot(proposer_slashing.header_2.slot)) + # Verify slots match + assert proposer_slashing.header_1.slot == proposer_slashing.header_2.slot # But the headers are different assert proposer_slashing.header_1 != proposer_slashing.header_2 # Check proposer is slashable @@ -1615,11 +1625,6 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: proposer_index=get_beacon_proposer_index(state), ) - # Check bitlist lengths - committee_size = get_committee_count(state, attestation.data.target.epoch) - assert len(attestation.aggregation_bits) == committee_size - assert len(attestation.custody_bits) == committee_size - if data.target.epoch == get_current_epoch(state): assert data.source == state.current_justified_checkpoint parent_crosslink = state.current_crosslinks[data.crosslink.shard] diff --git a/specs/core/0_deposit-contract.md b/specs/core/0_deposit-contract.md index ade1006a0..06962594e 100644 --- a/specs/core/0_deposit-contract.md +++ b/specs/core/0_deposit-contract.md @@ -34,11 +34,11 @@ This document represents the specification for the beacon chain deposit contract ## Ethereum 1.0 deposit contract -The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards in Phase 2 (i.e. when the EVM 2.0 is deployed and the shards have state). +The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards in Phase 2. ### `deposit` function -The deposit contract has a public `deposit` function to make deposits. It takes as arguments `pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96]` corresponding to a [`DepositData`](./0_beacon-chain.md#depositdata) object. +The deposit contract has a public `deposit` function to make deposits. It takes as arguments `pubkey: bytes[48], withdrawal_credentials: bytes[32], signature: bytes[96], deposit_data_root: bytes32`. The first three arguments populate a [`DepositData`](./0_beacon-chain.md#depositdata) object, and `deposit_data_root` is the expected `DepositData` root as a protection against malformatted calldata. #### Deposit amount diff --git a/specs/core/1_beacon-chain-misc.md b/specs/core/1_beacon-chain-misc.md new file mode 100644 index 000000000..5bb0f6da0 --- /dev/null +++ b/specs/core/1_beacon-chain-misc.md @@ -0,0 +1,238 @@ +# Phase 1 miscellaneous beacon chain changes + +## Table of contents + + + +- [Phase 1 miscellaneous beacon chain changes](#phase-1-miscellaneous-beacon-chain-changes) + - [Table of contents](#table-of-contents) + - [Configuration](#configuration) + - [Containers](#containers) + - [`CompactCommittee`](#compactcommittee) + - [`ShardReceiptProof`](#shardreceiptproof) + - [Helper functions](#helper-functions) + - [`pack_compact_validator`](#pack_compact_validator) + - [`unpack_compact_validator`](#unpack_compact_validator) + - [`committee_to_compact_committee`](#committee_to_compact_committee) + - [`verify_merkle_proof`](#verify_merkle_proof) + - [`compute_historical_state_generalized_index`](#compute_historical_state_generalized_index) + - [`get_generalized_index_of_crosslink_header`](#get_generalized_index_of_crosslink_header) + - [`process_shard_receipt_proof`](#process_shard_receipt_proof) + - [Changes](#changes) + - [Phase 0 container updates](#phase-0-container-updates) + - [`BeaconState`](#beaconstate) + - [`BeaconBlockBody`](#beaconblockbody) + - [Persistent committees](#persistent-committees) + - [Shard receipt processing](#shard-receipt-processing) + + + +## Configuration + +| Name | Value | Unit | Duration +| - | - | - | - | +| `MAX_SHARD_RECEIPT_PROOFS` | `2**0` (= 1) | - | - | +| `PERIOD_COMMITTEE_ROOT_LENGTH` | `2**8` (= 256) | periods | ~9 months | +| `MINOR_REWARD_QUOTIENT` | `2**8` (=256) | - | - | + +## Containers + +#### `CompactCommittee` + +```python +class CompactCommittee(Container): + pubkeys: List[BLSPubkey, MAX_VALIDATORS_PER_COMMITTEE] + compact_validators: List[uint64, MAX_VALIDATORS_PER_COMMITTEE] +``` + +#### `ShardReceiptProof` + +```python +class ShardReceiptProof(Container): + shard: Shard + proof: List[Hash, PLACEHOLDER] + receipt: List[ShardReceiptDelta, PLACEHOLDER] +``` + +## Helper functions + +#### `pack_compact_validator` + +```python +def pack_compact_validator(index: int, slashed: bool, balance_in_increments: int) -> int: + """ + Creates a compact validator object representing index, slashed status, and compressed balance. + Takes as input balance-in-increments (// EFFECTIVE_BALANCE_INCREMENT) to preserve symmetry with + the unpacking function. + """ + return (index << 16) + (slashed << 15) + balance_in_increments +``` + +#### `unpack_compact_validator` + +```python +def unpack_compact_validator(compact_validator: int) -> Tuple[int, bool, int]: + """ + Returns validator index, slashed, balance // EFFECTIVE_BALANCE_INCREMENT + """ + return compact_validator >> 16, bool((compact_validator >> 15) % 2), compact_validator & (2**15 - 1) +``` + +#### `committee_to_compact_committee` + +```python +def committee_to_compact_committee(state: BeaconState, committee: Sequence[ValidatorIndex]) -> CompactCommittee: + """ + Given a state and a list of validator indices, outputs the CompactCommittee representing them. + """ + validators = [state.validators[i] for i in committee] + compact_validators = [ + pack_compact_validator(i, v.slashed, v.effective_balance // EFFECTIVE_BALANCE_INCREMENT) + for i, v in zip(committee, validators) + ] + pubkeys = [v.pubkey for v in validators] + return CompactCommittee(pubkeys=pubkeys, compact_validators=compact_validators) +``` + +#### `verify_merkle_proof` + +```python +def verify_merkle_proof(leaf: Hash, proof: Sequence[Hash], index: GeneralizedIndex, root: Hash) -> bool: + assert len(proof) == get_generalized_index_length(index) + for i, h in enumerate(proof): + if get_generalized_index_bit(index, i): + leaf = hash(h + leaf) + else: + leaf = hash(leaf + h) + return leaf == root +``` + +#### `compute_historical_state_generalized_index` + +```python +def compute_historical_state_generalized_index(earlier: ShardSlot, later: ShardSlot) -> GeneralizedIndex: + """ + Computes the generalized index of the state root of slot `frm` based on the state root of slot `to`. + Relies on the `history_acc` in the `ShardState`, where `history_acc[i]` maintains the most recent 2**i'th + slot state. Works by tracing a `log(later-earlier)` step path from `later` to `earlier` through intermediate + blocks at the next available multiples of descending powers of two. + """ + o = GeneralizedIndex(1) + for i in range(HISTORY_ACCUMULATOR_VECTOR - 1, -1, -1): + if (later - 1) & 2**i > (earlier - 1) & 2**i: + later = later - ((later - 1) % 2**i) - 1 + o = concat_generalized_indices(o, GeneralizedIndex(get_generalized_index(ShardState, ['history_acc', i]))) + return o +``` + +#### `get_generalized_index_of_crosslink_header` + +```python +def get_generalized_index_of_crosslink_header(index: int) -> GeneralizedIndex: + """ + Gets the generalized index for the root of the index'th header in a crosslink. + """ + MAX_CROSSLINK_SIZE = ( + SHARD_BLOCK_SIZE_LIMIT * SHARD_SLOTS_PER_BEACON_SLOT * SLOTS_PER_EPOCH * MAX_EPOCHS_PER_CROSSLINK + ) + assert MAX_CROSSLINK_SIZE == get_previous_power_of_two(MAX_CROSSLINK_SIZE) + return GeneralizedIndex(MAX_CROSSLINK_SIZE // SHARD_HEADER_SIZE + index) +``` + +#### `process_shard_receipt_proof` + +```python +def process_shard_receipt_proof(state: BeaconState, receipt_proof: ShardReceiptProof) -> None: + """ + Processes a ShardReceipt object. + """ + SHARD_SLOTS_PER_EPOCH = SHARD_SLOTS_PER_BEACON_SLOT * SLOTS_PER_EPOCH + receipt_slot = ( + state.next_shard_receipt_period[receipt_proof.shard] * + SHARD_SLOTS_PER_BEACON_SLOT * SLOTS_PER_EPOCH * EPOCHS_PER_SHARD_PERIOD + ) + first_slot_in_last_crosslink = state.current_crosslinks[receipt_proof.shard].start_epoch * SHARD_SLOTS_PER_EPOCH + gindex = concat_generalized_indices( + get_generalized_index_of_crosslink_header(0), + GeneralizedIndex(get_generalized_index(ShardBlockHeader, 'state_root')), + compute_historical_state_generalized_index(receipt_slot, first_slot_in_last_crosslink), + GeneralizedIndex(get_generalized_index(ShardState, 'receipt_root')) + ) + assert verify_merkle_proof( + leaf=hash_tree_root(receipt_proof.receipt), + proof=receipt_proof.proof, + index=gindex, + root=state.current_crosslinks[receipt_proof.shard].data_root + ) + for delta in receipt_proof.receipt: + if get_current_epoch(state) < state.validators[delta.index].withdrawable_epoch: + increase_amount = ( + state.validators[delta.index].effective_balance * delta.reward_coefficient // REWARD_COEFFICIENT_BASE + ) + increase_balance(state, delta.index, increase_amount) + decrease_balance(state, delta.index, delta.block_fee) + state.next_shard_receipt_period[receipt_proof.shard] += 1 + proposer_index = get_beacon_proposer_index(state) + increase_balance(state, proposer_index, Gwei(get_base_reward(state, proposer_index) // MINOR_REWARD_QUOTIENT)) +``` + +## Changes + +### Phase 0 container updates + +Add the following fields to the end of the specified container objects. + +#### `BeaconState` + +```python +class BeaconState(Container): + # Period committees + period_committee_roots: Vector[Hash, PERIOD_COMMITTEE_ROOT_LENGTH] + next_shard_receipt_period: Vector[uint64, SHARD_COUNT] +``` + +`period_committee_roots` values are initialized to `Bytes32()` (empty bytes value). +`next_shard_receipt_period` values are initialized to `compute_epoch_of_slot(PHASE_1_FORK_SLOT) // EPOCHS_PER_SHARD_PERIOD`. + +#### `BeaconBlockBody` + +```python +class BeaconBlockBody(Container): + shard_receipt_proofs: List[ShardReceiptProof, MAX_SHARD_RECEIPT_PROOFS] +``` + +`shard_receipt_proofs` is initialized to `[]`. + +### Persistent committees + +Run `update_period_committee` immediately before `process_final_updates`: + +```python +# begin insert @update_period_committee + update_period_committee(state) +# end insert @update_period_committee +def update_period_committee(state: BeaconState) -> None: + """ + Updates period committee roots at boundary blocks. + """ + if (get_current_epoch(state) + 1) % EPOCHS_PER_SHARD_PERIOD == 0: + period = (get_current_epoch(state) + 1) // EPOCHS_PER_SHARD_PERIOD + committees = Vector[CompactCommittee, SHARD_COUNT]([ + committee_to_compact_committee( + state, + get_period_committee(state, Epoch(get_current_epoch(state) + 1), Shard(shard)), + ) + for shard in range(SHARD_COUNT) + ]) + state.period_committee_roots[period % PERIOD_COMMITTEE_ROOT_LENGTH] = hash_tree_root(committees) +``` + +### Shard receipt processing + +Run `process_shard_receipt_proof` on each `ShardReceiptProof` during block processing. + +```python +# begin insert @process_shard_receipt_proofs + (body.shard_receipt_proofs, process_shard_receipt_proof), +# end insert @process_shard_receipt_proofs +``` diff --git a/specs/core/1_custody-game.md b/specs/core/1_custody-game.md index d789a6855..158d575e2 100644 --- a/specs/core/1_custody-game.md +++ b/specs/core/1_custody-game.md @@ -77,7 +77,8 @@ This document details the beacon chain additions and changes in Phase 1 of Ether ## Constants ### Misc - +| Name | Value | +| - | - | | `BLS12_381_Q` | `4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787` | | `MINOR_REWARD_QUOTIENT` | `2**8` (= 256) | @@ -281,7 +282,7 @@ def ceillog2(x: uint64) -> int: ### `is_valid_merkle_branch_with_mixin` ```python -def is_valid_merkle_branch_with_mixin(leaf: Hash, +def is_valid_merkle_branch_with_mixin(leaf: Hash, branch: Sequence[Hash], depth: uint64, index: uint64, @@ -314,7 +315,7 @@ def legendre_bit(a: int, q: int) -> int: if a >= q: return legendre_bit(a % q, q) if a == 0: - return 0 + return 0 assert(q > a > 0 and q % 2 == 1) t = 1 n = q @@ -339,7 +340,7 @@ def legendre_bit(a: int, q: int) -> int: Given one proof of custody chunk, returns the proof of custody subchunks of the correct sizes. ```python -def custody_subchunkify(bytez: bytes) -> list: +def custody_subchunkify(bytez: bytes) -> Sequence[bytes]: bytez += b'\x00' * (-len(bytez) % BYTES_PER_CUSTODY_SUBCHUNK) return [bytez[i:i + BYTES_PER_CUSTODY_SUBCHUNK] for i in range(0, len(bytez), BYTES_PER_CUSTODY_SUBCHUNK)] @@ -601,7 +602,7 @@ def process_bit_challenge(state: BeaconState, challenge: CustodyBitChallenge) -> # Verify attestation is eligible for challenging responder = state.validators[challenge.responder_index] assert get_current_epoch(state) <= get_randao_epoch_for_custody_period( - get_custody_period_for_validator(state, challenge.responder_index, epoch), + get_custody_period_for_validator(state, challenge.responder_index, epoch), challenge.responder_index ) + 2 * EPOCHS_PER_CUSTODY_PERIOD + responder.max_reveal_lateness @@ -672,7 +673,7 @@ def process_chunk_challenge_response(state: BeaconState, # Verify bit challenge data is null assert response.chunk_bits_branch == [] and response.chunk_bits_leaf == Hash() # Verify minimum delay - assert get_current_epoch(state) >= challenge.inclusion_epoch + ACTIVATION_EXIT_DELAY + assert get_current_epoch(state) >= challenge.inclusion_epoch + MAX_SEED_LOOKAHEAD # Verify the chunk matches the crosslink data root assert is_valid_merkle_branch( leaf=hash_tree_root(response.chunk), diff --git a/specs/core/1_shard-data-chains.md b/specs/core/1_shard-data-chains.md index c985294aa..fceac061c 100644 --- a/specs/core/1_shard-data-chains.md +++ b/specs/core/1_shard-data-chains.md @@ -70,9 +70,9 @@ This document describes the shard transition function (data layer only) and the ### Initial values -| Name | Value | +| Name | Value | Unit | | - | - | -| `SHARD_GENESIS_EPOCH` | **TBD** | +| `SHARD_GENESIS_EPOCH` | **TBD** | Epoch | ### Time parameters @@ -182,7 +182,7 @@ def compute_shard_period_start_epoch(epoch: Epoch, lookback: uint64) -> Epoch: ```python def get_period_committee(beacon_state: BeaconState, shard: Shard, epoch: Epoch) -> Sequence[ValidatorIndex]: active_validator_indices = get_active_validator_indices(beacon_state, epoch) - seed = get_seed(beacon_state, epoch) + seed = get_seed(beacon_state, epoch, DOMAIN_SHARD_ATTESTER) return compute_committee(active_validator_indices, seed, shard, SHARD_COUNT)[:MAX_PERIOD_COMMITTEE_SIZE] ``` @@ -201,12 +201,16 @@ def get_shard_committee(beacon_state: BeaconState, shard: Shard, epoch: Epoch) - #### `get_shard_proposer_index` ```python -def get_shard_proposer_index(beacon_state: BeaconState, shard: Shard, slot: ShardSlot) -> ValidatorIndex: +def get_shard_proposer_index(beacon_state: BeaconState, shard: Shard, slot: ShardSlot) -> Optional[ValidatorIndex]: epoch = get_current_epoch(beacon_state) shard_committee = get_shard_committee(beacon_state, shard, epoch) active_indices = [i for i in shard_committee if is_active_validator(beacon_state.validators[i], epoch)] - seed = hash(get_seed(beacon_state, epoch) + int_to_bytes(slot, length=8) + int_to_bytes(shard, length=8)) - compute_proposer_index(beacon_state, active_indices, seed) + if not any(active_indices): + return None + + epoch_seed = get_seed(beacon_state, epoch, DOMAIN_SHARD_PROPOSER) + seed = hash(epoch_seed + int_to_bytes(slot, length=8) + int_to_bytes(shard, length=8)) + return compute_proposer_index(beacon_state, active_indices, seed) ``` ### Shard state mutators diff --git a/specs/light_client/merkle_proofs.md b/specs/light_client/merkle_proofs.md index ce7dc647c..b920f50b1 100644 --- a/specs/light_client/merkle_proofs.md +++ b/specs/light_client/merkle_proofs.md @@ -62,7 +62,7 @@ Note that the generalized index has the convenient property that the two childre def merkle_tree(leaves: Sequence[Hash]) -> Sequence[Hash]: padded_length = get_next_power_of_two(len(leaves)) o = [Hash()] * padded_length + list(leaves) + [Hash()] * (padded_length - len(leaves)) - for i in range(len(leaves) - 1, 0, -1): + for i in range(padded_length - 1, 0, -1): o[i] = hash(o[i * 2] + o[i * 2 + 1]) return o ``` @@ -152,7 +152,7 @@ def get_item_position(typ: SSZType, index_or_variable_name: Union[int, SSZVariab ``` ```python -def get_generalized_index(typ: SSZType, path: Sequence[Union[int, SSZVariableName]]) -> Optional[GeneralizedIndex]: +def get_generalized_index(typ: SSZType, path: Sequence[Union[int, SSZVariableName]]) -> GeneralizedIndex: """ Converts a path (eg. `[7, "foo", 3]` for `x[7].foo[3]`, `[12, "bar", "__len__"]` for `len(x[12].bar)`) into the generalized index representing its position in the Merkle tree. @@ -162,10 +162,8 @@ def get_generalized_index(typ: SSZType, path: Sequence[Union[int, SSZVariableNam assert not issubclass(typ, BasicValue) # If we descend to a basic type, the path cannot continue further if p == '__len__': typ = uint64 - if issubclass(typ, (List, Bytes)): - root = GeneralizedIndex(root * 2 + 1) - else: - return None + assert issubclass(typ, (List, Bytes)) + root = GeneralizedIndex(root * 2 + 1) else: pos, _, _ = get_item_position(typ, p) base_index = (GeneralizedIndex(2) if issubclass(typ, (List, Bytes)) else GeneralizedIndex(1)) @@ -181,7 +179,7 @@ _Usage note: functions outside this section should manipulate generalized indice #### `concat_generalized_indices` ```python -def concat_generalized_indices(indices: Sequence[GeneralizedIndex]) -> GeneralizedIndex: +def concat_generalized_indices(*indices: GeneralizedIndex) -> GeneralizedIndex: """ Given generalized indices i1 for A -> B, i2 for B -> C .... i_n for Y -> Z, returns the generalized index for A -> Z. diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 944abf8c1..c3b035270 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -15,7 +15,6 @@ - [`LightClientUpdate`](#lightclientupdate) - [Helpers](#helpers) - [`LightClientMemory`](#lightclientmemory) - - [`unpack_compact_validator`](#unpack_compact_validator) - [`get_persistent_committee_pubkeys_and_balances`](#get_persistent_committee_pubkeys_and_balances) - [Light client state updates](#light-client-state-updates) - [Data overhead](#data-overhead) @@ -77,20 +76,6 @@ class LightClientMemory(object): next_committee: CompactCommittee ``` -### `unpack_compact_validator` - -```python -def unpack_compact_validator(compact_validator: CompactValidator) -> Tuple[ValidatorIndex, bool, uint64]: - """ - Return the index, slashed, effective_balance // EFFECTIVE_BALANCE_INCREMENT of ``compact_validator``. - """ - return ( - ValidatorIndex(compact_validator >> 16), - (compact_validator >> 15) % 2, - uint64(compact_validator & (2**15 - 1)), - ) -``` - ### `get_persistent_committee_pubkeys_and_balances` ```python diff --git a/specs/networking/p2p-interface.md b/specs/networking/p2p-interface.md index b3e0db50e..c9bab8406 100644 --- a/specs/networking/p2p-interface.md +++ b/specs/networking/p2p-interface.md @@ -160,7 +160,7 @@ Additional topics are used to propagate lower frequency validator messages. Thei #### Interop -Unaggregated and aggregated attestations from all shards are sent to the `beacon_attestation` topic. Clients are not required to publish aggregate attestations but must be able to process them. +Unaggregated and aggregated attestations from all shards are sent to the `beacon_attestation` topic. Clients are not required to publish aggregate attestations but must be able to process them. All validating clients SHOULD try to perform local attestation aggregation to prepare for block proposing. #### Mainnet @@ -301,7 +301,7 @@ Here, `result` represents the 1-byte response code. The token of the negotiated protocol ID specifies the type of encoding to be used for the req/resp interaction. Two values are possible at this time: -- `ssz`: The contents are [SSZ-encoded](../simple-serialize.md). This encoding type MUST be supported by all clients. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the `BeaconBlocks` response would be an SSZ-encoded list of `BeaconBlock`s. All SSZ-Lists in the Req/Resp domain will have a maximum list size of `SSZ_MAX_LIST_SIZE`. +- `ssz`: the contents are [SSZ-encoded](#ssz-encoding). This encoding type MUST be supported by all clients. For objects containing a single field, only the field is SSZ-encoded not a container with a single field. For example, the `BeaconBlocks` response would be an SSZ-encoded list of `BeaconBlock`s. All SSZ-Lists in the Req/Resp domain will have a maximum list size of `SSZ_MAX_LIST_SIZE`. - `ssz_snappy`: The contents are SSZ-encoded and then compressed with [Snappy](https://github.com/google/snappy). MAY be supported in the interoperability testnet; MUST be supported in mainnet. #### SSZ-encoding strategy (with or without Snappy) diff --git a/specs/simple-serialize.md b/specs/simple-serialize.md index 588200f20..5e17962d1 100644 --- a/specs/simple-serialize.md +++ b/specs/simple-serialize.md @@ -63,7 +63,7 @@ * **bitlist**: ordered variable-length collection of `boolean` values, limited to `N` bits * notation `Bitlist[N]` * **union**: union type containing one of the given subtypes - * notation `Union[type_1, type_2, ...]`, e.g. `union[null, uint64]` + * notation `Union[type_0, type_1, ...]`, e.g. `union[null, uint64]` ### Variable-size and fixed-size @@ -79,8 +79,18 @@ For convenience we alias: * `null`: `{}` ### Default values +Assuming a helper function `default(type)` which returns the default value for `type`, we can recursively define the default value for all types. -The default value of a type upon initialization is recursively defined using `0` for `uintN`, `False` for `boolean` and the elements of `Bitvector`, and `[]` for lists and `Bitlist`. Unions default to the first type in the union (with type index zero), which is `null` if present in the union. +| Type | Default Value | +| ---- | ------------- | +| `uintN` | `0` | +| `boolean` | `False` | +| `Container` | `[default(type) for type in container]` | +| `Vector[type, N]` | `[default(type)] * N` | +| `Bitvector[boolean, N]` | `[False] * N` | +| `List[type, N]` | `[]` | +| `Bitlist[boolean, N]` | `[]` | +| `Union[type_0, type_1, ...]` | `default(type_0)` | #### `is_zero` diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index ef5ad4415..8a9cf1b5d 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -114,7 +114,7 @@ Once a validator has been processed and added to the beacon state's `validators` ### Activation -In normal operation, the validator is quickly activated, at which point the validator is added to the shuffling and begins validation after an additional `ACTIVATION_EXIT_DELAY` epochs (25.6 minutes). +In normal operation, the validator is quickly activated, at which point the validator is added to the shuffling and begins validation after an additional `MAX_SEED_LOOKAHEAD` epochs (25.6 minutes). The function [`is_active_validator`](../core/0_beacon-chain.md#is_active_validator) can be used to check if a validator is active during a given epoch. Usage is as follows: @@ -160,7 +160,7 @@ def get_committee_assignment(state: BeaconState, return None ``` -A validator can use the following function to see if they are supposed to propose during their assigned committee slot. This function can only be run with a `state` of the slot in question. Proposer selection is only stable within the context of the current epoch. +A validator can use the following function to see if they are supposed to propose during a slot. This function can only be run with a `state` of the slot in question. Proposer selection is only stable within the context of the current epoch. ```python def is_proposer(state: BeaconState, @@ -170,6 +170,8 @@ def is_proposer(state: BeaconState, *Note*: To see if a validator is assigned to propose during the slot, the beacon state must be in the epoch in question. At the epoch boundaries, the validator must run an epoch transition into the epoch to successfully check the proposal assignment of the first slot. +*Note*: `BeaconBlock` proposal is distinct from crosslink committee assignment, and in a given epoch each responsibility might occur at different a different slot. + ### Lookahead The beacon chain shufflings are designed to provide a minimum of 1 epoch lookahead on the validator's upcoming committee assignments for attesting dictated by the shuffling and slot. Note that this lookahead does not apply to proposing, which must be checked during the epoch in question. @@ -218,7 +220,7 @@ def get_epoch_signature(state: BeaconState, block: BeaconBlock, privkey: int) -> ##### Eth1 Data -The `block.eth1_data` field is for block proposers to vote on recent Eth 1.0 data. This recent data contains an Eth 1.0 block hash as well as the associated deposit root (as calculated by the `get_hash_tree_root()` method of the deposit contract) and deposit count after execution of the corresponding Eth 1.0 block. If over half of the block proposers in the current Eth 1.0 voting period vote for the same `eth1_data` then `state.eth1_data` updates at the end of the voting period. Each deposit in `block.body.deposits` must verify against `state.eth1_data.eth1_deposit_root`. +The `block.eth1_data` field is for block proposers to vote on recent Eth 1.0 data. This recent data contains an Eth 1.0 block hash as well as the associated deposit root (as calculated by the `get_deposit_root()` method of the deposit contract) and deposit count after execution of the corresponding Eth 1.0 block. If over half of the block proposers in the current Eth 1.0 voting period vote for the same `eth1_data` then `state.eth1_data` updates at the end of the voting period. Each deposit in `block.body.deposits` must verify against `state.eth1_data.eth1_deposit_root`. Let `get_eth1_data(distance: uint64) -> Eth1Data` be the (subjective) function that returns the Eth 1.0 data at distance `distance` relative to the Eth 1.0 head at the start of the current Eth 1.0 voting period. Let `previous_eth1_distance` be the distance relative to the Eth 1.0 block corresponding to `state.eth1_data.block_hash` at the start of the current Eth 1.0 voting period. An honest block proposer sets `block.eth1_data = get_eth1_vote(state, previous_eth1_distance)` where: @@ -343,7 +345,7 @@ def get_signed_attestation_data(state: BeaconState, attestation: IndexedAttestat custody_bit=0b0, ) - domain = get_domain(state, DOMAIN_ATTESTATION, attestation.data.target.epoch) + domain = get_domain(state, DOMAIN_BEACON_ATTESTER, attestation.data.target.epoch) return bls_sign(privkey, hash_tree_root(attestation_data_and_custody_bit), domain) ``` diff --git a/test_generators/ssz_generic/ssz_bitvector.py b/test_generators/ssz_generic/ssz_bitvector.py index 2b04577e8..d84614068 100644 --- a/test_generators/ssz_generic/ssz_bitvector.py +++ b/test_generators/ssz_generic/ssz_bitvector.py @@ -5,11 +5,19 @@ from random import Random from eth2spec.debug.random_value import RandomizationMode, get_random_ssz_object -def bitvector_case_fn(rng: Random, mode: RandomizationMode, size: int): - return get_random_ssz_object(rng, Bitvector[size], +def bitvector_case_fn(rng: Random, mode: RandomizationMode, size: int, invalid_making_pos: int=None): + bits = get_random_ssz_object(rng, Bitvector[size], max_bytes_length=(size + 7) // 8, max_list_length=size, mode=mode, chaos=False) + if invalid_making_pos is not None and invalid_making_pos <= size: + already_invalid = False + for i in range(invalid_making_pos, size): + if bits[i]: + already_invalid = True + if not already_invalid: + bits[invalid_making_pos] = True + return bits def valid_cases(): @@ -23,8 +31,12 @@ def invalid_cases(): # zero length bitvecors are illegal yield 'bitvec_0', invalid_test_case(lambda: b'') rng = Random(1234) + # Create a vector with test_size bits, but make the type typ_size instead, + # which is invalid when used with the given type size + # (and a bit set just after typ_size bits if necessary to avoid the valid 0 padding-but-same-last-byte case) for (typ_size, test_size) in [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (8, 9), (9, 8), (16, 8), (32, 33), (512, 513)]: for mode in [RandomizationMode.mode_random, RandomizationMode.mode_zero, RandomizationMode.mode_max]: yield f'bitvec_{typ_size}_{mode.to_name()}_{test_size}', \ - invalid_test_case(lambda: serialize(bitvector_case_fn(rng, mode, test_size))) + invalid_test_case(lambda: serialize(bitvector_case_fn(rng, mode, test_size, + invalid_making_pos=typ_size))) diff --git a/test_libs/pyspec/eth2spec/debug/random_value.py b/test_libs/pyspec/eth2spec/debug/random_value.py index 9a7d47239..ce1522c32 100644 --- a/test_libs/pyspec/eth2spec/debug/random_value.py +++ b/test_libs/pyspec/eth2spec/debug/random_value.py @@ -94,6 +94,8 @@ def get_random_ssz_object(rng: Random, length = 1 elif mode == RandomizationMode.mode_max_count: length = max_list_length + elif mode == RandomizationMode.mode_nil_count: + length = 0 if typ.length < length: # SSZ imposes a hard limit on lists, we can't put in more than that length = typ.length diff --git a/test_libs/pyspec/eth2spec/test/context.py b/test_libs/pyspec/eth2spec/test/context.py index 5cc42c510..80edaba9b 100644 --- a/test_libs/pyspec/eth2spec/test/context.py +++ b/test_libs/pyspec/eth2spec/test/context.py @@ -10,7 +10,7 @@ from .utils import vector_test, with_meta_tags def with_state(fn): def entry(*args, **kw): try: - kw['state'] = create_genesis_state(spec=kw['spec'], num_validators=spec_phase0.SLOTS_PER_EPOCH * 8) + kw['state'] = create_genesis_state(spec=kw['spec'], num_validators=spec_phase0.SLOTS_PER_EPOCH * 10) except KeyError: raise TypeError('Spec decorator must come within state decorator to inject spec into state.') return fn(*args, **kw) diff --git a/test_libs/pyspec/eth2spec/test/helpers/attestations.py b/test_libs/pyspec/eth2spec/test/helpers/attestations.py index 868517018..23d1a8f8f 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/attestations.py +++ b/test_libs/pyspec/eth2spec/test/helpers/attestations.py @@ -122,7 +122,7 @@ def get_attestation_signature(spec, state, attestation_data, privkey, custody_bi privkey=privkey, domain=spec.get_domain( state=state, - domain_type=spec.DOMAIN_ATTESTATION, + domain_type=spec.DOMAIN_BEACON_ATTESTER, message_epoch=attestation_data.target.epoch, ) ) diff --git a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py index d5b7f7b7f..ce53c5931 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py +++ b/test_libs/pyspec/eth2spec/test/helpers/proposer_slashings.py @@ -18,7 +18,6 @@ def get_valid_proposer_slashing(spec, state, signed_1=False, signed_2=False): ) header_2 = deepcopy(header_1) header_2.parent_root = b'\x99' * 32 - header_2.slot = slot + 1 if signed_1: sign_block_header(spec, state, header_1, privkey) diff --git a/test_libs/pyspec/eth2spec/test/merkle_proofs/test_merkle_proofs.py b/test_libs/pyspec/eth2spec/test/merkle_proofs/test_merkle_proofs.py index 91c861de3..62a2f6379 100644 --- a/test_libs/pyspec/eth2spec/test/merkle_proofs/test_merkle_proofs.py +++ b/test_libs/pyspec/eth2spec/test/merkle_proofs/test_merkle_proofs.py @@ -1,10 +1,10 @@ - import re from eth_utils import ( to_tuple, ) from eth2spec.test.context import ( + expect_assertion_error, spec_state_test, with_all_phases_except, ) @@ -89,10 +89,14 @@ generalized_index_cases = [ @spec_state_test def test_get_generalized_index(spec, state): for typ, path, generalized_index in generalized_index_cases: - assert spec.get_generalized_index( - typ=typ, - path=path, - ) == generalized_index + if generalized_index is not None: + assert spec.get_generalized_index( + typ=typ, + path=path, + ) == generalized_index + else: + expect_assertion_error(lambda: spec.get_generalized_index(typ=typ, path=path)) + yield 'typ', typ yield 'path', path yield 'generalized_index', generalized_index diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index ab6a74a70..bfd992ffa 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -21,7 +21,7 @@ def test_activation(spec, state): index = 0 mock_deposit(spec, state, index) - for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): + for _ in range(spec.MAX_SEED_LOOKAHEAD + 1): next_epoch(spec, state) yield from run_process_registry_updates(spec, state) @@ -73,7 +73,7 @@ def test_ejection(spec, state): # Mock an ejection state.validators[index].effective_balance = spec.EJECTION_BALANCE - for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): + for _ in range(spec.MAX_SEED_LOOKAHEAD + 1): next_epoch(spec, state) yield from run_process_registry_updates(spec, state) diff --git a/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_bit_challenge.py b/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_bit_challenge.py index e4880555a..ae6ff258c 100644 --- a/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_bit_challenge.py +++ b/test_libs/pyspec/eth2spec/test/phase_1/block_processing/test_process_bit_challenge.py @@ -212,13 +212,16 @@ def test_max_reveal_lateness_1(spec, state): challenge = get_valid_bit_challenge(spec, state, attestation) responder_index = challenge.responder_index + target_epoch = attestation.data.target.epoch state.validators[responder_index].max_reveal_lateness = 3 - for i in range(spec.get_randao_epoch_for_custody_period( - spec.get_custody_period_for_validator(state, responder_index), + latest_reveal_epoch = spec.get_randao_epoch_for_custody_period( + spec.get_custody_period_for_validator(state, responder_index, target_epoch), responder_index - ) + 2 * spec.EPOCHS_PER_CUSTODY_PERIOD + state.validators[responder_index].max_reveal_lateness - 2): + ) + 2 * spec.EPOCHS_PER_CUSTODY_PERIOD + state.validators[responder_index].max_reveal_lateness + + while spec.get_current_epoch(state) < latest_reveal_epoch - 2: next_epoch(spec, state) apply_empty_block(spec, state)