diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index f9acf5bf7..629badcee 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -17,6 +17,8 @@ MIN_PER_EPOCH_CHURN_LIMIT: 4 CHURN_LIMIT_QUOTIENT: 65536 # See issue 563 SHUFFLE_ROUND_COUNT: 90 +# `2**16` (= 65,536) +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 65536 # Deposit contract diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index 27ed9d15e..1d0ad015d 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -16,6 +16,8 @@ MIN_PER_EPOCH_CHURN_LIMIT: 4 CHURN_LIMIT_QUOTIENT: 65536 # [customized] Faster, but unsecure. SHUFFLE_ROUND_COUNT: 10 +# [customized] +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 64 # Deposit contract diff --git a/deposit_contract/contracts/validator_registration.json b/deposit_contract/contracts/validator_registration.json index 1988b28c0..527ce6087 100644 --- a/deposit_contract/contracts/validator_registration.json +++ b/deposit_contract/contracts/validator_registration.json @@ -1 +1 @@ -{"abi": [{"name": "Deposit", "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": 79221}, {"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": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b50506111c656600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63c5f2892f60005114156103cf57341561029057600080fd5b6000610140526001546101605261018060006020818352015b600160016101605116141561032a57600061018051602081106102cb57600080fd5b600060c052602060c02001546020826102200101526020810190506101405160208261022001015260208101905080610220526102209050602060c0825160208401600060025af161031c57600080fd5b60c051905061014052610398565b6000610140516020826101a0010152602081019050610180516020811061035057600080fd5b600260c052602060c02001546020826101a0010152602081019050806101a0526101a09050602060c0825160208401600060025af161038e57600080fd5b60c0519050610140525b61016060026103a657600080fd5b60028151048152505b81516001018083528114156102a9575b50506101405160005260206000f3005b63621fd13060005114156104e15734156103e857600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f8201039050610220511015156104335761044c565b610220516101e001526102205160200161022052610411565b6101c0805160200180610280828460006004600a8704601201f161046f57600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156104a1576104bd565b60006102e0516102a001535b8151600101808352811415610491575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561103b57606060046101403760506004356004016101a037603060043560040135111561051757600080fd5b604060243560040161022037602060243560040135111561053757600080fd5b608060443560040161028037606060443560040135111561055757600080fd5b63ffffffff6001541061056957600080fd5b633b9aca00610340526103405161057f57600080fd5b61034051340461032052633b9aca0061032051101561059d57600080fd5b60306101a051146105ad57600080fd5b602061022051146105bd57600080fd5b606061028051146105cd57600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a05110151561065d57610676565b6104a05161046001526104a0516020016104a05261063b565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f16106dd57600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a05110151561078e576107a7565b6105a05161056001526105a0516020016105a05261076c565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161082e57600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161086657600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156108a4576108c1565b6000610620516020850101535b8151600101808352811415610893575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f161091857600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b836106205110151561095657610973565b6000610620516020850101535b8151600101808352811415610945575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f16109ca57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a0857610a25565b6000610620516020850101535b81516001018083528114156109f7575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610a7c57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610aba57610ad7565b6000610620516020850101535b8151600101808352811415610aa9575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610b2e57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b6c57610b89565b6000610620516020850101535b8151600101808352811415610b5b575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527fdc5fc95703516abd38fa03c3737ff3b52dc52347055c8028460fdf5bbe2f12ce61064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610c2057600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610c8057600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610ca957600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610ce957600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610d1d57600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610d9a57600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610dd157600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610e3757600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610e8c57600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af1610eff57600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af1610f3657600080fd5b60c0519050610b00526001805460018254011015610f5357600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d2051161415610fa357610b0051610d405160208110610f9257600080fd5b600060c052602060c0200155611037565b6000610d405160208110610fb657600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161100757600080fd5b60c0519050610b0052610d20600261101e57600080fd5b60028151048152505b8151600101808352811415610f6e575b5050005b60006000fd5b6101856111c6036101856000396101856111c6036000f3"} \ 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_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": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b50506112ff56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63863a311b600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c561064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b6101856112ff036101856000396101856112ff036000f3"} \ 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 14f100520..bad619b07 100644 --- a/deposit_contract/contracts/validator_registration.v.py +++ b/deposit_contract/contracts/validator_registration.v.py @@ -6,7 +6,7 @@ WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32 # bytes AMOUNT_LENGTH: constant(uint256) = 8 # bytes SIGNATURE_LENGTH: constant(uint256) = 96 # bytes -Deposit: event({ +DepositEvent: event({ pubkey: bytes[48], withdrawal_credentials: bytes[32], amount: bytes[8], @@ -42,8 +42,9 @@ def to_little_endian_64(value: uint256) -> bytes[8]: @public @constant -def get_deposit_root() -> bytes32: - node: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 +def get_hash_tree_root() -> bytes32: + zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 + node: bytes32 = zero_bytes32 size: uint256 = self.deposit_count for height in range(DEPOSIT_CONTRACT_TREE_DEPTH): if bitwise_and(size, 1) == 1: # More gas efficient than `size % 2 == 1` @@ -51,7 +52,7 @@ def get_deposit_root() -> bytes32: else: node = sha256(concat(node, self.zero_hashes[height])) size /= 2 - return node + return sha256(concat(node, self.to_little_endian_64(self.deposit_count), slice(zero_bytes32, start=0, len=24))) @public @@ -75,11 +76,11 @@ def deposit(pubkey: bytes[PUBKEY_LENGTH], assert len(withdrawal_credentials) == WITHDRAWAL_CREDENTIALS_LENGTH assert len(signature) == SIGNATURE_LENGTH - # Emit `Deposit` log + # Emit `DepositEvent` log amount: bytes[8] = self.to_little_endian_64(deposit_amount) - log.Deposit(pubkey, withdrawal_credentials, amount, signature, self.to_little_endian_64(self.deposit_count)) + log.DepositEvent(pubkey, withdrawal_credentials, amount, signature, self.to_little_endian_64(self.deposit_count)) - # Compute `DepositData` root + # Compute `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,7 +92,7 @@ def deposit(pubkey: bytes[PUBKEY_LENGTH], sha256(concat(amount, slice(zero_bytes32, start=0, len=32 - AMOUNT_LENGTH), signature_root)), )) - # Add `DepositData` root to Merkle tree (update a single `branch` node) + # Add `DepositData` hash tree 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/tests/contracts/test_deposit.py b/deposit_contract/tests/contracts/test_deposit.py index 783af3356..1c96d074e 100644 --- a/deposit_contract/tests/contracts/test_deposit.py +++ b/deposit_contract/tests/contracts/test_deposit.py @@ -15,26 +15,12 @@ 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, ) -def compute_merkle_root(leaf_nodes): - assert len(leaf_nodes) >= 1 - empty_node = b'\x00' * 32 - child_nodes = leaf_nodes[:] - for _ in range(DEPOSIT_CONTRACT_TREE_DEPTH): - parent_nodes = [] - if len(child_nodes) % 2 == 1: - child_nodes.append(empty_node) - for j in range(0, len(child_nodes), 2): - parent_nodes.append(hash(child_nodes[j] + child_nodes[j + 1])) - child_nodes = parent_nodes - empty_node = hash(empty_node + empty_node) - return child_nodes[0] - - @pytest.fixture def deposit_input(): """ @@ -110,8 +96,8 @@ def test_deposit_inputs(registration_contract, ) -def test_deposit_log(registration_contract, a0, w3, deposit_input): - log_filter = registration_contract.events.Deposit.createFilter( +def test_deposit_event_log(registration_contract, a0, w3, deposit_input): + log_filter = registration_contract.events.DepositEvent.createFilter( fromBlock='latest', ) @@ -131,13 +117,14 @@ def test_deposit_log(registration_contract, a0, w3, deposit_input): assert log['signature'] == deposit_input[2] assert log['index'] == i.to_bytes(8, 'little') + def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input): - log_filter = registration_contract.events.Deposit.createFilter( + log_filter = registration_contract.events.DepositEvent.createFilter( fromBlock='latest', ) deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(10)] - leaf_nodes = [] + deposit_data_list = [] for i in range(0, 10): tx_hash = registration_contract.functions.deposit( *deposit_input, @@ -151,13 +138,12 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input assert log["index"] == i.to_bytes(8, 'little') - deposit_data = DepositData( + deposit_data_list.append(DepositData( pubkey=deposit_input[0], withdrawal_credentials=deposit_input[1], amount=deposit_amount_list[i], signature=deposit_input[2], - ) - hash_tree_root_result = hash_tree_root(deposit_data) - leaf_nodes.append(hash_tree_root_result) - root = compute_merkle_root(leaf_nodes) - assert root == registration_contract.functions.get_deposit_root().call() + )) + + root = hash_tree_root(List[DepositData, 2**32](*deposit_data_list)) + assert root == registration_contract.functions.get_hash_tree_root().call() diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f372c457a..3f834c19c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -95,7 +95,6 @@ - [`initiate_validator_exit`](#initiate_validator_exit) - [`slash_validator`](#slash_validator) - [Genesis](#genesis) - - [Genesis trigger](#genesis-trigger) - [Genesis state](#genesis-state) - [Genesis block](#genesis-block) - [Beacon chain state transition function](#beacon-chain-state-transition-function) @@ -126,7 +125,6 @@ This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain. At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of [validators](#dfn-validator). In the initial deployment phases of Ethereum 2.0, the only mechanism to become a [validator](#dfn-validator) is to make a one-way ETH transaction to a deposit contract on Ethereum 1.0. Activation as a [validator](#dfn-validator) happens when Ethereum 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior. - The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block and proof-of-stake votes for a beacon block. A sufficient number of attestations for the same shard block create a "crosslink", confirming the shard segment up to that shard block into the beacon chain. Crosslinks also serve as infrastructure for asynchronous cross-shard communication. ## Notation @@ -176,6 +174,7 @@ The following values are (non-configurable) constants used throughout the specif | `ZERO_HASH` | `Hash(b'\x00' * 32)` | | `BASE_REWARDS_PER_EPOCH` | `5` | | `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | +| `SECONDS_PER_DAY` | `86400` | ## Configuration @@ -191,6 +190,8 @@ The following values are (non-configurable) constants used throughout the specif | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `90` | +| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | +| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | | `JUSTIFICATION_BITS_LENGTH` | `4` | * For the safety of crosslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) @@ -446,7 +447,7 @@ class Attestation(Container): ```python class Deposit(Container): - proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # Merkle path to deposit root + proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit data list root data: DepositData ``` @@ -1109,61 +1110,43 @@ def slash_validator(state: BeaconState, ## Genesis -### Genesis trigger - -Before genesis has been triggered and whenever the deposit contract emits a `Deposit` log, call the function `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where: - -* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log -* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log - -When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: - -* `genesis_deposits = deposits` -* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` -* `genesis_eth1_data` be the object of type `Eth1Data` where: - * `genesis_eth1_data.block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` - * `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits` - * `genesis_eth1_data.deposit_count = len(genesis_deposits)` - -*Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder: - -```python -def is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool: - # Process deposits - state = BeaconState() - for deposit in deposits: - process_deposit(state, deposit) - - # Count active validators at genesis - active_validator_count = 0 - for validator in state.validators: - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - active_validator_count += 1 - - # Check effective balance to trigger genesis - GENESIS_ACTIVE_VALIDATOR_COUNT = 2**16 - return active_validator_count == GENESIS_ACTIVE_VALIDATOR_COUNT -``` - ### Genesis state -Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_data)`. +Before the Ethereum 2.0 genesis has been triggered, and for every Ethereum 1.0 block, call `initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` where: + +* `eth1_block_hash` is the hash of the Ethereum 1.0 block +* `eth1_timestamp` is the Unix timestamp corresponding to `eth1_block_hash` +* `deposits` is the sequence of all deposits, ordered chronologically, up to the block with hash `eth1_block_hash` + +The genesis state `genesis_state` is the return value of calling `initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` only if `is_valid_genesis_state(genesis_state) is True`. + +Implementations can choose to support different (more optimized) variations of the below initialization approach: + - Build the `genesis_state` from a stream of deposits by incrementally updating the `state.eth1_data.deposit_root`. + - Compute deposit proofs for the final `state.eth1_data.deposit_root`, and process as a pre-determined collection. + +*Note*: The two constants `MIN_GENESIS_TIME` and `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` have yet to be agreed upon by the community, and can be updated as necessary. ```python -def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth1_data: Eth1Data) -> BeaconState: +def initialize_beacon_state_from_eth1(eth1_block_hash: Hash, + eth1_timestamp: uint64, + deposits: Sequence[Deposit]) -> BeaconState: state = BeaconState( - genesis_time=genesis_time, - eth1_data=eth1_data, + genesis_time=eth1_timestamp - eth1_timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY, + eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=len(deposits)), latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) - # Process genesis deposits - for deposit in deposits: + # Process deposits + leaves = list(map(lambda deposit: deposit.data, deposits)) + for index, deposit in enumerate(deposits): + state.eth1_data.deposit_root = hash_tree_root( + List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) + ) process_deposit(state, deposit) - # Process genesis activations - for validator in state.validators: - if validator.effective_balance >= MAX_EFFECTIVE_BALANCE: + # Process activations + for index, validator in enumerate(state.validators): + if state.balances[index] >= MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH @@ -1174,6 +1157,16 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth return state ``` +```python +def is_valid_genesis_state(state: BeaconState) -> bool: + if state.genesis_time < MIN_GENESIS_TIME: + return False + elif len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: + return False + else: + return True +``` + ### Genesis block Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`. @@ -1455,7 +1448,7 @@ def process_registry_updates(state: BeaconState) -> None: for index, validator in enumerate(state.validators): if ( validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and - validator.effective_balance >= MAX_EFFECTIVE_BALANCE + validator.effective_balance == MAX_EFFECTIVE_BALANCE ): validator.activation_eligibility_epoch = get_current_epoch(state) @@ -1695,7 +1688,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, - depth=DEPOSIT_CONTRACT_TREE_DEPTH, + depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # add 1 for the SSZ length mix-in index=state.eth1_deposit_index, root=state.eth1_data.deposit_root, ) diff --git a/specs/core/0_deposit-contract.md b/specs/core/0_deposit-contract.md index d06dbaea1..0efc15f25 100644 --- a/specs/core/0_deposit-contract.md +++ b/specs/core/0_deposit-contract.md @@ -14,7 +14,7 @@ - [`deposit` function](#deposit-function) - [Deposit amount](#deposit-amount) - [Withdrawal credentials](#withdrawal-credentials) - - [`Deposit` log](#deposit-log) + - [`DepositEvent` log](#depositevent-log) - [Vyper code](#vyper-code) @@ -53,9 +53,9 @@ One of the `DepositData` fields is `withdrawal_credentials`. It is a commitment The private key corresponding to `withdrawal_pubkey` will be required to initiate a withdrawal. It can be stored separately until a withdrawal is required, e.g. in cold storage. -#### `Deposit` log +#### `DepositEvent` log -Every Ethereum 1.0 deposit emits a `Deposit` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract. +Every Ethereum 1.0 deposit emits a `DepositEvent` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract. ## Vyper code diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 7d5630c7b..1b103b218 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -221,7 +221,7 @@ epoch_signature = bls_sign( ##### 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_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`. +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`. Let `get_eth1_data(distance: int) -> 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: diff --git a/test_libs/pyspec/eth2spec/test/context.py b/test_libs/pyspec/eth2spec/test/context.py index 97266acf2..e7560afc6 100644 --- a/test_libs/pyspec/eth2spec/test/context.py +++ b/test_libs/pyspec/eth2spec/test/context.py @@ -27,9 +27,13 @@ def with_state(fn): DEFAULT_BLS_ACTIVE = False +def spectest_with_bls_switch(fn): + return bls_switch(spectest()(fn)) + + # shorthand for decorating @with_state @spectest() def spec_state_test(fn): - return with_state(bls_switch(spectest()(fn))) + return with_state(spectest_with_bls_switch(fn)) def expect_assertion_error(fn): diff --git a/test_libs/pyspec/eth2spec/test/genesis/__init__.py b/test_libs/pyspec/eth2spec/test/genesis/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_initialize_beacon_state_from_eth1.py b/test_libs/pyspec/eth2spec/test/genesis/test_initialize_beacon_state_from_eth1.py new file mode 100644 index 000000000..b95b70fef --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/genesis/test_initialize_beacon_state_from_eth1.py @@ -0,0 +1,30 @@ +from eth2spec.test.context import spectest_with_bls_switch, with_phases +from eth2spec.test.helpers.deposits import ( + prepare_genesis_deposits, +) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_initialize_beacon_state_from_eth1(spec): + deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + + yield 'eth1_block_hash', eth1_block_hash + yield 'eth1_timestamp', eth1_timestamp + yield 'deposits', deposits + + # initialize beacon_state + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + assert state.genesis_time == eth1_timestamp - eth1_timestamp % spec.SECONDS_PER_DAY + 2 * spec.SECONDS_PER_DAY + assert len(state.validators) == deposit_count + assert state.eth1_data.deposit_root == deposit_root + assert state.eth1_data.deposit_count == deposit_count + assert state.eth1_data.block_hash == eth1_block_hash + + # yield state + yield 'state', state diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py b/test_libs/pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py new file mode 100644 index 000000000..4ad509200 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py @@ -0,0 +1,86 @@ +from eth2spec.test.context import spectest_with_bls_switch, with_phases +from eth2spec.test.helpers.deposits import ( + prepare_genesis_deposits, +) + + +def create_valid_beacon_state(spec): + deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + return spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + +def run_is_valid_genesis_state(spec, state, valid=True): + """ + Run ``is_valid_genesis_state``, yielding: + - state ('state') + - is_valid ('is_valid') + If ``valid == False``, run expecting ``AssertionError`` + """ + yield state + is_valid = spec.is_valid_genesis_state(state) + yield 'is_valid', is_valid + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_true(spec): + state = create_valid_beacon_state(spec) + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_false_invalid_timestamp(spec): + state = create_valid_beacon_state(spec) + state.genesis_time = spec.MIN_GENESIS_TIME - 1 + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_true_more_balance(spec): + state = create_valid_beacon_state(spec) + state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE + 1 + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_false_not_enough_balance(spec): + state = create_valid_beacon_state(spec) + state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE - 1 + + yield from run_is_valid_genesis_state(spec, state, valid=False) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_true_one_more_validator(spec): + deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 1 + deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_false_not_enough_validator(spec): + deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 + deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + yield from run_is_valid_genesis_state(spec, state, valid=False) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 20ff7440f..b46363e62 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -1,66 +1,88 @@ from eth2spec.test.helpers.keys import pubkeys, privkeys from eth2spec.utils.bls import bls_sign -from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_root, get_merkle_proof -from eth2spec.utils.ssz.ssz_impl import signing_root +from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_proof +from eth2spec.utils.ssz.ssz_impl import signing_root, hash_tree_root +from eth2spec.utils.ssz.ssz_typing import List -def build_deposit_data(spec, state, pubkey, privkey, amount, withdrawal_credentials, signed=False): +def build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=None, signed=False): deposit_data = spec.DepositData( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, ) if signed: - sign_deposit_data(spec, state, deposit_data, privkey) + sign_deposit_data(spec, deposit_data, privkey, state) return deposit_data -def sign_deposit_data(spec, state, deposit_data, privkey): - signature = bls_sign( - message_hash=signing_root(deposit_data), - privkey=privkey, - domain=spec.get_domain( +def sign_deposit_data(spec, deposit_data, privkey, state=None): + if state is None: + # Genesis + domain = spec.bls_domain(spec.DOMAIN_DEPOSIT) + else: + domain = spec.get_domain( state, spec.DOMAIN_DEPOSIT, ) + + signature = bls_sign( + message_hash=signing_root(deposit_data), + privkey=privkey, + domain=domain, ) deposit_data.signature = signature def build_deposit(spec, state, - deposit_data_leaves, + deposit_data_list, pubkey, privkey, amount, withdrawal_credentials, signed): - deposit_data = build_deposit_data(spec, state, pubkey, privkey, amount, withdrawal_credentials, signed) + deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed) + index = len(deposit_data_list) + deposit_data_list.append(deposit_data) + root = hash_tree_root(List[spec.DepositData, 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH](*deposit_data_list)) + tree = calc_merkle_tree_from_leaves(tuple([d.hash_tree_root() for d in deposit_data_list])) + proof = list(get_merkle_proof(tree, item_index=index)) + [(index + 1).to_bytes(32, 'little')] + leaf = deposit_data.hash_tree_root() + assert spec.verify_merkle_branch(leaf, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH + 1, index, root) + deposit = spec.Deposit(proof=proof, data=deposit_data) - item = deposit_data.hash_tree_root() - index = len(deposit_data_leaves) - deposit_data_leaves.append(item) - tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) - root = get_merkle_root((tuple(deposit_data_leaves))) - proof = list(get_merkle_proof(tree, item_index=index)) - assert spec.verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, index, root) + return deposit, root, deposit_data_list - deposit = spec.Deposit( - proof=list(proof), - index=index, - data=deposit_data, - ) - return deposit, root, deposit_data_leaves +def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False): + deposit_data_list = [] + genesis_deposits = [] + for validator_index in range(genesis_validator_count): + pubkey = pubkeys[validator_index] + privkey = privkeys[validator_index] + # insecurely use pubkey as withdrawal key if no credentials provided + withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:] + deposit, root, deposit_data_list = build_deposit( + spec, + None, + deposit_data_list, + pubkey, + privkey, + amount, + withdrawal_credentials, + signed, + ) + genesis_deposits.append(deposit) + + return genesis_deposits, root def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_credentials=None, signed=False): """ Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount. """ - pre_validator_count = len(state.validators) - # fill previous deposits with zero-hash - deposit_data_leaves = [spec.ZERO_HASH] * pre_validator_count + deposit_data_list = [] pubkey = pubkeys[validator_index] privkey = privkeys[validator_index] @@ -69,10 +91,10 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c if withdrawal_credentials is None: withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:] - deposit, root, deposit_data_leaves = build_deposit( + deposit, root, deposit_data_list = build_deposit( spec, state, - deposit_data_leaves, + deposit_data_list, pubkey, privkey, amount, @@ -80,6 +102,7 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c signed, ) + state.eth1_deposit_index = 0 state.eth1_data.deposit_root = root - state.eth1_data.deposit_count = len(deposit_data_leaves) + state.eth1_data.deposit_count = len(deposit_data_list) return deposit diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py index 0f94bd26c..685eb6ebb 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py @@ -147,7 +147,7 @@ def test_invalid_withdrawal_credentials_top_up(spec, state): @with_all_phases @spec_state_test def test_wrong_deposit_for_deposit_count(spec, state): - deposit_data_leaves = [spec.ZERO_HASH] * len(state.validators) + deposit_data_leaves = [spec.DepositData() for _ in range(len(state.validators))] # build root for deposit_1 index_1 = len(deposit_data_leaves) @@ -197,6 +197,6 @@ def test_bad_merkle_proof(spec, state): # mess up merkle branch deposit.proof[5] = spec.ZERO_HASH - sign_deposit_data(spec, state, deposit.data, privkeys[validator_index]) + sign_deposit_data(spec, deposit.data, privkeys[validator_index], state=state) yield from run_deposit_processing(spec, state, deposit, validator_index, valid=False) diff --git a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py index 038b555cf..e9416ea05 100644 --- a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py +++ b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py @@ -1,4 +1,5 @@ from .hash_function import hash +from math import log2 ZERO_BYTES32 = b'\x00' * 32 @@ -8,11 +9,10 @@ for layer in range(1, 100): zerohashes.append(hash(zerohashes[layer - 1] + zerohashes[layer - 1])) -# Compute a Merkle root of a right-zerobyte-padded 2**32 sized tree -def calc_merkle_tree_from_leaves(values): +def calc_merkle_tree_from_leaves(values, layer_count=32): values = list(values) tree = [values[::]] - for h in range(32): + for h in range(layer_count): if len(values) % 2 == 1: values.append(zerohashes[h]) values = [hash(values[i] + values[i + 1]) for i in range(0, len(values), 2)] @@ -20,8 +20,11 @@ def calc_merkle_tree_from_leaves(values): return tree -def get_merkle_root(values): - return calc_merkle_tree_from_leaves(values)[-1][0] +def get_merkle_root(values, pad_to=1): + layer_count = int(log2(pad_to)) + if len(values) == 0: + return zerohashes[layer_count] + return calc_merkle_tree_from_leaves(values, layer_count)[-1][0] def get_merkle_proof(tree, item_index): @@ -32,19 +35,7 @@ def get_merkle_proof(tree, item_index): return proof -def next_power_of_two(v: int) -> int: - """ - Get the next power of 2. (for 64 bit range ints). - 0 is a special case, to have non-empty defaults. - Examples: - 0 -> 1, 1 -> 1, 2 -> 2, 3 -> 4, 32 -> 32, 33 -> 64 - """ - if v == 0: - return 1 - return 1 << (v - 1).bit_length() - - -def merkleize_chunks(chunks, pad_to: int = 1): +def merkleize_chunks(chunks, pad_to: int=1): count = len(chunks) depth = max(count - 1, 0).bit_length() max_depth = max(depth, (pad_to - 1).bit_length()) diff --git a/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py b/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py index 1c72a649b..f1ed768e6 100644 --- a/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py +++ b/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py @@ -1,5 +1,5 @@ import pytest -from .merkle_minimal import zerohashes, merkleize_chunks +from .merkle_minimal import zerohashes, merkleize_chunks, get_merkle_root from .hash_function import hash @@ -53,6 +53,7 @@ cases = [ 'depth,count,pow2,value', cases, ) -def test_merkleize_chunks(depth, count, pow2, value): +def test_merkleize_chunks_and_get_merkle_root(depth, count, pow2, value): chunks = [e(i) for i in range(count)] assert merkleize_chunks(chunks, pad_to=pow2) == value + assert get_merkle_root(chunks, pad_to=pow2) == value