mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
664 lines
32 KiB
Go
664 lines
32 KiB
Go
package vm
|
|
|
|
import (
|
|
"bytes"
|
|
"math/big"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/consensys/gnark-crypto/ecc/bn254"
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/bn254util"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/core/vm/precompiles"
|
|
"github.com/ethereum/go-ethereum/core/vm/precompiles/dasigners"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/vmihailenco/msgpack/v5"
|
|
)
|
|
|
|
const (
|
|
DASignersRequiredGasMax uint64 = 1000_000_000
|
|
|
|
DASignersFunctionParams = "params"
|
|
DASignersFunctionEpochNumber = "epochNumber"
|
|
DASignersFunctionQuorumCount = "quorumCount"
|
|
DASignersFunctionGetSigner = "getSigner"
|
|
DASignersFunctionGetQuorum = "getQuorum"
|
|
DASignersFunctionGetQuorumRow = "getQuorumRow"
|
|
DASignersFunctionRegisterSigner = "registerSigner"
|
|
DASignersFunctionUpdateSocket = "updateSocket"
|
|
DASignersFunctionRegisterNextEpoch = "registerNextEpoch"
|
|
DASignersFunctionGetAggPkG1 = "getAggPkG1"
|
|
DASignersFunctionIsSigner = "isSigner"
|
|
DASignersFunctionRegisteredEpoch = "registeredEpoch"
|
|
DASignersFunctionMakeEpoch = "makeEpoch"
|
|
)
|
|
|
|
var DASignersRequiredGasBasic = map[string]uint64{
|
|
DASignersFunctionParams: 1_000,
|
|
DASignersFunctionEpochNumber: 1_000,
|
|
DASignersFunctionQuorumCount: 1_000,
|
|
DASignersFunctionGetSigner: 100_000,
|
|
DASignersFunctionGetQuorum: 100_000,
|
|
DASignersFunctionGetQuorumRow: 10_000,
|
|
DASignersFunctionRegisterSigner: 100_000,
|
|
DASignersFunctionUpdateSocket: 50_000,
|
|
DASignersFunctionRegisterNextEpoch: 100_000,
|
|
DASignersFunctionGetAggPkG1: 1_000_000,
|
|
DASignersFunctionIsSigner: 10_000,
|
|
DASignersFunctionRegisteredEpoch: 10_000,
|
|
DASignersFunctionMakeEpoch: 100_000,
|
|
}
|
|
|
|
const (
|
|
DASignersNewSignerEvent = "NewSigner"
|
|
DASignersSocketUpdatedEvent = "SocketUpdated"
|
|
)
|
|
|
|
var _ StatefulPrecompiledContract = &DASignersPrecompile{}
|
|
|
|
type DASignersPrecompile struct {
|
|
abi abi.ABI
|
|
}
|
|
|
|
func NewDASignersPrecompile() *DASignersPrecompile {
|
|
abi, err := abi.JSON(strings.NewReader(dasigners.DASignersABI))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &DASignersPrecompile{
|
|
abi: abi,
|
|
}
|
|
}
|
|
|
|
// Address implements vm.PrecompiledContract.
|
|
func (d *DASignersPrecompile) Address() common.Address {
|
|
return common.HexToAddress("0x0000000000000000000000000000000000001000")
|
|
}
|
|
|
|
// RequiredGas implements vm.PrecompiledContract.
|
|
func (d *DASignersPrecompile) RequiredGas(input []byte) uint64 {
|
|
method, err := d.abi.MethodById(input[:4])
|
|
if err != nil {
|
|
return DASignersRequiredGasMax
|
|
}
|
|
if gas, ok := DASignersRequiredGasBasic[method.Name]; ok {
|
|
return gas
|
|
}
|
|
return DASignersRequiredGasMax
|
|
}
|
|
|
|
func (d *DASignersPrecompile) IsTx(method string) bool {
|
|
switch method {
|
|
case DASignersFunctionUpdateSocket,
|
|
DASignersFunctionRegisterSigner,
|
|
DASignersFunctionRegisterNextEpoch:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (d *DASignersPrecompile) Abi() *abi.ABI {
|
|
return &d.abi
|
|
}
|
|
|
|
// Run implements vm.PrecompiledContract.
|
|
func (d *DASignersPrecompile) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) {
|
|
method, args, err := InitializeStatefulPrecompileCall(d, evm, contract, readonly)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var bz []byte
|
|
switch method.Name {
|
|
// queries
|
|
case DASignersFunctionParams:
|
|
bz, err = d.Params(evm, method, args)
|
|
case DASignersFunctionEpochNumber:
|
|
bz, err = d.EpochNumber(evm, method, args)
|
|
case DASignersFunctionQuorumCount:
|
|
bz, err = d.QuorumCount(evm, method, args)
|
|
case DASignersFunctionGetSigner:
|
|
bz, err = d.GetSigner(evm, method, args)
|
|
case DASignersFunctionGetQuorum:
|
|
bz, err = d.GetQuorum(evm, method, args)
|
|
case DASignersFunctionGetQuorumRow:
|
|
bz, err = d.GetQuorumRow(evm, method, args)
|
|
case DASignersFunctionGetAggPkG1:
|
|
bz, err = d.GetAggPkG1(evm, method, args)
|
|
case DASignersFunctionIsSigner:
|
|
bz, err = d.IsSigner(evm, method, args)
|
|
case DASignersFunctionRegisteredEpoch:
|
|
bz, err = d.RegisteredEpoch(evm, method, args)
|
|
// txs
|
|
case DASignersFunctionRegisterSigner:
|
|
bz, err = d.RegisterSigner(evm, contract, method, args)
|
|
case DASignersFunctionRegisterNextEpoch:
|
|
bz, err = d.RegisterNextEpoch(evm, contract, method, args)
|
|
case DASignersFunctionUpdateSocket:
|
|
bz, err = d.UpdateSocket(evm, contract, method, args)
|
|
case DASignersFunctionMakeEpoch:
|
|
bz, err = d.MakeEpoch(evm, contract, method, args)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return bz, nil
|
|
}
|
|
|
|
func (d *DASignersPrecompile) EmitNewSignerEvent(evm *EVM, signer dasigners.IDASignersSignerDetail) error {
|
|
event := d.abi.Events[DASignersNewSignerEvent]
|
|
quries := make([]interface{}, 2)
|
|
quries[0] = event.ID
|
|
quries[1] = signer.Signer
|
|
topics, err := abi.MakeTopics(quries)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
arguments := abi.Arguments{event.Inputs[1], event.Inputs[2]}
|
|
b, err := arguments.Pack(signer.PkG1, signer.PkG2)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
evm.StateDB.AddLog(&types.Log{
|
|
Address: d.Address(),
|
|
Topics: topics[0],
|
|
Data: b,
|
|
BlockNumber: evm.Context.BlockNumber.Uint64(),
|
|
})
|
|
return d.EmitSocketUpdatedEvent(evm, signer.Signer, signer.Socket)
|
|
}
|
|
|
|
func (d *DASignersPrecompile) EmitSocketUpdatedEvent(evm *EVM, signer common.Address, socket string) error {
|
|
event := d.abi.Events[DASignersSocketUpdatedEvent]
|
|
quries := make([]interface{}, 2)
|
|
quries[0] = event.ID
|
|
quries[1] = signer
|
|
topics, err := abi.MakeTopics(quries)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
arguments := abi.Arguments{event.Inputs[1]}
|
|
b, err := arguments.Pack(socket)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
evm.StateDB.AddLog(&types.Log{
|
|
Address: d.Address(),
|
|
Topics: topics[0],
|
|
Data: b,
|
|
BlockNumber: evm.Context.BlockNumber.Uint64(),
|
|
})
|
|
return nil
|
|
}
|
|
|
|
type Ballot struct {
|
|
account common.Address
|
|
content []byte
|
|
}
|
|
|
|
func (d *DASignersPrecompile) MakeEpoch(
|
|
evm *EVM,
|
|
contract *Contract,
|
|
method *abi.Method,
|
|
args []interface{},
|
|
) ([]byte, error) {
|
|
if len(args) != 0 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
params := d.params()
|
|
epoch := d.epochNumber(evm)
|
|
epochBlock := d.epochBlock(evm, epoch)
|
|
blockHeight := evm.Context.BlockNumber.Uint64()
|
|
if epochBlock > 0 && blockHeight < epochBlock+params.EpochBlocks.Uint64() {
|
|
// not yet to the next epoch
|
|
return method.Outputs.Pack()
|
|
}
|
|
// new epoch
|
|
epoch += 1
|
|
cnt := d.epochRegistration(evm, epoch)
|
|
ballots := []Ballot{}
|
|
for index := range cnt {
|
|
account := d.epochRegisteredSigner(evm, epoch, index)
|
|
sigHash, _ := d.getRegistration(evm, epoch, account)
|
|
votes := d.getVotes(evm, epoch, account)
|
|
// MaxVotesPerSigner is hard limit
|
|
if params.MaxVotesPerSigner.Int64() < int64(votes) {
|
|
votes = int(params.MaxVotesPerSigner.Int64())
|
|
}
|
|
content := sigHash
|
|
for j := 0; j < votes; j += 1 {
|
|
ballots = append(ballots, Ballot{
|
|
account: account,
|
|
content: content,
|
|
})
|
|
content = crypto.Keccak256(content)
|
|
}
|
|
}
|
|
sort.Slice(ballots, func(i, j int) bool {
|
|
return bytes.Compare(ballots[i].content, ballots[j].content) < 0
|
|
})
|
|
|
|
quorums := make([][]common.Address, 0)
|
|
encodedSlices := params.EncodedSlices.Uint64()
|
|
maxQuorums := params.MaxQuorums.Uint64()
|
|
if len(ballots) >= int(encodedSlices) {
|
|
for i := 0; i+int(encodedSlices) <= len(ballots); i += int(encodedSlices) {
|
|
if int(maxQuorums) <= len(quorums) {
|
|
break
|
|
}
|
|
quorum := make([]common.Address, encodedSlices)
|
|
for j := 0; j < int(encodedSlices); j += 1 {
|
|
quorum[j] = ballots[i+j].account
|
|
}
|
|
quorums = append(quorums, quorum)
|
|
}
|
|
if len(ballots)%int(encodedSlices) != 0 && int(maxQuorums) > len(quorums) {
|
|
quorum := make([]common.Address, 0)
|
|
for j := len(ballots) - int(encodedSlices); j < len(ballots); j += 1 {
|
|
quorum = append(quorum, ballots[j].account)
|
|
}
|
|
quorums = append(quorums, quorum)
|
|
}
|
|
} else if len(ballots) > 0 {
|
|
quorum := make([]common.Address, encodedSlices)
|
|
n := len(ballots)
|
|
for i := 0; i < int(encodedSlices); i += 1 {
|
|
quorum[i] = ballots[i%n].account
|
|
}
|
|
quorums = append(quorums, quorum)
|
|
}
|
|
|
|
// save quorums
|
|
for index, quorum := range quorums {
|
|
b, err := msgpack.Marshal(quorum)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
StoreBytes(evm.StateDB, d.Address(), dasigners.QuorumKey(epoch, uint64(index)), b)
|
|
}
|
|
evm.StateDB.SetState(d.Address(), dasigners.QuorumCountKey(epoch), common.BigToHash(big.NewInt(int64(len(quorums)))))
|
|
// save epoch number & block height
|
|
evm.StateDB.SetState(d.Address(), dasigners.EpochNumberKey(), common.BigToHash(big.NewInt(int64(epoch))))
|
|
evm.StateDB.SetState(d.Address(), dasigners.EpochBlockKey(epoch), common.BigToHash(big.NewInt(int64(blockHeight))))
|
|
return method.Outputs.Pack()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) setSigner(evm *EVM, signer dasigners.IDASignersSignerDetail) error {
|
|
b, err := msgpack.Marshal(signer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
StoreBytes(evm.StateDB, d.Address(), dasigners.SignerKey(signer.Signer), b)
|
|
return nil
|
|
}
|
|
|
|
func (d *DASignersPrecompile) getRegistry() common.Address {
|
|
// This is a upgradeable contract deployed in Beacon-Proxy pattern in three raw transaction:
|
|
// raw tx params:
|
|
// from: 0xeb995d37799ad4a2db524e5ff0825ae2d4711757
|
|
// nonce: 0..2
|
|
// gasPrice: 100 Gwei
|
|
// gasLimit: 1000000
|
|
// The sender is an ephemeral account, nobody holds its private key and this is the only transaction it signed.
|
|
// This transaction is a legacy transaction without chain ID so it can be deployed at any EVM chain which supports pre-EIP155 transactions.
|
|
// raw tx #0(implementation): 0xf90b708085174876e800830f42408080b90b1d608060405234801561001057600080fd5b50610afd806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063807f063a1161005b578063807f063a146100b25780638129fc1c146100d75780638da5cb5b146100df578063f2fde38b1461010f57600080fd5b806356a3237214610082578063715018a6146100975780637ca4dd5e1461009f575b600080fd5b6100956100903660046106e6565b610122565b005b610095610242565b6100956100ad3660046107b5565b610256565b6100bb61100081565b6040516001600160a01b03909116815260200160405180910390f35b610095610395565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166100bb565b61009561011d3660046108bd565b6104b7565b33321461014257604051630f15d65160e01b815260040160405180910390fd5b6000806110006001600160a01b0316630f62bda560e01b3385600160405160240161016f939291906108d8565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516101ad9190610934565b6000604051808303816000865af19150503d80600081146101ea576040519150601f19603f3d011682016040523d82523d6000602084013e6101ef565b606091505b509150915081816040516020016102069190610950565b6040516020818303038152906040529061023c5760405162461bcd60e51b815260040161023391906109c1565b60405180910390fd5b50505050565b61024a6104f5565b6102546000610550565b565b33321461027657604051630f15d65160e01b815260040160405180910390fd5b81516001600160a01b031633146102a057604051631024390d60e21b815260040160405180910390fd5b6000806110006001600160a01b0316637ca4dd5e60e01b85856040516024016102ca9291906109f7565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516103089190610934565b6000604051808303816000865af19150503d8060008114610345576040519150601f19603f3d011682016040523d82523d6000602084013e61034a565b606091505b509150915081816040516020016103619190610a82565b6040516020818303038152906040529061038e5760405162461bcd60e51b815260040161023391906109c1565b5050505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156103db5750825b905060008267ffffffffffffffff1660011480156103f85750303b155b905081158015610406575080155b156104245760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561044e57845460ff60401b1916600160401b1785555b61046b732d7f2d2286994477ba878f321b17a7e40e52cda46105c1565b831561038e57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15050505050565b6104bf6104f5565b6001600160a01b0381166104e957604051631e4fbdf760e01b815260006004820152602401610233565b6104f281610550565b50565b336105277f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146102545760405163118cdaa760e01b8152336004820152602401610233565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6105c96105d2565b6104f28161061b565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661025457604051631afcd79f60e31b815260040160405180910390fd5b6104bf6105d2565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561065c5761065c610623565b60405290565b6040516080810167ffffffffffffffff8111828210171561065c5761065c610623565b604051601f8201601f1916810167ffffffffffffffff811182821017156106ae576106ae610623565b604052919050565b6000604082840312156106c857600080fd5b6106d0610639565b9050813581526020820135602082015292915050565b6000604082840312156106f857600080fd5b61070283836106b6565b9392505050565b80356001600160a01b038116811461072057600080fd5b919050565b600082601f83011261073657600080fd5b61073e610639565b80604084018581111561075057600080fd5b845b8181101561076a578035845260209384019301610752565b509095945050505050565b60006080828403121561078757600080fd5b61078f610639565b905061079b8383610725565b81526107aa8360408401610725565b602082015292915050565b600080606083850312156107c857600080fd5b823567ffffffffffffffff808211156107e057600080fd5b9084019061010082870312156107f557600080fd5b6107fd610662565b61080683610709565b81526020808401358381111561081b57600080fd5b8401601f8101891361082c57600080fd5b80358481111561083e5761083e610623565b610850601f8201601f19168401610685565b9450808552898382840101111561086657600080fd5b808383018487013760008382870101525050828183015261088a88604086016106b6565b604083015261089c8860808601610775565b60608301528195506108b0888289016106b6565b9450505050509250929050565b6000602082840312156108cf57600080fd5b61070282610709565b6001600160a01b0384168152608081016108ff602083018580518252602090810151910152565b60ff83166060830152949350505050565b60005b8381101561092b578181015183820152602001610913565b50506000910152565b60008251610946818460208701610910565b9190910192915050565b7f72656769737465724e65787445706f63682063616c6c206661696c65643a200081526000825161098881601f850160208701610910565b91909101601f0192915050565b600081518084526109ad816020860160208601610910565b601f01601f19169290920160200192915050565b6020815260006107026020830184610995565b8060005b600281101561023c5781518452602093840193909101906001016109d8565b606080825283516001600160a01b03169082015260208301516101006080830152600090610a29610160840182610995565b6040860151805160a0860152602081015160c0860152909150506060850151610a5660e0850182516109d4565b60200151610a686101208501826109d4565b509050610702602083018480518252602090810151910152565b7f72656769737465725369676e65722063616c6c206661696c65643a2000000000815260008251610aba81601c850160208701610910565b91909101601c019291505056fea2646970667358221220bb50c03fb5e1cc5e8bb317ff0bf7889ef0b368a37ea3568a9d02d8379ebc351164736f6c634300081400331ba04ce6e58373b6023b7ffc717cc0db01847ed8da661c7c3c98693957d3248af35fa0727edc90561444dcb4e91a329e8ef7916cb018dfef5f18e86e2bd90391e7a204
|
|
// raw tx #1(beacon): 0xf904cb0185174876e800830f42408080b90478608060405234801561001057600080fd5b5060405161043838038061043883398101604081905261002f91610165565b806001600160a01b03811661005f57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b61006881610079565b50610072826100c9565b5050610198565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b806001600160a01b03163b6000036100ff5760405163211eb15960e21b81526001600160a01b0382166004820152602401610056565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b80516001600160a01b038116811461016057600080fd5b919050565b6000806040838503121561017857600080fd5b61018183610149565b915061018f60208401610149565b90509250929050565b610291806101a76000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80633659cfe61461005c5780635c60da1b14610071578063715018a61461009a5780638da5cb5b146100a2578063f2fde38b146100b3575b600080fd5b61006f61006a36600461022b565b6100c6565b005b6001546001600160a01b03165b6040516001600160a01b03909116815260200160405180910390f35b61006f6100da565b6000546001600160a01b031661007e565b61006f6100c136600461022b565b6100ee565b6100ce61012e565b6100d78161015b565b50565b6100e261012e565b6100ec60006101db565b565b6100f661012e565b6001600160a01b03811661012557604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6100d7816101db565b6000546001600160a01b031633146100ec5760405163118cdaa760e01b815233600482015260240161011c565b806001600160a01b03163b6000036101915760405163211eb15960e21b81526001600160a01b038216600482015260240161011c565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561023d57600080fd5b81356001600160a01b038116811461025457600080fd5b939250505056fea26469706673582212205220e5b3095ab739313888ed7a605b359ca52e79f2a5a6297e03c439e8e8b30764736f6c634300081400330000000000000000000000007ad29425f6d68ed6bd8eb8a77d73bb2ad81b8afa0000000000000000000000002d7f2d2286994477ba878f321b17a7e40e52cda41ca0a1e38aac4e65cf5d87e9c2f857d3f0b3cc9f24d42639689f01c9876a45665ebda0330c349d845c3403c9be2b8e31ed0c17e5b3824d02c9e11e71564df71d6621ee
|
|
// raw tx #2(proxy): 0xf906720285174876e800830f42408080b9061f60a06040526040516105bf3803806105bf83398101604081905261002291610387565b61002c828261003e565b506001600160a01b031660805261047e565b610047826100fe565b6040516001600160a01b038316907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a28051156100f2576100ed826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e79190610447565b82610211565b505050565b6100fa610288565b5050565b806001600160a01b03163b60000361013957604051631933b43b60e21b81526001600160a01b03821660048201526024015b60405180910390fd5b807fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392831617905560408051635c60da1b60e01b81529051600092841691635c60da1b9160048083019260209291908290030181865afa1580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d99190610447565b9050806001600160a01b03163b6000036100fa57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610130565b6060600080846001600160a01b03168460405161022e9190610462565b600060405180830381855af49150503d8060008114610269576040519150601f19603f3d011682016040523d82523d6000602084013e61026e565b606091505b50909250905061027f8583836102a9565b95945050505050565b34156102a75760405163b398979f60e01b815260040160405180910390fd5b565b6060826102be576102b982610308565b610301565b81511580156102d557506001600160a01b0384163b155b156102fe57604051639996b31560e01b81526001600160a01b0385166004820152602401610130565b50805b9392505050565b8051156103185780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80516001600160a01b038116811461034857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561037e578181015183820152602001610366565b50506000910152565b6000806040838503121561039a57600080fd5b6103a383610331565b60208401519092506001600160401b03808211156103c057600080fd5b818501915085601f8301126103d457600080fd5b8151818111156103e6576103e661034d565b604051601f8201601f19908116603f0116810190838211818310171561040e5761040e61034d565b8160405282815288602084870101111561042757600080fd5b610438836020830160208801610363565b80955050505050509250929050565b60006020828403121561045957600080fd5b61030182610331565b60008251610474818460208701610363565b9190910192915050565b6080516101276104986000396000601e01526101276000f3fe6080604052600a600c565b005b60186014601a565b60a0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156079573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190609b919060c3565b905090565b3660008037600080366000845af43d6000803e80801560be573d6000f35b3d6000fd5b60006020828403121560d457600080fd5b81516001600160a01b038116811460ea57600080fd5b939250505056fea264697066735822122039e43d51fa1bcd8fe79599db2a7e6dd3e5358b756c53210827bbf02fda62be6c64736f6c63430008140033000000000000000000000000762662fb644cdd051f35e0dd8fb6ac15a4bf65ad000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000001ca04189ff3e2929af3203bb5041d582084f676c866a1faae88b0a1fad3f616b90ada0309a30d2c3fabc8e659b9a747c75f62556f1db3b269b1377fa936b7c236685cb
|
|
// The owners of the contract and the beacon will be set to 0x2D7F2d2286994477Ba878f321b17A7e40E52cDa4,
|
|
// and after the network has launched and reached a stable state, ownership will be transferred to a timelock contract controlled by a multisig
|
|
return common.HexToAddress("0x20f30b2584f3096ea0d6c18c3b5cacc0585e12fc")
|
|
}
|
|
|
|
func (d *DASignersPrecompile) RegisterSigner(
|
|
evm *EVM,
|
|
contract *Contract,
|
|
method *abi.Method,
|
|
args []interface{},
|
|
) ([]byte, error) {
|
|
if len(args) != 2 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
signer := args[0].(dasigners.IDASignersSignerDetail)
|
|
signature := dasigners.SerializeG1(args[1].(dasigners.BN254G1Point))
|
|
// validation
|
|
if contract.caller != d.getRegistry() {
|
|
return nil, precompiles.ErrSenderNotRegistry
|
|
}
|
|
// execute
|
|
// validate sender
|
|
// staked value is checked in registry contract
|
|
_, found, err := d.getSigner(evm, signer.Signer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if found {
|
|
return nil, dasigners.ErrSignerExists
|
|
}
|
|
// validate signature
|
|
chainID := evm.chainConfig.ChainID
|
|
hash := dasigners.PubkeyRegistrationHash(signer.Signer, chainID)
|
|
if !dasigners.ValidateSignature(signer, hash, bn254util.DeserializeG1(signature)) {
|
|
return nil, dasigners.ErrInvalidSignature
|
|
}
|
|
// save signer
|
|
if err := d.setSigner(evm, signer); err != nil {
|
|
return nil, err
|
|
}
|
|
// emit events
|
|
err = d.EmitNewSignerEvent(evm, signer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return method.Outputs.Pack()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) epochRegistration(evm *EVM, epoch uint64) uint64 {
|
|
return evm.StateDB.GetState(d.Address(), dasigners.EpochRegistrationKey(epoch)).Big().Uint64()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) epochRegisteredSigner(evm *EVM, epoch uint64, index uint64) common.Address {
|
|
h := evm.StateDB.GetState(d.Address(), dasigners.EpochRegisteredSignerKey(epoch, index))
|
|
return common.Address(h[12:])
|
|
}
|
|
|
|
func (d *DASignersPrecompile) storeRegistration(evm *EVM, epoch uint64, signer common.Address, signature []byte, votes *big.Int) error {
|
|
if _, found := d.getRegistration(evm, epoch, signer); found {
|
|
return nil
|
|
}
|
|
// save signature hash
|
|
evm.StateDB.SetState(d.Address(), dasigners.RegistrationKey(epoch, signer), crypto.Keccak256Hash(signature))
|
|
// save votes
|
|
evm.StateDB.SetState(d.Address(), dasigners.VotesKey(epoch, signer), common.BigToHash(votes))
|
|
// increment epoch registration count
|
|
registration := d.epochRegistration(evm, epoch)
|
|
evm.StateDB.SetState(d.Address(), dasigners.EpochRegistrationKey(epoch), common.BigToHash(big.NewInt(int64(registration+1))))
|
|
// save registered signer address
|
|
evm.StateDB.SetState(d.Address(), dasigners.EpochRegisteredSignerKey(epoch, registration), common.BytesToHash(signer.Bytes()))
|
|
return nil
|
|
}
|
|
|
|
func (d *DASignersPrecompile) RegisterNextEpoch(
|
|
evm *EVM,
|
|
contract *Contract,
|
|
method *abi.Method,
|
|
args []interface{},
|
|
) ([]byte, error) {
|
|
if len(args) != 3 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
account := args[0].(common.Address)
|
|
signature := dasigners.SerializeG1(args[1].(dasigners.BN254G1Point))
|
|
votes := args[2].(*big.Int)
|
|
// validation
|
|
if contract.caller != d.getRegistry() {
|
|
return nil, precompiles.ErrSenderNotRegistry
|
|
}
|
|
// execute
|
|
// get signer
|
|
// staked value is checked in registry contract
|
|
signer, found, err := d.getSigner(evm, account)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !found {
|
|
return nil, dasigners.ErrSignerNotFound
|
|
}
|
|
// validate signature
|
|
epochNumber := d.epochNumber(evm)
|
|
chainID := evm.chainConfig.ChainID
|
|
hash := dasigners.EpochRegistrationHash(account, epochNumber+1, chainID)
|
|
if !dasigners.ValidateSignature(signer, hash, bn254util.DeserializeG1(signature)) {
|
|
return nil, dasigners.ErrInvalidSignature
|
|
}
|
|
// save registration
|
|
if err := d.storeRegistration(evm, epochNumber+1, account, signature, votes); err != nil {
|
|
return nil, err
|
|
}
|
|
return method.Outputs.Pack()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) UpdateSocket(
|
|
evm *EVM,
|
|
contract *Contract,
|
|
method *abi.Method,
|
|
args []interface{},
|
|
) ([]byte, error) {
|
|
if len(args) != 1 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
socket := args[0].(string)
|
|
// validation
|
|
if contract.caller != evm.Origin {
|
|
return nil, precompiles.ErrSenderNotOrigin
|
|
}
|
|
// execute
|
|
signer, found, err := d.getSigner(evm, contract.caller)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !found {
|
|
return nil, dasigners.ErrSignerNotFound
|
|
}
|
|
signer.Socket = socket
|
|
if err := d.setSigner(evm, signer); err != nil {
|
|
return nil, err
|
|
}
|
|
// emit events
|
|
err = d.EmitSocketUpdatedEvent(evm, contract.caller, socket)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return method.Outputs.Pack()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) params() dasigners.IDASignersParams {
|
|
return dasigners.IDASignersParams{
|
|
TokensPerVote: big.NewInt(10), // deprecated
|
|
MaxVotesPerSigner: big.NewInt(1024),
|
|
MaxQuorums: big.NewInt(10),
|
|
EpochBlocks: big.NewInt(5760),
|
|
EncodedSlices: big.NewInt(3072),
|
|
}
|
|
}
|
|
|
|
func (d *DASignersPrecompile) Params(evm *EVM, method *abi.Method, _ []interface{}) ([]byte, error) {
|
|
return method.Outputs.Pack(d.params())
|
|
}
|
|
|
|
func (d *DASignersPrecompile) epochBlock(evm *EVM, epoch uint64) uint64 {
|
|
return evm.StateDB.GetState(d.Address(), dasigners.EpochBlockKey(epoch)).Big().Uint64()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) epochNumber(evm *EVM) uint64 {
|
|
return evm.StateDB.GetState(d.Address(), dasigners.EpochNumberKey()).Big().Uint64()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) EpochNumber(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 0 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
return method.Outputs.Pack(big.NewInt(int64(d.epochNumber(evm))))
|
|
}
|
|
|
|
func (d *DASignersPrecompile) quorumCount(evm *EVM, epochNumber uint64) uint64 {
|
|
return evm.StateDB.GetState(d.Address(), dasigners.QuorumCountKey(epochNumber)).Big().Uint64()
|
|
}
|
|
|
|
func (d *DASignersPrecompile) QuorumCount(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 1 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
epochNumber := args[0].(*big.Int).Uint64()
|
|
return method.Outputs.Pack(big.NewInt(int64(d.quorumCount(evm, epochNumber))))
|
|
}
|
|
|
|
func (d *DASignersPrecompile) getSigner(evm *EVM, account common.Address) (dasigners.IDASignersSignerDetail, bool, error) {
|
|
b := LoadBytes(evm.StateDB, d.Address(), dasigners.SignerKey(account))
|
|
if len(b) == 0 {
|
|
return dasigners.IDASignersSignerDetail{}, false, nil
|
|
}
|
|
|
|
var signer dasigners.IDASignersSignerDetail
|
|
err := msgpack.Unmarshal(b, &signer)
|
|
if err != nil {
|
|
return dasigners.IDASignersSignerDetail{}, false, err
|
|
}
|
|
return signer, true, nil
|
|
}
|
|
|
|
func (d *DASignersPrecompile) GetSigner(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 1 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
accounts := args[0].([]common.Address)
|
|
signers := make([]dasigners.IDASignersSignerDetail, len(accounts))
|
|
for i, account := range accounts {
|
|
signer, found, err := d.getSigner(evm, account)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !found {
|
|
return nil, dasigners.ErrSignerNotFound
|
|
}
|
|
signers[i] = signer
|
|
}
|
|
return method.Outputs.Pack(signers)
|
|
}
|
|
|
|
func (d *DASignersPrecompile) IsSigner(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 1 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
account := args[0].(common.Address)
|
|
_, found, err := d.getSigner(evm, account)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return method.Outputs.Pack(found)
|
|
}
|
|
|
|
func (d *DASignersPrecompile) getRegistration(evm *EVM, epoch uint64, account common.Address) ([]byte, bool) {
|
|
h := evm.StateDB.GetState(d.Address(), dasigners.RegistrationKey(epoch, account))
|
|
if h == (common.Hash{}) {
|
|
return nil, false
|
|
}
|
|
return h.Bytes(), true
|
|
}
|
|
|
|
func (d *DASignersPrecompile) getVotes(evm *EVM, epoch uint64, account common.Address) int {
|
|
return int(evm.StateDB.GetState(d.Address(), dasigners.VotesKey(epoch, account)).Big().Int64())
|
|
}
|
|
|
|
func (d *DASignersPrecompile) RegisteredEpoch(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 2 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
account := args[0].(common.Address)
|
|
epoch := args[1].(*big.Int).Uint64()
|
|
_, found := d.getRegistration(evm, epoch, account)
|
|
return method.Outputs.Pack(found)
|
|
}
|
|
|
|
func (d *DASignersPrecompile) getQuorum(evm *EVM, epochNumber uint64, quorumId uint64) ([]common.Address, error) {
|
|
if d.quorumCount(evm, epochNumber) <= quorumId {
|
|
return nil, dasigners.ErrQuorumIdOutOfBound
|
|
}
|
|
if d.epochNumber(evm) < epochNumber {
|
|
return nil, dasigners.ErrEpochOutOfBound
|
|
}
|
|
b := LoadBytes(evm.StateDB, d.Address(), dasigners.QuorumKey(epochNumber, quorumId))
|
|
var quorum []common.Address
|
|
err := msgpack.Unmarshal(b, &quorum)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return quorum, nil
|
|
}
|
|
|
|
func (d *DASignersPrecompile) GetQuorum(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 2 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
epochNumber := args[0].(*big.Int).Uint64()
|
|
quorumId := args[1].(*big.Int).Uint64()
|
|
quorum, err := d.getQuorum(evm, epochNumber, quorumId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return method.Outputs.Pack(quorum)
|
|
}
|
|
|
|
func (d *DASignersPrecompile) GetQuorumRow(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 3 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
epochNumber := args[0].(*big.Int).Uint64()
|
|
quorumId := args[1].(*big.Int).Uint64()
|
|
rowIndex := args[2].(uint32)
|
|
quorum, err := d.getQuorum(evm, epochNumber, quorumId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if int(rowIndex) >= len(quorum) {
|
|
return nil, dasigners.ErrRowIdOfBound
|
|
}
|
|
return method.Outputs.Pack(quorum[rowIndex])
|
|
}
|
|
|
|
func (d *DASignersPrecompile) getAggPkG1(
|
|
evm *EVM,
|
|
epochNumber uint64,
|
|
quorumId uint64,
|
|
quorumBitmap []byte,
|
|
) (dasigners.BN254G1Point, *big.Int, *big.Int, error) {
|
|
quorum, err := d.getQuorum(evm, epochNumber, quorumId)
|
|
if err != nil {
|
|
return dasigners.BN254G1Point{}, nil, nil, err
|
|
}
|
|
if (len(quorum)+7)/8 != len(quorumBitmap) {
|
|
return dasigners.BN254G1Point{}, nil, nil, dasigners.ErrQuorumBitmapLengthMismatch
|
|
}
|
|
aggPubkeyG1 := new(bn254.G1Affine)
|
|
hit := 0
|
|
added := make(map[common.Address]struct{})
|
|
for i, signer := range quorum {
|
|
if _, ok := added[signer]; ok {
|
|
hit += 1
|
|
continue
|
|
}
|
|
b := quorumBitmap[i/8] & (1 << (i % 8))
|
|
if b == 0 {
|
|
continue
|
|
}
|
|
hit += 1
|
|
added[signer] = struct{}{}
|
|
signer, found, err := d.getSigner(evm, signer)
|
|
if err != nil {
|
|
return dasigners.BN254G1Point{}, nil, nil, err
|
|
}
|
|
if !found {
|
|
return dasigners.BN254G1Point{}, nil, nil, dasigners.ErrSignerNotFound
|
|
}
|
|
aggPubkeyG1.Add(aggPubkeyG1, bn254util.DeserializeG1(dasigners.SerializeG1(signer.PkG1)))
|
|
}
|
|
return dasigners.NewBN254G1Point(bn254util.SerializeG1(aggPubkeyG1)), big.NewInt(int64(len(quorum))), big.NewInt(int64(hit)), nil
|
|
}
|
|
|
|
func (d *DASignersPrecompile) GetAggPkG1(evm *EVM, method *abi.Method, args []interface{}) ([]byte, error) {
|
|
if len(args) != 3 {
|
|
return nil, ErrExecutionReverted
|
|
}
|
|
epochNumber := args[0].(*big.Int).Uint64()
|
|
quorumId := args[1].(*big.Int).Uint64()
|
|
quorumBitmap := args[2].([]byte)
|
|
aggPkG1, total, hit, err := d.getAggPkG1(evm, epochNumber, quorumId, quorumBitmap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return method.Outputs.Pack(aggPkG1, total, hit)
|
|
}
|