diff options
-rw-r--r-- | build/testtool/testtool.go | 76 | ||||
-rw-r--r-- | consensus/dexcon/dexcon.go | 6 | ||||
-rw-r--r-- | consensus/dexcon/dexcon_test.go | 10 | ||||
-rw-r--r-- | consensus/dexcon/fake_dexcon.go | 8 | ||||
-rw-r--r-- | core/dexon_chain_makers.go | 1 | ||||
-rw-r--r-- | core/evm.go | 1 | ||||
-rw-r--r-- | core/genesis.go | 25 | ||||
-rw-r--r-- | core/governance.go | 68 | ||||
-rw-r--r-- | core/headerchain.go | 2 | ||||
-rw-r--r-- | core/tx_pool.go | 4 | ||||
-rw-r--r-- | core/vm/evm.go | 1 | ||||
-rw-r--r-- | core/vm/oracle_contract_abi.go | 171 | ||||
-rw-r--r-- | core/vm/oracle_contracts.go | 603 | ||||
-rw-r--r-- | core/vm/oracle_contracts_test.go | 171 | ||||
-rw-r--r-- | dex/downloader/downloader.go | 11 | ||||
-rw-r--r-- | dex/downloader/testchain_test.go | 76 | ||||
-rw-r--r-- | dex/governance.go | 33 | ||||
-rw-r--r-- | dex/handler.go | 27 | ||||
-rw-r--r-- | dex/helper_test.go | 6 | ||||
-rw-r--r-- | dex/protocol.go | 4 | ||||
-rw-r--r-- | params/config.go | 6 |
21 files changed, 679 insertions, 631 deletions
diff --git a/build/testtool/testtool.go b/build/testtool/testtool.go index 801c343b6..09e94fe16 100644 --- a/build/testtool/testtool.go +++ b/build/testtool/testtool.go @@ -11,6 +11,8 @@ import ( "strings" "time" + dexCore "github.com/dexon-foundation/dexon-consensus/core" + "github.com/dexon-foundation/dexon" "github.com/dexon-foundation/dexon/accounts/abi" "github.com/dexon-foundation/dexon/cmd/zoo/monkey" @@ -37,14 +39,42 @@ func main() { } } -func doVerifyGovCRS(args []string) { - if len(args) < 2 { - log.Fatal("arg length is not enough") +func getBlockNumber(client *ethclient.Client, round int) *big.Int { + if round == 0 { + return big.NewInt(0) + } + abiObject, err := abi.JSON(strings.NewReader(vm.GovernanceABIJSON)) + if err != nil { + log.Fatalf("read abi fail: %v", err) } - client, err := ethclient.Dial(args[0]) + input, err := abiObject.Pack("roundHeight", big.NewInt(int64(round))) if err != nil { - log.Fatalf("new ethclient fail: %v", err) + log.Fatalf("pack input fail: %v", err) + } + + result, err := client.CallContract(context.Background(), ethereum.CallMsg{ + To: &vm.GovernanceContractAddress, + Data: input, + }, nil) + if err != nil { + log.Fatalf("call contract fail: %v", err) + } + + if bytes.Equal(make([]byte, 32), result) { + log.Fatalf("round %d height not found", round) + } + + roundHeight := new(big.Int) + if err := abiObject.Unpack(&roundHeight, "roundHeight", result); err != nil { + log.Fatalf("unpack output fail: %v", err) + } + return roundHeight +} + +func doVerifyGovCRS(args []string) { + if len(args) < 2 { + log.Fatal("arg length is not enough") } abiObject, err := abi.JSON(strings.NewReader(vm.GovernanceABIJSON)) @@ -57,7 +87,14 @@ func doVerifyGovCRS(args []string) { log.Fatalf("pasre round from arg 2 fail: %v", err) } - input, err := abiObject.Pack("crs", big.NewInt(int64(round))) + client, err := ethclient.Dial(args[0]) + if err != nil { + log.Fatalf("new ethclient fail: %v", err) + } + + blockNumber := getBlockNumber(client, round) + + input, err := abiObject.Pack("crs") if err != nil { log.Fatalf("pack input fail: %v", err) } @@ -65,7 +102,7 @@ func doVerifyGovCRS(args []string) { result, err := client.CallContract(context.Background(), ethereum.CallMsg{ To: &vm.GovernanceContractAddress, Data: input, - }, nil) + }, blockNumber) if err != nil { log.Fatalf("call contract fail: %v", err) } @@ -81,12 +118,6 @@ func doVerifyGovMPK(args []string) { if len(args) < 3 { log.Fatal("arg length is not enough") } - - client, err := ethclient.Dial(args[0]) - if err != nil { - log.Fatalf("new ethclient fail: %v", err) - } - abiObject, err := abi.JSON(strings.NewReader(vm.GovernanceABIJSON)) if err != nil { log.Fatalf("read abi fail: %v", err) @@ -97,12 +128,23 @@ func doVerifyGovMPK(args []string) { log.Fatalf("pasre round from arg 2 fail: %v", err) } + if uint64(round) < dexCore.DKGDelayRound { + return + } + + client, err := ethclient.Dial(args[0]) + if err != nil { + log.Fatalf("new ethclient fail: %v", err) + } + + blockNumber := getBlockNumber(client, round) + index, err := strconv.Atoi(args[2]) if err != nil { - log.Fatalf("pasre round from arg 2 fail: %v", err) + log.Fatalf("pasre index from arg 2 fail: %v", err) } - input, err := abiObject.Pack("dkgMasterPublicKeys", big.NewInt(int64(round)), big.NewInt(int64(index))) + input, err := abiObject.Pack("dkgMasterPublicKeys", big.NewInt(int64(index))) if err != nil { log.Fatalf("pack input fail: %v", err) } @@ -110,13 +152,13 @@ func doVerifyGovMPK(args []string) { result, err := client.CallContract(context.Background(), ethereum.CallMsg{ To: &vm.GovernanceContractAddress, Data: input, - }, nil) + }, blockNumber) if err != nil { log.Fatalf("call contract fail: %v", err) } if bytes.Equal(make([]byte, 0), result) { - log.Fatalf("round %s index %s crs not found", args[1], args[2]) + log.Fatalf("round %s index %s mpk not found", args[1], args[2]) } log.Printf("get round %s index %s master public key %x", args[1], args[2], result) diff --git a/consensus/dexcon/dexcon.go b/consensus/dexcon/dexcon.go index aff5c9c45..c837e3a43 100644 --- a/consensus/dexcon/dexcon.go +++ b/consensus/dexcon/dexcon.go @@ -28,7 +28,7 @@ import ( ) type GovernanceStateFetcher interface { - GetGovStateHelperAtRound(round uint64) *vm.GovernanceStateHelper + GetStateForConfigAtRound(round uint64) *vm.GovernanceState } // Dexcon is a delegated proof-of-stake consensus engine. @@ -108,7 +108,7 @@ func (d *Dexcon) Prepare(chain consensus.ChainReader, header *types.Header) erro } func (d *Dexcon) calculateBlockReward(round int64, state *state.StateDB) *big.Int { - gs := d.govStateFetcer.GetGovStateHelperAtRound(uint64(round)) + gs := d.govStateFetcer.GetStateForConfigAtRound(uint64(round)) config := gs.Configuration() blocksPerRound := config.RoundLength @@ -134,7 +134,7 @@ func (d *Dexcon) calculateBlockReward(round int64, state *state.StateDB) *big.In // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given, and returns the final block. func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { - gs := vm.GovernanceStateHelper{state} + gs := vm.GovernanceState{state} height := gs.RoundHeight(new(big.Int).SetUint64(header.Round)) if header.Round > 0 && height.Uint64() == 0 { diff --git a/consensus/dexcon/dexcon_test.go b/consensus/dexcon/dexcon_test.go index 65ed77cc8..f34823570 100644 --- a/consensus/dexcon/dexcon_test.go +++ b/consensus/dexcon/dexcon_test.go @@ -35,8 +35,8 @@ type GovStateFetcher struct { statedb *state.StateDB } -func (g *GovStateFetcher) GetGovStateHelperAtRound(_ uint64) *vm.GovernanceStateHelper { - return &vm.GovernanceStateHelper{g.statedb} +func (g *GovStateFetcher) GetStateForConfigAtRound(_ uint64) *vm.GovernanceState { + return &vm.GovernanceState{g.statedb} } type DexconTestSuite struct { @@ -45,7 +45,7 @@ type DexconTestSuite struct { config *params.DexconConfig memDB *ethdb.MemDatabase stateDB *state.StateDB - s *vm.GovernanceStateHelper + s *vm.GovernanceState } func (d *DexconTestSuite) SetupTest() { @@ -56,7 +56,7 @@ func (d *DexconTestSuite) SetupTest() { } d.memDB = memDB d.stateDB = stateDB - d.s = &vm.GovernanceStateHelper{stateDB} + d.s = &vm.GovernanceState{stateDB} config := params.TestnetChainConfig.Dexcon config.LockupPeriod = 1000 @@ -73,7 +73,7 @@ func (d *DexconTestSuite) SetupTest() { // Genesis CRS. crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) - d.s.PushCRS(crs) + d.s.SetCRS(crs) // Round 0 height. d.s.PushRoundHeight(big.NewInt(0)) diff --git a/consensus/dexcon/fake_dexcon.go b/consensus/dexcon/fake_dexcon.go index ca48b5275..ae7bed90e 100644 --- a/consensus/dexcon/fake_dexcon.go +++ b/consensus/dexcon/fake_dexcon.go @@ -6,6 +6,7 @@ import ( "time" coreCommon "github.com/dexon-foundation/dexon-consensus/common" + dexCore "github.com/dexon-foundation/dexon-consensus/core" coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" coreDKG "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" @@ -250,7 +251,12 @@ func (n *NodeSet) Randomness(round uint64, hash common.Hash) []byte { } func (n *NodeSet) SignCRS(round uint64) { - signedCRS := n.TSig(round, n.crs[round]) + var signedCRS []byte + if round < dexCore.DKGDelayRound { + signedCRS = crypto.Keccak256(n.signedCRS[round]) + } else { + signedCRS = n.TSig(round, n.crs[round]) + } n.signedCRS[round+1] = signedCRS n.crs[round+1] = crypto.Keccak256Hash(signedCRS) } diff --git a/core/dexon_chain_makers.go b/core/dexon_chain_makers.go index 128cc454b..010b30c84 100644 --- a/core/dexon_chain_makers.go +++ b/core/dexon_chain_makers.go @@ -183,6 +183,7 @@ func GenerateDexonChain(config *params.ChainConfig, parent *types.Block, engine } b.header.DexconMeta = makeDexconMeta(b, parent) + b.header.Round = b.position.Round // sign tsig to create dexcon, prepare witness b.engine.Prepare(chain, b.header) diff --git a/core/evm.go b/core/evm.go index 04bc173f5..a2b61c535 100644 --- a/core/evm.go +++ b/core/evm.go @@ -67,6 +67,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author Time: new(big.Int).SetUint64(header.Time), Randomness: header.Randomness, Difficulty: new(big.Int).Set(header.Difficulty), + Round: new(big.Int).SetUint64(header.Round), GasLimit: header.GasLimit, GasPrice: new(big.Int).Set(msg.GasPrice()), } diff --git a/core/genesis.go b/core/genesis.go index ff4d9762a..f6935830c 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -33,7 +33,6 @@ import ( "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" "github.com/dexon-foundation/dexon/core/vm" - "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/params" @@ -265,7 +264,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { db = ethdb.NewMemDatabase() } statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - govStateHelper := vm.GovernanceStateHelper{StateDB: statedb} + govStateHelper := vm.GovernanceState{StateDB: statedb} totalSupply := big.NewInt(0) totalStaked := big.NewInt(0) @@ -309,26 +308,8 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { } } - if g.Config.Dexcon.NextHalvingSupply.Cmp(totalSupply) <= 0 { - panic(fmt.Sprintf("invalid genesis found, totalSupply: %s, nextHavlingSupply: %s", - totalSupply, g.Config.Dexcon.NextHalvingSupply)) - } - - // Genesis CRS. - crs := crypto.Keccak256Hash([]byte(g.Config.Dexcon.GenesisCRSText)) - govStateHelper.PushCRS(crs) - - // Round 0 height. - govStateHelper.PushRoundHeight(big.NewInt(0)) - - // Owner. - govStateHelper.SetOwner(g.Config.Dexcon.Owner) - - // Governance configuration. - govStateHelper.UpdateConfiguration(g.Config.Dexcon) - - // Set totalSupply. - govStateHelper.IncTotalSupply(totalSupply) + // Initialize governance. + govStateHelper.Initialize(g.Config.Dexcon, totalSupply) } // Set oracle contract. diff --git a/core/governance.go b/core/governance.go index 03f53ae6b..73fb0c923 100644 --- a/core/governance.go +++ b/core/governance.go @@ -48,16 +48,16 @@ func NewGovernance(db GovernanceStateDB) *Governance { return &Governance{db: db} } -func (g *Governance) GetHeadHelper() *vm.GovernanceStateHelper { +func (g *Governance) GetHeadState() *vm.GovernanceState { headState, err := g.db.State() if err != nil { log.Error("Governance head state not ready", "err", err) panic(err) } - return &vm.GovernanceStateHelper{StateDB: headState} + return &vm.GovernanceState{StateDB: headState} } -func (g *Governance) getHelperAtRound(round uint64) *vm.GovernanceStateHelper { +func (g *Governance) getHelperAtRound(round uint64) *vm.GovernanceState { height := g.GetRoundHeight(round) // Sanity check @@ -71,10 +71,10 @@ func (g *Governance) getHelperAtRound(round uint64) *vm.GovernanceStateHelper { log.Error("Governance state not ready", "round", round, "height", height, "err", err) panic(err) } - return &vm.GovernanceStateHelper{StateDB: s} + return &vm.GovernanceState{StateDB: s} } -func (g *Governance) GetGovStateHelperAtRound(round uint64) *vm.GovernanceStateHelper { +func (g *Governance) GetStateForConfigAtRound(round uint64) *vm.GovernanceState { if round < dexCore.ConfigRoundShift { round = 0 } else { @@ -83,12 +83,22 @@ func (g *Governance) GetGovStateHelperAtRound(round uint64) *vm.GovernanceStateH return g.getHelperAtRound(round) } +func (g *Governance) GetStateAtRound(round uint64) *vm.GovernanceState { + height := g.GetRoundHeight(round) + s, err := g.db.StateAt(height) + if err != nil { + log.Error("Governance state not ready", "round", round, "height", height, "err", err) + panic(err) + } + return &vm.GovernanceState{StateDB: s} +} + func (g *Governance) GetRoundHeight(round uint64) uint64 { - return g.GetHeadHelper().RoundHeight(big.NewInt(int64(round))).Uint64() + return g.GetHeadState().RoundHeight(big.NewInt(int64(round))).Uint64() } func (g *Governance) Configuration(round uint64) *coreTypes.Config { - configHelper := g.GetGovStateHelperAtRound(round) + configHelper := g.GetStateForConfigAtRound(round) c := configHelper.Configuration() return &coreTypes.Config{ LambdaBA: time.Duration(c.LambdaBA) * time.Millisecond, @@ -100,10 +110,25 @@ func (g *Governance) Configuration(round uint64) *coreTypes.Config { } } +func (g *Governance) GetStateForDKGAtRound(round uint64) *vm.GovernanceState { + dkgRound := g.GetHeadState().DKGRound().Uint64() + if round > dkgRound { + return nil + } + if round == dkgRound { + return g.GetHeadState() + } + return g.GetStateAtRound(round) +} + func (g *Governance) DKGComplaints(round uint64) []*dkgTypes.Complaint { - headHelper := g.GetHeadHelper() + s := g.GetStateForDKGAtRound(round) + if s == nil { + return nil + } + var dkgComplaints []*dkgTypes.Complaint - for _, pk := range headHelper.DKGComplaints(big.NewInt(int64(round))) { + for _, pk := range s.DKGComplaints() { x := new(dkgTypes.Complaint) if err := rlp.DecodeBytes(pk, x); err != nil { panic(err) @@ -114,30 +139,39 @@ func (g *Governance) DKGComplaints(round uint64) []*dkgTypes.Complaint { } func (g *Governance) DKGMasterPublicKeys(round uint64) []*dkgTypes.MasterPublicKey { - headHelper := g.GetHeadHelper() - return headHelper.UniqueDKGMasterPublicKeys(big.NewInt(int64(round))) + s := g.GetStateForDKGAtRound(round) + if s == nil { + return nil + } + return s.UniqueDKGMasterPublicKeys() } func (g *Governance) IsDKGMPKReady(round uint64) bool { - headHelper := g.GetHeadHelper() + s := g.GetStateForDKGAtRound(round) + if s == nil { + return false + } config := g.Configuration(round) threshold := 2*uint64(config.DKGSetSize)/3 + 1 - count := headHelper.DKGMPKReadysCount(big.NewInt(int64(round))).Uint64() + count := s.DKGMPKReadysCount().Uint64() return count >= threshold } func (g *Governance) IsDKGFinal(round uint64) bool { - headHelper := g.GetHeadHelper() + s := g.GetStateForDKGAtRound(round) + if s == nil { + return false + } config := g.Configuration(round) threshold := 2*uint64(config.DKGSetSize)/3 + 1 - count := headHelper.DKGFinalizedsCount(big.NewInt(int64(round))).Uint64() + count := s.DKGFinalizedsCount().Uint64() return count >= threshold } func (g *Governance) MinGasPrice(round uint64) *big.Int { - return g.GetGovStateHelperAtRound(round).MinGasPrice() + return g.GetStateForConfigAtRound(round).MinGasPrice() } func (g *Governance) DKGResetCount(round uint64) uint64 { - return g.GetHeadHelper().DKGResetCount(big.NewInt(int64(round))).Uint64() + return g.GetHeadState().DKGResetCount(big.NewInt(int64(round))).Uint64() } diff --git a/core/headerchain.go b/core/headerchain.go index 17cedffdd..946b96f18 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -538,7 +538,7 @@ func (hc *HeaderChain) verifyDexonHeader(header *types.Header, return fmt.Errorf("round mismatch") } - gs := gov.GetGovStateHelperAtRound(header.Round) + gs := gov.GetStateForConfigAtRound(header.Round) config := gs.Configuration() if header.GasLimit != config.BlockGasLimit { return fmt.Errorf("block gas limit mismatch") diff --git a/core/tx_pool.go b/core/tx_pool.go index 0a1b3f132..1719b4b4e 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -397,7 +397,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { } else { round -= dexCore.ConfigRoundShift } - state := &vm.GovernanceStateHelper{StateDB: statedb} + state := &vm.GovernanceState{StateDB: statedb} height := state.RoundHeight(new(big.Int).SetUint64((round))).Uint64() block := pool.chain.GetBlockByNumber(height) if block == nil { @@ -409,7 +409,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { log.Error("Failed to get txpool state for min gas price", "err", err) panic("cannot get state for new round's min gas price") } - govState := &vm.GovernanceStateHelper{StateDB: configState} + govState := &vm.GovernanceState{StateDB: configState} pool.setGovPrice(govState.MinGasPrice()) } diff --git a/core/vm/evm.go b/core/vm/evm.go index 422d52ccb..6b2844020 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -101,6 +101,7 @@ type Context struct { Time *big.Int // Provides information for TIME Randomness []byte // Provides information for RAND Difficulty *big.Int // Provides information for DIFFICULTY + Round *big.Int // Current round number. RandCallIndex uint64 // Number of times opRand is called } diff --git a/core/vm/oracle_contract_abi.go b/core/vm/oracle_contract_abi.go index ff4a94b29..43055bc4a 100644 --- a/core/vm/oracle_contract_abi.go +++ b/core/vm/oracle_contract_abi.go @@ -47,29 +47,6 @@ const GovernanceABIJSON = ` }, { "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgComplaints", - "outputs": [ - { - "name": "", - "type": "bytes" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, "inputs": [], "name": "notarySetSize", "outputs": [ @@ -223,14 +200,26 @@ const GovernanceABIJSON = ` "inputs": [ { "name": "", + "type": "address" + }, + { + "name": "", "type": "uint256" } ], - "name": "crs", + "name": "delegators", "outputs": [ { - "name": "", - "type": "bytes32" + "name": "owner", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "undelegated_at", + "type": "uint256" } ], "payable": false, @@ -242,14 +231,14 @@ const GovernanceABIJSON = ` "inputs": [ { "name": "", - "type": "uint256" + "type": "address" } ], - "name": "dkgMPKReadysCount", + "name": "dkgFinalizeds", "outputs": [ { "name": "", - "type": "uint256" + "type": "bool" } ], "payable": false, @@ -258,21 +247,12 @@ const GovernanceABIJSON = ` }, { "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "address" - } - ], - "name": "dkgMPKReadys", + "inputs": [], + "name": "blockGasLimit", "outputs": [ { "name": "", - "type": "bool" + "type": "uint256" } ], "payable": false, @@ -284,26 +264,14 @@ const GovernanceABIJSON = ` "inputs": [ { "name": "", - "type": "address" - }, - { - "name": "", - "type": "uint256" + "type": "bytes32" } ], - "name": "delegators", + "name": "nodesOffsetByID", "outputs": [ { - "name": "owner", - "type": "address" - }, - { - "name": "value", - "type": "uint256" - }, - { - "name": "undelegated_at", - "type": "uint256" + "name": "", + "type": "int256" } ], "payable": false, @@ -313,7 +281,7 @@ const GovernanceABIJSON = ` { "constant": true, "inputs": [], - "name": "blockGasLimit", + "name": "totalStaked", "outputs": [ { "name": "", @@ -329,10 +297,10 @@ const GovernanceABIJSON = ` "inputs": [ { "name": "", - "type": "bytes32" + "type": "address" } ], - "name": "nodesOffsetByID", + "name": "nodesOffsetByAddress", "outputs": [ { "name": "", @@ -346,11 +314,11 @@ const GovernanceABIJSON = ` { "constant": true, "inputs": [], - "name": "totalStaked", + "name": "crs", "outputs": [ { "name": "", - "type": "uint256" + "type": "bytes32" } ], "payable": false, @@ -359,17 +327,12 @@ const GovernanceABIJSON = ` }, { "constant": true, - "inputs": [ - { - "name": "", - "type": "address" - } - ], - "name": "nodesOffsetByAddress", + "inputs": [], + "name": "roundLength", "outputs": [ { "name": "", - "type": "int256" + "type": "uint256" } ], "payable": false, @@ -379,7 +342,7 @@ const GovernanceABIJSON = ` { "constant": true, "inputs": [], - "name": "roundLength", + "name": "nextHalvingSupply", "outputs": [ { "name": "", @@ -392,14 +355,19 @@ const GovernanceABIJSON = ` }, { "constant": true, - "inputs": [], - "name": "nextHalvingSupply", - "outputs": [ + "inputs": [ { "name": "", "type": "uint256" } ], + "name": "dkgComplaints", + "outputs": [ + { + "name": "", + "type": "bytes" + } + ], "payable": false, "stateMutability": "view", "type": "function" @@ -420,6 +388,25 @@ const GovernanceABIJSON = ` }, { "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "dkgMPKReadys", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, "inputs": [], "name": "lastHalvedAmount", "outputs": [ @@ -506,7 +493,7 @@ const GovernanceABIJSON = ` { "constant": true, "inputs": [], - "name": "minBlockInterval", + "name": "dkgMPKReadysCount", "outputs": [ { "name": "", @@ -519,21 +506,12 @@ const GovernanceABIJSON = ` }, { "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - }, - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgMasterPublicKeys", + "inputs": [], + "name": "minBlockInterval", "outputs": [ { "name": "", - "type": "bytes" + "type": "uint256" } ], "payable": false, @@ -546,17 +524,13 @@ const GovernanceABIJSON = ` { "name": "", "type": "uint256" - }, - { - "name": "", - "type": "address" } ], - "name": "dkgFinalizeds", + "name": "dkgMasterPublicKeys", "outputs": [ { "name": "", - "type": "bool" + "type": "bytes" } ], "payable": false, @@ -580,7 +554,7 @@ const GovernanceABIJSON = ` { "constant": true, "inputs": [], - "name": "lockupPeriod", + "name": "dkgFinalizedsCount", "outputs": [ { "name": "", @@ -593,13 +567,8 @@ const GovernanceABIJSON = ` }, { "constant": true, - "inputs": [ - { - "name": "", - "type": "uint256" - } - ], - "name": "dkgFinalizedsCount", + "inputs": [], + "name": "lockupPeriod", "outputs": [ { "name": "", diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index aa93c97fb..fcdc1d0a2 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -20,6 +20,7 @@ package vm import ( "bytes" "errors" + "fmt" "math/big" "sort" @@ -31,7 +32,7 @@ import ( "github.com/dexon-foundation/dexon/rlp" coreCommon "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core" + dexCore "github.com/dexon-foundation/dexon-consensus/core" coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" coreUtils "github.com/dexon-foundation/dexon-consensus/core/utils" @@ -60,7 +61,9 @@ const ( nodesOffsetByIDLoc delegatorsLoc delegatorsOffsetLoc + crsRoundLoc crsLoc + dkgRoundLoc dkgMasterPublicKeysLoc dkgComplaintsLoc dkgReadyLoc @@ -96,36 +99,36 @@ func publicKeyToNodeID(pkBytes []byte) (Bytes32, error) { } // State manipulation helper fro the governance contract. -type GovernanceStateHelper struct { +type GovernanceState struct { StateDB StateDB } -func (s *GovernanceStateHelper) getState(loc common.Hash) common.Hash { +func (s *GovernanceState) getState(loc common.Hash) common.Hash { return s.StateDB.GetState(GovernanceContractAddress, loc) } -func (s *GovernanceStateHelper) setState(loc common.Hash, val common.Hash) { +func (s *GovernanceState) setState(loc common.Hash, val common.Hash) { s.StateDB.SetState(GovernanceContractAddress, loc, val) } -func (s *GovernanceStateHelper) getStateBigInt(loc *big.Int) *big.Int { +func (s *GovernanceState) getStateBigInt(loc *big.Int) *big.Int { res := s.StateDB.GetState(GovernanceContractAddress, common.BigToHash(loc)) return new(big.Int).SetBytes(res.Bytes()) } -func (s *GovernanceStateHelper) setStateBigInt(loc *big.Int, val *big.Int) { +func (s *GovernanceState) setStateBigInt(loc *big.Int, val *big.Int) { s.setState(common.BigToHash(loc), common.BigToHash(val)) } -func (s *GovernanceStateHelper) getSlotLoc(loc *big.Int) *big.Int { +func (s *GovernanceState) getSlotLoc(loc *big.Int) *big.Int { return new(big.Int).SetBytes(crypto.Keccak256(common.BigToHash(loc).Bytes())) } -func (s *GovernanceStateHelper) getMapLoc(pos *big.Int, key []byte) *big.Int { +func (s *GovernanceState) getMapLoc(pos *big.Int, key []byte) *big.Int { return new(big.Int).SetBytes(crypto.Keccak256(key, common.BigToHash(pos).Bytes())) } -func (s *GovernanceStateHelper) readBytes(loc *big.Int) []byte { +func (s *GovernanceState) readBytes(loc *big.Int) []byte { // Length of the dynamic array (bytes). rawLength := s.getStateBigInt(loc) lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) @@ -158,7 +161,7 @@ func (s *GovernanceStateHelper) readBytes(loc *big.Int) []byte { return data } -func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) { +func (s *GovernanceState) writeBytes(loc *big.Int, data []byte) { length := int64(len(data)) if length == 0 { @@ -204,7 +207,7 @@ func (s *GovernanceStateHelper) writeBytes(loc *big.Int, data []byte) { } } -func (s *GovernanceStateHelper) eraseBytes(loc *big.Int) { +func (s *GovernanceState) eraseBytes(loc *big.Int) { // Length of the dynamic array (bytes). rawLength := s.getStateBigInt(loc) lengthByte := new(big.Int).Mod(rawLength, big.NewInt(256)) @@ -227,10 +230,7 @@ func (s *GovernanceStateHelper) eraseBytes(loc *big.Int) { s.setStateBigInt(loc, big.NewInt(0)) } -func (s *GovernanceStateHelper) read2DByteArray(pos, index *big.Int) [][]byte { - baseLoc := s.getSlotLoc(pos) - loc := new(big.Int).Add(baseLoc, index) - +func (s *GovernanceState) read1DByteArray(loc *big.Int) [][]byte { arrayLength := s.getStateBigInt(loc) dataLoc := s.getSlotLoc(loc) @@ -243,11 +243,7 @@ func (s *GovernanceStateHelper) read2DByteArray(pos, index *big.Int) [][]byte { return data } -func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data []byte) { - // Find the loc of the last element. - baseLoc := s.getSlotLoc(pos) - loc := new(big.Int).Add(baseLoc, index) - +func (s *GovernanceState) appendTo1DByteArray(loc *big.Int, data []byte) { // Increase length by 1. arrayLength := s.getStateBigInt(loc) s.setStateBigInt(loc, new(big.Int).Add(arrayLength, big.NewInt(1))) @@ -258,10 +254,7 @@ func (s *GovernanceStateHelper) appendTo2DByteArray(pos, index *big.Int, data [] s.writeBytes(elementLoc, data) } -func (s *GovernanceStateHelper) erase2DByteArray(pos, index *big.Int) { - baseLoc := s.getSlotLoc(pos) - loc := new(big.Int).Add(baseLoc, index) - +func (s *GovernanceState) erase1DByteArray(loc *big.Int) { arrayLength := s.getStateBigInt(loc) dataLoc := s.getSlotLoc(loc) @@ -273,12 +266,12 @@ func (s *GovernanceStateHelper) erase2DByteArray(pos, index *big.Int) { } // uint256[] public roundHeight; -func (s *GovernanceStateHelper) RoundHeight(round *big.Int) *big.Int { +func (s *GovernanceState) RoundHeight(round *big.Int) *big.Int { baseLoc := s.getSlotLoc(big.NewInt(roundHeightLoc)) loc := new(big.Int).Add(baseLoc, round) return s.getStateBigInt(loc) } -func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) { +func (s *GovernanceState) PushRoundHeight(height *big.Int) { // Increase length by 1. length := s.getStateBigInt(big.NewInt(roundHeightLoc)) s.setStateBigInt(big.NewInt(roundHeightLoc), new(big.Int).Add(length, big.NewInt(1))) @@ -290,24 +283,24 @@ func (s *GovernanceStateHelper) PushRoundHeight(height *big.Int) { } // uint256 public totalSupply; -func (s *GovernanceStateHelper) TotalSupply() *big.Int { +func (s *GovernanceState) TotalSupply() *big.Int { return s.getStateBigInt(big.NewInt(totalSupplyLoc)) } -func (s *GovernanceStateHelper) IncTotalSupply(amount *big.Int) { +func (s *GovernanceState) IncTotalSupply(amount *big.Int) { s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Add(s.TotalSupply(), amount)) } -func (s *GovernanceStateHelper) DecTotalSupply(amount *big.Int) { +func (s *GovernanceState) DecTotalSupply(amount *big.Int) { s.setStateBigInt(big.NewInt(totalSupplyLoc), new(big.Int).Sub(s.TotalSupply(), amount)) } // uint256 public totalStaked; -func (s *GovernanceStateHelper) TotalStaked() *big.Int { +func (s *GovernanceState) TotalStaked() *big.Int { return s.getStateBigInt(big.NewInt(totalStakedLoc)) } -func (s *GovernanceStateHelper) IncTotalStaked(amount *big.Int) { +func (s *GovernanceState) IncTotalStaked(amount *big.Int) { s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Add(s.TotalStaked(), amount)) } -func (s *GovernanceStateHelper) DecTotalStaked(amount *big.Int) { +func (s *GovernanceState) DecTotalStaked(amount *big.Int) { s.setStateBigInt(big.NewInt(totalStakedLoc), new(big.Int).Sub(s.TotalStaked(), amount)) } @@ -337,10 +330,10 @@ type nodeInfo struct { const nodeStructSize = 8 -func (s *GovernanceStateHelper) LenNodes() *big.Int { +func (s *GovernanceState) LenNodes() *big.Int { return s.getStateBigInt(big.NewInt(nodesLoc)) } -func (s *GovernanceStateHelper) Node(index *big.Int) *nodeInfo { +func (s *GovernanceState) Node(index *big.Int) *nodeInfo { node := new(nodeInfo) arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) @@ -381,14 +374,14 @@ func (s *GovernanceStateHelper) Node(index *big.Int) *nodeInfo { return node } -func (s *GovernanceStateHelper) PushNode(n *nodeInfo) { +func (s *GovernanceState) PushNode(n *nodeInfo) { // Increase length by 1. arrayLength := s.LenNodes() s.setStateBigInt(big.NewInt(nodesLoc), new(big.Int).Add(arrayLength, big.NewInt(1))) s.UpdateNode(arrayLength, n) } -func (s *GovernanceStateHelper) UpdateNode(index *big.Int, n *nodeInfo) { +func (s *GovernanceState) UpdateNode(index *big.Int, n *nodeInfo) { arrayBaseLoc := s.getSlotLoc(big.NewInt(nodesLoc)) elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(index, big.NewInt(nodeStructSize))) @@ -425,7 +418,7 @@ func (s *GovernanceStateHelper) UpdateNode(index *big.Int, n *nodeInfo) { loc = new(big.Int).Add(elementBaseLoc, big.NewInt(7)) s.writeBytes(loc, []byte(n.Url)) } -func (s *GovernanceStateHelper) PopLastNode() { +func (s *GovernanceState) PopLastNode() { // Decrease length by 1. arrayLength := s.LenNodes() newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) @@ -436,14 +429,14 @@ func (s *GovernanceStateHelper) PopLastNode() { Fined: big.NewInt(0), }) } -func (s *GovernanceStateHelper) Nodes() []*nodeInfo { +func (s *GovernanceState) Nodes() []*nodeInfo { var nodes []*nodeInfo for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { nodes = append(nodes, s.Node(big.NewInt(i))) } return nodes } -func (s *GovernanceStateHelper) QualifiedNodes() []*nodeInfo { +func (s *GovernanceState) QualifiedNodes() []*nodeInfo { var nodes []*nodeInfo for i := int64(0); i < int64(s.LenNodes().Uint64()); i++ { node := s.Node(big.NewInt(i)) @@ -455,34 +448,34 @@ func (s *GovernanceStateHelper) QualifiedNodes() []*nodeInfo { } // mapping(address => uint256) public nodeOffsetByAddress; -func (s *GovernanceStateHelper) NodesOffsetByAddress(addr common.Address) *big.Int { +func (s *GovernanceState) NodesOffsetByAddress(addr common.Address) *big.Int { loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) } -func (s *GovernanceStateHelper) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) { +func (s *GovernanceState) PutNodesOffsetByAddress(addr common.Address, offset *big.Int) { loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) } -func (s *GovernanceStateHelper) DeleteNodesOffsetByAddress(addr common.Address) { +func (s *GovernanceState) DeleteNodesOffsetByAddress(addr common.Address) { loc := s.getMapLoc(big.NewInt(nodesOffsetByAddressLoc), addr.Bytes()) s.setStateBigInt(loc, big.NewInt(0)) } // mapping(address => uint256) public nodeOffsetByID; -func (s *GovernanceStateHelper) NodesOffsetByID(id Bytes32) *big.Int { +func (s *GovernanceState) NodesOffsetByID(id Bytes32) *big.Int { loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) } -func (s *GovernanceStateHelper) PutNodesOffsetByID(id Bytes32, offset *big.Int) { +func (s *GovernanceState) PutNodesOffsetByID(id Bytes32, offset *big.Int) { loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) } -func (s *GovernanceStateHelper) DeleteNodesOffsetByID(id Bytes32) { +func (s *GovernanceState) DeleteNodesOffsetByID(id Bytes32) { loc := s.getMapLoc(big.NewInt(nodesOffsetByIDLoc), id[:]) s.setStateBigInt(loc, big.NewInt(0)) } -func (s *GovernanceStateHelper) PutNodeOffsets(n *nodeInfo, offset *big.Int) error { +func (s *GovernanceState) PutNodeOffsets(n *nodeInfo, offset *big.Int) error { id, err := publicKeyToNodeID(n.PublicKey) if err != nil { return err @@ -508,11 +501,11 @@ type delegatorInfo struct { const delegatorStructSize = 3 // mapping(address => Delegator[]) public delegators; -func (s *GovernanceStateHelper) LenDelegators(nodeAddr common.Address) *big.Int { +func (s *GovernanceState) LenDelegators(nodeAddr common.Address) *big.Int { loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) return s.getStateBigInt(loc) } -func (s *GovernanceStateHelper) Delegator(nodeAddr common.Address, offset *big.Int) *delegatorInfo { +func (s *GovernanceState) Delegator(nodeAddr common.Address, offset *big.Int) *delegatorInfo { delegator := new(delegatorInfo) loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) @@ -533,7 +526,7 @@ func (s *GovernanceStateHelper) Delegator(nodeAddr common.Address, offset *big.I return delegator } -func (s *GovernanceStateHelper) PushDelegator(nodeAddr common.Address, delegator *delegatorInfo) { +func (s *GovernanceState) PushDelegator(nodeAddr common.Address, delegator *delegatorInfo) { // Increase length by 1. arrayLength := s.LenDelegators(nodeAddr) loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) @@ -541,7 +534,7 @@ func (s *GovernanceStateHelper) PushDelegator(nodeAddr common.Address, delegator s.UpdateDelegator(nodeAddr, arrayLength, delegator) } -func (s *GovernanceStateHelper) UpdateDelegator(nodeAddr common.Address, offset *big.Int, delegator *delegatorInfo) { +func (s *GovernanceState) UpdateDelegator(nodeAddr common.Address, offset *big.Int, delegator *delegatorInfo) { loc := s.getMapLoc(big.NewInt(delegatorsLoc), nodeAddr.Bytes()) arrayBaseLoc := s.getSlotLoc(loc) elementBaseLoc := new(big.Int).Add(arrayBaseLoc, new(big.Int).Mul(big.NewInt(delegatorStructSize), offset)) @@ -558,7 +551,7 @@ func (s *GovernanceStateHelper) UpdateDelegator(nodeAddr common.Address, offset loc = new(big.Int).Add(elementBaseLoc, big.NewInt(2)) s.setStateBigInt(loc, delegator.UndelegatedAt) } -func (s *GovernanceStateHelper) PopLastDelegator(nodeAddr common.Address) { +func (s *GovernanceState) PopLastDelegator(nodeAddr common.Address) { // Decrease length by 1. arrayLength := s.LenDelegators(nodeAddr) newArrayLength := new(big.Int).Sub(arrayLength, big.NewInt(1)) @@ -572,67 +565,55 @@ func (s *GovernanceStateHelper) PopLastDelegator(nodeAddr common.Address) { } // mapping(address => mapping(address => uint256)) delegatorsOffset; -func (s *GovernanceStateHelper) DelegatorsOffset(nodeAddr, delegatorAddr common.Address) *big.Int { +func (s *GovernanceState) DelegatorsOffset(nodeAddr, delegatorAddr common.Address) *big.Int { loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) return new(big.Int).Sub(s.getStateBigInt(loc), big.NewInt(1)) } -func (s *GovernanceStateHelper) PutDelegatorOffset(nodeAddr, delegatorAddr common.Address, offset *big.Int) { +func (s *GovernanceState) PutDelegatorOffset(nodeAddr, delegatorAddr common.Address, offset *big.Int) { loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) s.setStateBigInt(loc, new(big.Int).Add(offset, big.NewInt(1))) } -func (s *GovernanceStateHelper) DeleteDelegatorsOffset(nodeAddr, delegatorAddr common.Address) { +func (s *GovernanceState) DeleteDelegatorsOffset(nodeAddr, delegatorAddr common.Address) { loc := s.getMapLoc(s.getMapLoc(big.NewInt(delegatorsOffsetLoc), nodeAddr.Bytes()), delegatorAddr.Bytes()) s.setStateBigInt(loc, big.NewInt(0)) } -// bytes32[] public crs; -func (s *GovernanceStateHelper) LenCRS() *big.Int { - return s.getStateBigInt(big.NewInt(crsLoc)) +// uint256 public crsRound; +func (s *GovernanceState) CRSRound() *big.Int { + return s.getStateBigInt(big.NewInt(crsRoundLoc)) } -func (s *GovernanceStateHelper) CRS(index *big.Int) common.Hash { - baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) - loc := new(big.Int).Add(baseLoc, index) - return s.getState(common.BigToHash(loc)) +func (s *GovernanceState) SetCRSRound(round *big.Int) { + s.setStateBigInt(big.NewInt(crsRoundLoc), round) } -func (s *GovernanceStateHelper) CurrentCRS() common.Hash { - return s.CRS(new(big.Int).Sub(s.LenCRS(), big.NewInt(1))) -} -func (s *GovernanceStateHelper) PushCRS(crs common.Hash) { - // increase length by 1. - length := s.getStateBigInt(big.NewInt(crsLoc)) - s.setStateBigInt(big.NewInt(crsLoc), new(big.Int).Add(length, big.NewInt(1))) - - baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) - loc := new(big.Int).Add(baseLoc, length) - s.setState(common.BigToHash(loc), crs) +// bytes32 public crs; +func (s *GovernanceState) CRS() common.Hash { + return s.getState(common.BigToHash(big.NewInt(crsLoc))) +} +func (s *GovernanceState) SetCRS(crs common.Hash) { + s.setState(common.BigToHash(big.NewInt(crsLoc)), crs) } -func (s *GovernanceStateHelper) PopCRS() { - // decrease length by 1. - length := s.getStateBigInt(big.NewInt(crsLoc)) - s.setStateBigInt(big.NewInt(crsLoc), new(big.Int).Sub(length, big.NewInt(1))) - - baseLoc := s.getSlotLoc(big.NewInt(crsLoc)) - loc := new(big.Int).Add(baseLoc, length) - s.setState(common.BigToHash(loc), common.Hash{}) +// uint256 public dkgRound; +func (s *GovernanceState) DKGRound() *big.Int { + return s.getStateBigInt(big.NewInt(dkgRoundLoc)) } -func (s *GovernanceStateHelper) Round() *big.Int { - return new(big.Int).Sub(s.getStateBigInt(big.NewInt(crsLoc)), big.NewInt(1)) +func (s *GovernanceState) SetDKGRound(round *big.Int) { + s.setStateBigInt(big.NewInt(dkgRoundLoc), round) } -// bytes[][] public dkgMasterPublicKeys; -func (s *GovernanceStateHelper) DKGMasterPublicKeys(round *big.Int) [][]byte { - return s.read2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round) +// bytes[] public dkgMasterPublicKeys; +func (s *GovernanceState) DKGMasterPublicKeys() [][]byte { + return s.read1DByteArray(big.NewInt(dkgMasterPublicKeysLoc)) } -func (s *GovernanceStateHelper) PushDKGMasterPublicKey(round *big.Int, mpk []byte) { - s.appendTo2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round, mpk) +func (s *GovernanceState) PushDKGMasterPublicKey(mpk []byte) { + s.appendTo1DByteArray(big.NewInt(dkgMasterPublicKeysLoc), mpk) } -func (s *GovernanceStateHelper) UniqueDKGMasterPublicKeys(round *big.Int) []*dkgTypes.MasterPublicKey { +func (s *GovernanceState) UniqueDKGMasterPublicKeys() []*dkgTypes.MasterPublicKey { // Prepare DKGMasterPublicKeys. var dkgMasterPKs []*dkgTypes.MasterPublicKey existence := make(map[coreTypes.NodeID]struct{}) - for _, mpk := range s.DKGMasterPublicKeys(round) { + for _, mpk := range s.DKGMasterPublicKeys() { x := new(dkgTypes.MasterPublicKey) if err := rlp.DecodeBytes(mpk, x); err != nil { panic(err) @@ -647,10 +628,10 @@ func (s *GovernanceStateHelper) UniqueDKGMasterPublicKeys(round *big.Int) []*dkg } return dkgMasterPKs } -func (s *GovernanceStateHelper) GetDKGMasterPublicKeyByProposerID( - round *big.Int, proposerID coreTypes.NodeID) (*dkgTypes.MasterPublicKey, error) { +func (s *GovernanceState) GetDKGMasterPublicKeyByProposerID( + proposerID coreTypes.NodeID) (*dkgTypes.MasterPublicKey, error) { - for _, mpk := range s.DKGMasterPublicKeys(round) { + for _, mpk := range s.DKGMasterPublicKeys() { x := new(dkgTypes.MasterPublicKey) if err := rlp.DecodeBytes(mpk, x); err != nil { panic(err) @@ -661,199 +642,189 @@ func (s *GovernanceStateHelper) GetDKGMasterPublicKeyByProposerID( } return nil, errors.New("not found") } -func (s *GovernanceStateHelper) ClearDKGMasterPublicKeys(round *big.Int) { - s.erase2DByteArray(big.NewInt(dkgMasterPublicKeysLoc), round) +func (s *GovernanceState) ClearDKGMasterPublicKeys() { + s.erase1DByteArray(big.NewInt(dkgMasterPublicKeysLoc)) } -// bytes[][] public dkgComplaints; -func (s *GovernanceStateHelper) DKGComplaints(round *big.Int) [][]byte { - return s.read2DByteArray(big.NewInt(dkgComplaintsLoc), round) +// bytes[] public dkgComplaints; +func (s *GovernanceState) DKGComplaints() [][]byte { + return s.read1DByteArray(big.NewInt(dkgComplaintsLoc)) } -func (s *GovernanceStateHelper) PushDKGComplaint(round *big.Int, complaint []byte) { - s.appendTo2DByteArray(big.NewInt(dkgComplaintsLoc), round, complaint) +func (s *GovernanceState) PushDKGComplaint(complaint []byte) { + s.appendTo1DByteArray(big.NewInt(dkgComplaintsLoc), complaint) } -func (s *GovernanceStateHelper) ClearDKGComplaints(round *big.Int) { - s.erase2DByteArray(big.NewInt(dkgComplaintsLoc), round) +func (s *GovernanceState) ClearDKGComplaints() { + s.erase1DByteArray(big.NewInt(dkgComplaintsLoc)) } -// mapping(address => bool)[] public dkgReady; -func (s *GovernanceStateHelper) DKGMPKReady(round *big.Int, addr common.Address) bool { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) +// mapping(address => bool) public dkgReady; +func (s *GovernanceState) DKGMPKReady(addr common.Address) bool { + mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes()) return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 } -func (s *GovernanceStateHelper) PutDKGMPKReady(round *big.Int, addr common.Address, ready bool) { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadyLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) +func (s *GovernanceState) PutDKGMPKReady(addr common.Address, ready bool) { + mapLoc := s.getMapLoc(big.NewInt(dkgReadyLoc), addr.Bytes()) res := big.NewInt(0) if ready { res = big.NewInt(1) } s.setStateBigInt(mapLoc, res) } -func (s *GovernanceStateHelper) ClearDKGMPKReady(round *big.Int, dkgSet map[coreTypes.NodeID]struct{}) { +func (s *GovernanceState) ClearDKGMPKReady(dkgSet map[coreTypes.NodeID]struct{}) { for id := range dkgSet { offset := s.NodesOffsetByID(Bytes32(id.Hash)) if offset.Cmp(big.NewInt(0)) < 0 { panic(errors.New("DKG node does not exist")) } node := s.Node(offset) - s.PutDKGMPKReady(round, node.Owner, false) + s.PutDKGMPKReady(node.Owner, false) } } -// uint256[] public dkgReadysCount; -func (s *GovernanceStateHelper) DKGMPKReadysCount(round *big.Int) *big.Int { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) - return s.getStateBigInt(loc) +// uint256 public dkgReadysCount; +func (s *GovernanceState) DKGMPKReadysCount() *big.Int { + return s.getStateBigInt(big.NewInt(dkgReadysCountLoc)) } -func (s *GovernanceStateHelper) IncDKGMPKReadysCount(round *big.Int) { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) - count := s.getStateBigInt(loc) - s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) +func (s *GovernanceState) IncDKGMPKReadysCount() { + s.setStateBigInt(big.NewInt(dkgReadysCountLoc), + new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgReadysCountLoc)), big.NewInt(1))) } -func (s *GovernanceStateHelper) ResetDKGMPKReadysCount(round *big.Int) { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgReadysCountLoc)), round) - s.setStateBigInt(loc, big.NewInt(0)) +func (s *GovernanceState) ResetDKGMPKReadysCount() { + s.setStateBigInt(big.NewInt(dkgReadysCountLoc), big.NewInt(0)) } -// mapping(address => bool)[] public dkgFinalized; -func (s *GovernanceStateHelper) DKGFinalized(round *big.Int, addr common.Address) bool { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) +// mapping(address => bool) public dkgFinalized; +func (s *GovernanceState) DKGFinalized(addr common.Address) bool { + mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes()) return s.getStateBigInt(mapLoc).Cmp(big.NewInt(0)) != 0 } -func (s *GovernanceStateHelper) PutDKGFinalized(round *big.Int, addr common.Address, finalized bool) { - baseLoc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedLoc)), round) - mapLoc := s.getMapLoc(baseLoc, addr.Bytes()) +func (s *GovernanceState) PutDKGFinalized(addr common.Address, finalized bool) { + mapLoc := s.getMapLoc(big.NewInt(dkgFinalizedLoc), addr.Bytes()) res := big.NewInt(0) if finalized { res = big.NewInt(1) } s.setStateBigInt(mapLoc, res) } -func (s *GovernanceStateHelper) ClearDKGFinalized(round *big.Int, dkgSet map[coreTypes.NodeID]struct{}) { +func (s *GovernanceState) ClearDKGFinalized(dkgSet map[coreTypes.NodeID]struct{}) { for id := range dkgSet { offset := s.NodesOffsetByID(Bytes32(id.Hash)) if offset.Cmp(big.NewInt(0)) < 0 { panic(errors.New("DKG node does not exist")) } node := s.Node(offset) - s.PutDKGFinalized(round, node.Owner, false) + s.PutDKGFinalized(node.Owner, false) } } -// uint256[] public dkgFinalizedsCount; -func (s *GovernanceStateHelper) DKGFinalizedsCount(round *big.Int) *big.Int { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) - return s.getStateBigInt(loc) +// uint256 public dkgFinalizedsCount; +func (s *GovernanceState) DKGFinalizedsCount() *big.Int { + return s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc)) } -func (s *GovernanceStateHelper) IncDKGFinalizedsCount(round *big.Int) { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) - count := s.getStateBigInt(loc) - s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) +func (s *GovernanceState) IncDKGFinalizedsCount() { + s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), + new(big.Int).Add(s.getStateBigInt(big.NewInt(dkgFinalizedsCountLoc)), big.NewInt(1))) } -func (s *GovernanceStateHelper) ResetDKGFinalizedsCount(round *big.Int) { - loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgFinalizedsCountLoc)), round) - s.setStateBigInt(loc, big.NewInt(0)) +func (s *GovernanceState) ResetDKGFinalizedsCount() { + s.setStateBigInt(big.NewInt(dkgFinalizedsCountLoc), big.NewInt(0)) } // address public owner; -func (s *GovernanceStateHelper) Owner() common.Address { +func (s *GovernanceState) Owner() common.Address { val := s.getState(common.BigToHash(big.NewInt(ownerLoc))) return common.BytesToAddress(val.Bytes()) } -func (s *GovernanceStateHelper) SetOwner(newOwner common.Address) { +func (s *GovernanceState) SetOwner(newOwner common.Address) { s.setState(common.BigToHash(big.NewInt(ownerLoc)), newOwner.Hash()) } // uint256 public minStake; -func (s *GovernanceStateHelper) MinStake() *big.Int { +func (s *GovernanceState) MinStake() *big.Int { return s.getStateBigInt(big.NewInt(minStakeLoc)) } // uint256 public lockupPeriod; -func (s *GovernanceStateHelper) LockupPeriod() *big.Int { +func (s *GovernanceState) LockupPeriod() *big.Int { return s.getStateBigInt(big.NewInt(lockupPeriodLoc)) } // uint256 public miningVelocity; -func (s *GovernanceStateHelper) MiningVelocity() *big.Int { +func (s *GovernanceState) MiningVelocity() *big.Int { return s.getStateBigInt(big.NewInt(miningVelocityLoc)) } -func (s *GovernanceStateHelper) HalfMiningVelocity() { +func (s *GovernanceState) HalfMiningVelocity() { s.setStateBigInt(big.NewInt(miningVelocityLoc), new(big.Int).Div(s.MiningVelocity(), big.NewInt(2))) } // uint256 public nextHalvingSupply; -func (s *GovernanceStateHelper) NextHalvingSupply() *big.Int { +func (s *GovernanceState) NextHalvingSupply() *big.Int { return s.getStateBigInt(big.NewInt(nextHalvingSupplyLoc)) } -func (s *GovernanceStateHelper) IncNextHalvingSupply(amount *big.Int) { +func (s *GovernanceState) IncNextHalvingSupply(amount *big.Int) { s.setStateBigInt(big.NewInt(nextHalvingSupplyLoc), new(big.Int).Add(s.NextHalvingSupply(), amount)) } // uint256 public lastHalvedAmount; -func (s *GovernanceStateHelper) LastHalvedAmount() *big.Int { +func (s *GovernanceState) LastHalvedAmount() *big.Int { return s.getStateBigInt(big.NewInt(lastHalvedAmountLoc)) } -func (s *GovernanceStateHelper) HalfLastHalvedAmount() { +func (s *GovernanceState) HalfLastHalvedAmount() { s.setStateBigInt(big.NewInt(lastHalvedAmountLoc), new(big.Int).Div(s.LastHalvedAmount(), big.NewInt(2))) } -func (s *GovernanceStateHelper) MiningHalved() { +func (s *GovernanceState) MiningHalved() { s.HalfMiningVelocity() s.HalfLastHalvedAmount() s.IncNextHalvingSupply(s.LastHalvedAmount()) } // uint256 public blockGasLimit; -func (s *GovernanceStateHelper) BlockGasLimit() *big.Int { +func (s *GovernanceState) BlockGasLimit() *big.Int { return s.getStateBigInt(big.NewInt(blockGasLimitLoc)) } -func (s *GovernanceStateHelper) SetBlockGasLimit(reward *big.Int) { +func (s *GovernanceState) SetBlockGasLimit(reward *big.Int) { s.setStateBigInt(big.NewInt(blockGasLimitLoc), reward) } // uint256 public lambdaBA; -func (s *GovernanceStateHelper) LambdaBA() *big.Int { +func (s *GovernanceState) LambdaBA() *big.Int { return s.getStateBigInt(big.NewInt(lambdaBALoc)) } // uint256 public lambdaDKG; -func (s *GovernanceStateHelper) LambdaDKG() *big.Int { +func (s *GovernanceState) LambdaDKG() *big.Int { return s.getStateBigInt(big.NewInt(lambdaDKGLoc)) } // uint256 public notarySetSize; -func (s *GovernanceStateHelper) NotarySetSize() *big.Int { +func (s *GovernanceState) NotarySetSize() *big.Int { return s.getStateBigInt(big.NewInt(notarySetSizeLoc)) } // uint256 public dkgSetSize; -func (s *GovernanceStateHelper) DKGSetSize() *big.Int { +func (s *GovernanceState) DKGSetSize() *big.Int { return s.getStateBigInt(big.NewInt(dkgSetSizeLoc)) } // uint256 public roundLength; -func (s *GovernanceStateHelper) RoundLength() *big.Int { +func (s *GovernanceState) RoundLength() *big.Int { return s.getStateBigInt(big.NewInt(roundLengthLoc)) } // uint256 public minBlockInterval; -func (s *GovernanceStateHelper) MinBlockInterval() *big.Int { +func (s *GovernanceState) MinBlockInterval() *big.Int { return s.getStateBigInt(big.NewInt(minBlockIntervalLoc)) } // uint256[] public fineValues; -func (s *GovernanceStateHelper) FineValue(index *big.Int) *big.Int { +func (s *GovernanceState) FineValue(index *big.Int) *big.Int { arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, index)) } -func (s *GovernanceStateHelper) FineValues() []*big.Int { +func (s *GovernanceState) FineValues() []*big.Int { len := s.getStateBigInt(big.NewInt(fineValuesLoc)) result := make([]*big.Int, len.Uint64()) for i := 0; i < int(len.Uint64()); i++ { @@ -861,7 +832,7 @@ func (s *GovernanceStateHelper) FineValues() []*big.Int { } return result } -func (s *GovernanceStateHelper) SetFineValues(values []*big.Int) { +func (s *GovernanceState) SetFineValues(values []*big.Int) { s.setStateBigInt(big.NewInt(fineValuesLoc), big.NewInt(int64(len(values)))) arrayBaseLoc := s.getSlotLoc(big.NewInt(fineValuesLoc)) @@ -871,11 +842,11 @@ func (s *GovernanceStateHelper) SetFineValues(values []*big.Int) { } // mapping(bytes32 => bool) public fineRdecords; -func (s *GovernanceStateHelper) FineRecords(recordHash Bytes32) bool { +func (s *GovernanceState) FineRecords(recordHash Bytes32) bool { loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) return s.getStateBigInt(loc).Cmp(big.NewInt(0)) > 0 } -func (s *GovernanceStateHelper) SetFineRecords(recordHash Bytes32, status bool) { +func (s *GovernanceState) SetFineRecords(recordHash Bytes32, status bool) { loc := s.getMapLoc(big.NewInt(finedRecordsLoc), recordHash[:]) value := int64(0) if status { @@ -885,23 +856,50 @@ func (s *GovernanceStateHelper) SetFineRecords(recordHash Bytes32, status bool) } // uint256[] public DKGResetCount; -func (s *GovernanceStateHelper) DKGResetCount(round *big.Int) *big.Int { +func (s *GovernanceState) DKGResetCount(round *big.Int) *big.Int { arrayBaseLoc := s.getSlotLoc(big.NewInt(dkgResetCountLoc)) return s.getStateBigInt(new(big.Int).Add(arrayBaseLoc, round)) } -func (s *GovernanceStateHelper) IncDKGResetCount(round *big.Int) { +func (s *GovernanceState) IncDKGResetCount(round *big.Int) { loc := new(big.Int).Add(s.getSlotLoc(big.NewInt(dkgResetCountLoc)), round) count := s.getStateBigInt(loc) s.setStateBigInt(loc, new(big.Int).Add(count, big.NewInt(1))) } // uint256 public minGasPrice; -func (s *GovernanceStateHelper) MinGasPrice() *big.Int { +func (s *GovernanceState) MinGasPrice() *big.Int { return s.getStateBigInt(big.NewInt(minGasPriceLoc)) } +// Initialize initializes governance contract state. +func (s *GovernanceState) Initialize(config *params.DexconConfig, totalSupply *big.Int) { + if config.NextHalvingSupply.Cmp(totalSupply) <= 0 { + panic(fmt.Sprintf("invalid genesis found, totalSupply: %s, nextHavlingSupply: %s", + totalSupply, config.NextHalvingSupply)) + } + + // Genesis CRS. + crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) + s.SetCRS(crs) + + // Round 0 height. + s.PushRoundHeight(big.NewInt(0)) + + // Owner. + s.SetOwner(config.Owner) + + // Governance configuration. + s.UpdateConfiguration(config) + + // Set totalSupply. + s.IncTotalSupply(totalSupply) + + // Set DKGRound. + s.SetDKGRound(big.NewInt(int64(dexCore.DKGDelayRound))) +} + // Stake is a helper function for creating genesis state. -func (s *GovernanceStateHelper) Stake( +func (s *GovernanceState) Stake( addr common.Address, publicKey []byte, staked *big.Int, name, email, location, url string) { offset := s.LenNodes() @@ -939,7 +937,7 @@ func (s *GovernanceStateHelper) Stake( const decimalMultiplier = 100000000.0 // Configuration returns the current configuration. -func (s *GovernanceStateHelper) Configuration() *params.DexconConfig { +func (s *GovernanceState) Configuration() *params.DexconConfig { return ¶ms.DexconConfig{ MinStake: s.getStateBigInt(big.NewInt(minStakeLoc)), LockupPeriod: s.getStateBigInt(big.NewInt(lockupPeriodLoc)).Uint64(), @@ -959,7 +957,7 @@ func (s *GovernanceStateHelper) Configuration() *params.DexconConfig { } // UpdateConfiguration updates system configuration. -func (s *GovernanceStateHelper) UpdateConfiguration(cfg *params.DexconConfig) { +func (s *GovernanceState) UpdateConfiguration(cfg *params.DexconConfig) { s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) s.setStateBigInt(big.NewInt(lockupPeriodLoc), big.NewInt(int64(cfg.LockupPeriod))) s.setStateBigInt(big.NewInt(miningVelocityLoc), big.NewInt(int64(cfg.MiningVelocity*decimalMultiplier))) @@ -991,7 +989,7 @@ type rawConfigStruct struct { } // UpdateConfigurationRaw updates system configuration. -func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) { +func (s *GovernanceState) UpdateConfigurationRaw(cfg *rawConfigStruct) { s.setStateBigInt(big.NewInt(minStakeLoc), cfg.MinStake) s.setStateBigInt(big.NewInt(lockupPeriodLoc), cfg.LockupPeriod) s.setStateBigInt(big.NewInt(blockGasLimitLoc), cfg.BlockGasLimit) @@ -1006,7 +1004,7 @@ func (s *GovernanceStateHelper) UpdateConfigurationRaw(cfg *rawConfigStruct) { } // event ConfigurationChanged(); -func (s *GovernanceStateHelper) emitConfigurationChangedEvent() { +func (s *GovernanceState) emitConfigurationChangedEvent() { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["ConfigurationChanged"].Id()}, @@ -1015,7 +1013,7 @@ func (s *GovernanceStateHelper) emitConfigurationChangedEvent() { } // event CRSProposed(uint256 round, bytes32 crs); -func (s *GovernanceStateHelper) emitCRSProposed(round *big.Int, crs common.Hash) { +func (s *GovernanceState) emitCRSProposed(round *big.Int, crs common.Hash) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["CRSProposed"].Id(), common.BigToHash(round)}, @@ -1024,7 +1022,7 @@ func (s *GovernanceStateHelper) emitCRSProposed(round *big.Int, crs common.Hash) } // event Staked(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) { +func (s *GovernanceState) emitStaked(nodeAddr common.Address) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["Staked"].Id(), nodeAddr.Hash()}, @@ -1033,7 +1031,7 @@ func (s *GovernanceStateHelper) emitStaked(nodeAddr common.Address) { } // event Unstaked(address indexed NodeAddress); -func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) { +func (s *GovernanceState) emitUnstaked(nodeAddr common.Address) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["Unstaked"].Id(), nodeAddr.Hash()}, @@ -1042,7 +1040,7 @@ func (s *GovernanceStateHelper) emitUnstaked(nodeAddr common.Address) { } // event NodeRemoved(address indexed NodeAddress); -func (s *GovernanceStateHelper) emitNodeRemoved(nodeAddr common.Address) { +func (s *GovernanceState) emitNodeRemoved(nodeAddr common.Address) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["NodeRemoved"].Id(), nodeAddr.Hash()}, @@ -1051,7 +1049,7 @@ func (s *GovernanceStateHelper) emitNodeRemoved(nodeAddr common.Address) { } // event Delegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitDelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { +func (s *GovernanceState) emitDelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["Delegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, @@ -1060,7 +1058,7 @@ func (s *GovernanceStateHelper) emitDelegated(nodeAddr, delegatorAddr common.Add } // event Undelegated(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { +func (s *GovernanceState) emitUndelegated(nodeAddr, delegatorAddr common.Address, amount *big.Int) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["Undelegated"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, @@ -1069,7 +1067,7 @@ func (s *GovernanceStateHelper) emitUndelegated(nodeAddr, delegatorAddr common.A } // event Withdrawn(address indexed NodeAddress, address indexed DelegatorAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitWithdrawn(nodeAddr common.Address, delegatorAddr common.Address, amount *big.Int) { +func (s *GovernanceState) emitWithdrawn(nodeAddr common.Address, delegatorAddr common.Address, amount *big.Int) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["Withdrawn"].Id(), nodeAddr.Hash(), delegatorAddr.Hash()}, @@ -1078,7 +1076,7 @@ func (s *GovernanceStateHelper) emitWithdrawn(nodeAddr common.Address, delegator } // event ForkReported(address indexed NodeAddress, address indexed Type, bytes Arg1, bytes Arg2); -func (s *GovernanceStateHelper) emitForkReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) { +func (s *GovernanceState) emitForkReported(nodeAddr common.Address, reportType *big.Int, arg1, arg2 []byte) { t, err := abi.NewType("bytes", nil) if err != nil { @@ -1110,7 +1108,7 @@ func (s *GovernanceStateHelper) emitForkReported(nodeAddr common.Address, report } // event Fined(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitFined(nodeAddr common.Address, amount *big.Int) { +func (s *GovernanceState) emitFined(nodeAddr common.Address, amount *big.Int) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["Fined"].Id(), nodeAddr.Hash()}, @@ -1119,7 +1117,7 @@ func (s *GovernanceStateHelper) emitFined(nodeAddr common.Address, amount *big.I } // event FinePaid(address indexed NodeAddress, uint256 Amount); -func (s *GovernanceStateHelper) emitFinePaid(nodeAddr common.Address, amount *big.Int) { +func (s *GovernanceState) emitFinePaid(nodeAddr common.Address, amount *big.Int) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["FinePaid"].Id(), nodeAddr.Hash()}, @@ -1128,7 +1126,7 @@ func (s *GovernanceStateHelper) emitFinePaid(nodeAddr common.Address, amount *bi } // event DKGReset(uint256 indexed Round, uint256 BlockHeight); -func (s *GovernanceStateHelper) emitDKGReset(round *big.Int, blockHeight *big.Int) { +func (s *GovernanceState) emitDKGReset(round *big.Int, blockHeight *big.Int) { s.StateDB.AddLog(&types.Log{ Address: GovernanceContractAddress, Topics: []common.Hash{GovernanceABI.Events["DKGReset"].Id(), common.BigToHash(round)}, @@ -1136,25 +1134,28 @@ func (s *GovernanceStateHelper) emitDKGReset(round *big.Int, blockHeight *big.In }) } -func getConfigState(evm *EVM, round *big.Int) (*GovernanceStateHelper, error) { - configRound := big.NewInt(0) - if round.Uint64() > core.ConfigRoundShift { - configRound = new(big.Int).Sub(round, big.NewInt(int64(core.ConfigRoundShift))) - } - - gs := &GovernanceStateHelper{evm.StateDB} - height := gs.RoundHeight(configRound).Uint64() - if round.Uint64() > core.ConfigRoundShift { +func getRoundState(evm *EVM, round *big.Int) (*GovernanceState, error) { + gs := &GovernanceState{evm.StateDB} + height := gs.RoundHeight(round).Uint64() + if round.Uint64() > dexCore.ConfigRoundShift { if height == 0 { return nil, errExecutionReverted } } statedb, err := evm.StateAtNumber(height) - return &GovernanceStateHelper{statedb}, err + return &GovernanceState{statedb}, err +} + +func getConfigState(evm *EVM, round *big.Int) (*GovernanceState, error) { + configRound := big.NewInt(0) + if round.Uint64() > dexCore.ConfigRoundShift { + configRound = new(big.Int).Sub(round, big.NewInt(int64(dexCore.ConfigRoundShift))) + } + return getRoundState(evm, configRound) } type coreDKGUtils interface { - SetState(GovernanceStateHelper) + SetState(GovernanceState) NewGroupPublicKey(*big.Int, int) (tsigVerifierIntf, error) } type tsigVerifierIntf interface { @@ -1164,28 +1165,27 @@ type tsigVerifierIntf interface { // GovernanceContract represents the governance contract of DEXCON. type GovernanceContract struct { evm *EVM - state GovernanceStateHelper + state GovernanceState contract *Contract coreDKGUtils coreDKGUtils } // defaultCoreDKGUtils implements coreDKGUtils. type defaultCoreDKGUtils struct { - state GovernanceStateHelper + state GovernanceState } -func (c *defaultCoreDKGUtils) SetState(state GovernanceStateHelper) { +func (c *defaultCoreDKGUtils) SetState(state GovernanceState) { c.state = state } -func (c *defaultCoreDKGUtils) NewGroupPublicKey(round *big.Int, - threshold int) (tsigVerifierIntf, error) { +func (c *defaultCoreDKGUtils) NewGroupPublicKey(round *big.Int, threshold int) (tsigVerifierIntf, error) { // Prepare DKGMasterPublicKeys. - mpks := c.state.UniqueDKGMasterPublicKeys(round) + mpks := c.state.UniqueDKGMasterPublicKeys() // Prepare DKGComplaints. var complaints []*dkgTypes.Complaint - for _, comp := range c.state.DKGComplaints(round) { + for _, comp := range c.state.DKGComplaints() { x := new(dkgTypes.Complaint) if err := rlp.DecodeBytes(comp, x); err != nil { panic(err) @@ -1193,7 +1193,7 @@ func (c *defaultCoreDKGUtils) NewGroupPublicKey(round *big.Int, complaints = append(complaints, x) } - return core.NewDKGGroupPublicKey(round.Uint64(), mpks, complaints, threshold) + return dexCore.NewDKGGroupPublicKey(round.Uint64(), mpks, complaints, threshold) } func (g *GovernanceContract) Address() common.Address { @@ -1229,7 +1229,7 @@ func (g *GovernanceContract) configDKGSetSize(round *big.Int) *big.Int { return s.DKGSetSize() } func (g *GovernanceContract) getDKGSet(round *big.Int) map[coreTypes.NodeID]struct{} { - target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CRS(round))) + target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.state.CRS())) ns := coreTypes.NewNodeSet() state, err := getConfigState(g.evm, round) @@ -1252,15 +1252,21 @@ func (g *GovernanceContract) inDKGSet(round *big.Int, nodeID coreTypes.NodeID) b return ok } -func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byte, error) { - if round.Cmp(g.state.Round()) != 0 { - return g.penalize() - } +func (g *GovernanceContract) clearDKG() { + dkgSet := g.getDKGSet(g.evm.Round) + g.state.ClearDKGMasterPublicKeys() + g.state.ClearDKGComplaints() + g.state.ClearDKGMPKReady(dkgSet) + g.state.ResetDKGMPKReadysCount() + g.state.ClearDKGFinalized(dkgSet) + g.state.ResetDKGFinalizedsCount() +} +func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byte, error) { caller := g.contract.Caller() // Finalized caller is not allowed to propose complaint. - if g.state.DKGFinalized(round, caller) { + if g.state.DKGFinalized(caller) { return g.penalize() } @@ -1270,7 +1276,7 @@ func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byt new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3))) // If 2f + 1 of DKG set is finalized, one can not propose complaint anymore. - if g.state.DKGFinalizedsCount(round).Cmp(threshold) > 0 { + if g.state.DKGFinalizedsCount().Cmp(threshold) > 0 { return nil, errExecutionReverted } @@ -1289,8 +1295,7 @@ func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byt return g.penalize() } - mpk, err := g.state.GetDKGMasterPublicKeyByProposerID( - round, dkgComplaint.PrivateShare.ProposerID) + mpk, err := g.state.GetDKGMasterPublicKeyByProposerID(dkgComplaint.PrivateShare.ProposerID) if err != nil { return g.penalize() } @@ -1315,28 +1320,35 @@ func (g *GovernanceContract) addDKGComplaint(round *big.Int, comp []byte) ([]byt } } - g.state.PushDKGComplaint(round, comp) + g.state.PushDKGComplaint(comp) // Set this to relatively high to prevent spamming return g.useGas(5000000) } func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ([]byte, error) { - // Can only add DKG master public key of current and next round. - if round.Cmp(new(big.Int).Add(g.state.Round(), big.NewInt(1))) > 0 { - return g.penalize() - } - caller := g.contract.Caller() offset := g.state.NodesOffsetByAddress(caller) + if g.evm.Round.Uint64() > 0 { + if round.Uint64() != g.evm.Round.Uint64()+1 { + return nil, errExecutionReverted + } + + if g.state.DKGRound().Cmp(g.evm.Round) == 0 { + // Clear DKG states for next round. + g.clearDKG() + g.state.SetDKGRound(round) + } + } + // Can not add dkg mpk if not staked. if offset.Cmp(big.NewInt(0)) < 0 { return nil, errExecutionReverted } // MPKReady caller is not allowed to propose mpk. - if g.state.DKGMPKReady(round, caller) { + if g.state.DKGMPKReady(caller) { return g.penalize() } @@ -1346,7 +1358,7 @@ func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ( new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3))) // If 2f + 1 of DKG set is mpk ready, one can not propose mpk anymore. - if g.state.DKGMPKReadysCount(round).Cmp(threshold) > 0 { + if g.state.DKGMPKReadysCount().Cmp(threshold) > 0 { return nil, errExecutionReverted } @@ -1365,16 +1377,12 @@ func (g *GovernanceContract) addDKGMasterPublicKey(round *big.Int, mpk []byte) ( return g.penalize() } - g.state.PushDKGMasterPublicKey(round, mpk) + g.state.PushDKGMasterPublicKey(mpk) return g.useGas(100000) } func (g *GovernanceContract) addDKGMPKReady(round *big.Int, ready []byte) ([]byte, error) { - if round.Cmp(g.state.Round()) != 0 { - return g.penalize() - } - caller := g.contract.Caller() var dkgReady dkgTypes.MPKReady @@ -1392,18 +1400,14 @@ func (g *GovernanceContract) addDKGMPKReady(round *big.Int, ready []byte) ([]byt return g.penalize() } - if !g.state.DKGMPKReady(round, caller) { - g.state.PutDKGMPKReady(round, caller, true) - g.state.IncDKGMPKReadysCount(round) + if !g.state.DKGMPKReady(caller) { + g.state.PutDKGMPKReady(caller, true) + g.state.IncDKGMPKReadysCount() } return g.useGas(100000) } func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([]byte, error) { - if round.Cmp(g.state.Round()) != 0 { - return g.penalize() - } - caller := g.contract.Caller() var dkgFinalize dkgTypes.Finalize @@ -1421,9 +1425,9 @@ func (g *GovernanceContract) addDKGFinalize(round *big.Int, finalize []byte) ([] return g.penalize() } - if !g.state.DKGFinalized(round, caller) { - g.state.PutDKGFinalized(round, caller, true) - g.state.IncDKGFinalizedsCount(round) + if !g.state.DKGFinalized(caller) { + g.state.PutDKGFinalized(caller, true) + g.state.IncDKGFinalizedsCount() } return g.useGas(100000) @@ -1688,18 +1692,22 @@ func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { } func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([]byte, error) { - round := g.state.Round() - - if nextRound.Cmp(round) <= 0 { + if nextRound.Uint64() != g.evm.Round.Uint64()+1 || + g.state.CRSRound().Uint64() == nextRound.Uint64() { return nil, errExecutionReverted } - prevCRS := g.state.CRS(round) + prevCRS := g.state.CRS() - threshold := int(g.state.DKGSetSize().Uint64()/3 + 1) + // CRS(n) = hash(CRS(n-1)) if n <= core.DKGRoundDelay + if g.evm.Round.Uint64() == dexCore.DKGDelayRound { + for i := uint64(0); i < dexCore.DKGDelayRound; i++ { + prevCRS = crypto.Keccak256Hash(prevCRS[:]) + } + } - dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey( - round, threshold) + threshold := int(g.state.DKGSetSize().Uint64()/3 + 1) + dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(nextRound, threshold) if err != nil { return nil, errExecutionReverted } @@ -1712,10 +1720,10 @@ func (g *GovernanceContract) proposeCRS(nextRound *big.Int, signedCRS []byte) ([ } // Save new CRS into state and increase round. - newCRS := crypto.Keccak256(signedCRS) - crs := common.BytesToHash(newCRS) + crs := crypto.Keccak256Hash(signedCRS) - g.state.PushCRS(crs) + g.state.SetCRS(crs) + g.state.SetCRSRound(nextRound) g.state.emitCRSProposed(nextRound, crs) // To encourage DKG set to propose the correct value, correctly submitting @@ -1811,23 +1819,24 @@ func (g *GovernanceContract) report(reportType *big.Int, arg1, arg2 []byte) ([]b } func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { - // Check if current block over 80% of current round. - round := g.state.Round() + round := g.evm.Round + nextRound := new(big.Int).Add(round, big.NewInt(1)) + resetCount := g.state.DKGResetCount(round) + // Just restart DEXON if failed at round 0. if round.Cmp(big.NewInt(0)) == 0 { return nil, errExecutionReverted } - // target = 80 + 100 * DKGResetCount + // Extend the the current round. + // target = (80 + 100 * DKGResetCount)% target := new(big.Int).Add( big.NewInt(80), new(big.Int).Mul(big.NewInt(100), resetCount)) - // Round() is increased if CRS is signed. But we want to extend round r-1 now. - curRound := new(big.Int).Sub(round, big.NewInt(1)) - roundHeight := g.state.RoundHeight(curRound) - gs, err := getConfigState(g.evm, curRound) + roundHeight := g.state.RoundHeight(round) + gs, err := getConfigState(g.evm, round) if err != nil { return nil, err } @@ -1838,6 +1847,7 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { targetBlockNum.Quo(targetBlockNum, big.NewInt(100)) targetBlockNum.Add(targetBlockNum, roundHeight) + // Check if current block over 80% of current round. blockHeight := g.evm.Context.BlockNumber if blockHeight.Cmp(targetBlockNum) < 0 { return nil, errExecutionReverted @@ -1850,35 +1860,30 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { new(big.Int).Div(g.state.DKGSetSize(), big.NewInt(3))) // If 2f + 1 of DKG set is finalized, check if DKG succeeded. - if g.state.DKGFinalizedsCount(round).Cmp(threshold) > 0 { - _, err := g.coreDKGUtils.NewGroupPublicKey( - round, int(threshold.Int64())) + if g.state.DKGFinalizedsCount().Cmp(threshold) > 0 { + _, err := g.coreDKGUtils.NewGroupPublicKey(nextRound, int(threshold.Int64())) // DKG success. if err == nil { return nil, errExecutionReverted } switch err { - case core.ErrNotReachThreshold, core.ErrInvalidThreshold: + case dexCore.ErrNotReachThreshold, dexCore.ErrInvalidThreshold: default: return nil, errExecutionReverted } } - // Clear dkg states for next round. - dkgSet := g.getDKGSet(round) - g.state.ClearDKGMasterPublicKeys(round) - g.state.ClearDKGComplaints(round) - g.state.ClearDKGMPKReady(round, dkgSet) - g.state.ResetDKGMPKReadysCount(round) - g.state.ClearDKGFinalized(round, dkgSet) - g.state.ResetDKGFinalizedsCount(round) + // Update CRS. - prevCRS := g.state.CRS(curRound) + headState, err := getRoundState(g.evm, round) + if err != nil { + return nil, errExecutionReverted + } + prevCRS := headState.CRS() for i := uint64(0); i < resetCount.Uint64()+1; i++ { prevCRS = crypto.Keccak256Hash(prevCRS[:]) } - dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey( - curRound, int(config.DKGSetSize/3+1)) + dkgGPK, err := g.coreDKGUtils.NewGroupPublicKey(round, int(config.DKGSetSize/3+1)) if err != nil { return nil, errExecutionReverted } @@ -1890,16 +1895,22 @@ func (g *GovernanceContract) resetDKG(newSignedCRS []byte) ([]byte, error) { return g.penalize() } + newRound := new(big.Int).Add(g.evm.Round, big.NewInt(1)) + + // Clear DKG states for next round. + g.clearDKG() + g.state.SetDKGRound(newRound) + // Save new CRS into state and increase round. newCRS := crypto.Keccak256(newSignedCRS) crs := common.BytesToHash(newCRS) - g.state.PopCRS() - g.state.PushCRS(crs) - g.state.emitCRSProposed(round, crs) + g.state.SetCRS(crs) + g.state.SetCRSRound(newRound) + g.state.emitCRSProposed(newRound, crs) // Increase reset count. - g.state.IncDKGResetCount(round) + g.state.IncDKGResetCount(new(big.Int).Add(round, big.NewInt(1))) g.state.emitDKGReset(round, blockHeight) return nil, nil @@ -1913,7 +1924,7 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re // Initialize contract state. g.evm = evm - g.state = GovernanceStateHelper{evm.StateDB} + g.state = GovernanceState{evm.StateDB} g.contract = contract g.coreDKGUtils.SetState(g.state) @@ -2068,11 +2079,7 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re } return res, nil case "crs": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - res, err := method.Outputs.Pack(g.state.CRS(round)) + res, err := method.Outputs.Pack(g.state.CRS()) if err != nil { return nil, errExecutionReverted } @@ -2101,12 +2108,11 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re } return res, nil case "dkgComplaints": - round, index := new(big.Int), new(big.Int) - args := []interface{}{&round, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { + index := new(big.Int) + if err := method.Inputs.Unpack(&index, arguments); err != nil { return nil, errExecutionReverted } - complaints := g.state.DKGComplaints(round) + complaints := g.state.DKGComplaints() if int(index.Uint64()) >= len(complaints) { return nil, errExecutionReverted } @@ -2117,23 +2123,18 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re } return res, nil case "dkgReadys": - round, addr := new(big.Int), common.Address{} - args := []interface{}{&round, &addr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { + addr := common.Address{} + if err := method.Inputs.Unpack(&addr, arguments); err != nil { return nil, errExecutionReverted } - ready := g.state.DKGMPKReady(round, addr) + ready := g.state.DKGMPKReady(addr) res, err := method.Outputs.Pack(ready) if err != nil { return nil, errExecutionReverted } return res, nil case "dkgReadysCount": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - count := g.state.DKGMPKReadysCount(round) + count := g.state.DKGMPKReadysCount() res, err := method.Outputs.Pack(count) if err != nil { return nil, errExecutionReverted @@ -2141,35 +2142,29 @@ func (g *GovernanceContract) Run(evm *EVM, input []byte, contract *Contract) (re return res, nil case "dkgFinalizeds": - round, addr := new(big.Int), common.Address{} - args := []interface{}{&round, &addr} - if err := method.Inputs.Unpack(&args, arguments); err != nil { + addr := common.Address{} + if err := method.Inputs.Unpack(&addr, arguments); err != nil { return nil, errExecutionReverted } - finalized := g.state.DKGFinalized(round, addr) + finalized := g.state.DKGFinalized(addr) res, err := method.Outputs.Pack(finalized) if err != nil { return nil, errExecutionReverted } return res, nil case "dkgFinalizedsCount": - round := new(big.Int) - if err := method.Inputs.Unpack(&round, arguments); err != nil { - return nil, errExecutionReverted - } - count := g.state.DKGFinalizedsCount(round) + count := g.state.DKGFinalizedsCount() res, err := method.Outputs.Pack(count) if err != nil { return nil, errExecutionReverted } return res, nil case "dkgMasterPublicKeys": - round, index := new(big.Int), new(big.Int) - args := []interface{}{&round, &index} - if err := method.Inputs.Unpack(&args, arguments); err != nil { + index := new(big.Int) + if err := method.Inputs.Unpack(&index, arguments); err != nil { return nil, errExecutionReverted } - mpks := g.state.DKGMasterPublicKeys(round) + mpks := g.state.DKGMasterPublicKeys() if int(index.Uint64()) >= len(mpks) { return nil, errExecutionReverted } @@ -2442,7 +2437,6 @@ func PackReportForkVote(vote1, vote2 *coreTypes.Vote) ([]byte, error) { if err != nil { return nil, err } - data := append(method.Id(), res...) return data, nil } @@ -2464,7 +2458,6 @@ func PackReportForkBlock(block1, block2 *coreTypes.Block) ([]byte, error) { if err != nil { return nil, err } - data := append(method.Id(), res...) return data, nil } diff --git a/core/vm/oracle_contracts_test.go b/core/vm/oracle_contracts_test.go index 4980d4b77..c96256e5d 100644 --- a/core/vm/oracle_contracts_test.go +++ b/core/vm/oracle_contracts_test.go @@ -27,6 +27,7 @@ import ( "time" coreCommon "github.com/dexon-foundation/dexon-consensus/common" + dexCore "github.com/dexon-foundation/dexon-consensus/core" coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" coreEcdsa "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" @@ -57,22 +58,22 @@ func randomBytes(minLength, maxLength int32) []byte { return b } -type GovernanceStateHelperTestSuite struct { +type GovernanceStateTestSuite struct { suite.Suite - s *GovernanceStateHelper + s *GovernanceState } -func (g *GovernanceStateHelperTestSuite) SetupTest() { +func (g *GovernanceStateTestSuite) SetupTest() { db := state.NewDatabase(ethdb.NewMemDatabase()) statedb, err := state.New(common.Hash{}, db) if err != nil { panic(err) } - g.s = &GovernanceStateHelper{statedb} + g.s = &GovernanceState{statedb} } -func (g *GovernanceStateHelperTestSuite) TestReadWriteEraseBytes() { +func (g *GovernanceStateTestSuite) TestReadWriteEraseBytes() { for i := 0; i < 100; i++ { // Short bytes. loc := big.NewInt(rand.Int63()) @@ -96,30 +97,27 @@ func (g *GovernanceStateHelperTestSuite) TestReadWriteEraseBytes() { } } -func (g *GovernanceStateHelperTestSuite) TestReadWriteErase2DArray() { - for i := 0; i < 50; i++ { - loc := big.NewInt(rand.Int63()) - for j := 0; j < 50; j++ { - idx := big.NewInt(int64(j)) - data := make([][]byte, 30) - for key := range data { - data[key] = randomBytes(3, 32) - g.s.appendTo2DByteArray(loc, idx, data[key]) - } - read := g.s.read2DByteArray(loc, idx) - g.Require().Len(read, len(data)) - for key := range data { - g.Require().Equal(0, bytes.Compare(data[key], read[key])) - } - g.s.erase2DByteArray(loc, idx) - read = g.s.read2DByteArray(loc, idx) - g.Require().Len(read, 0) +func (g *GovernanceStateTestSuite) TestReadWriteErase1DArray() { + for j := 0; j < 50; j++ { + idx := big.NewInt(int64(j)) + data := make([][]byte, 30) + for key := range data { + data[key] = randomBytes(3, 32) + g.s.appendTo1DByteArray(idx, data[key]) } + read := g.s.read1DByteArray(idx) + g.Require().Len(read, len(data)) + for key := range data { + g.Require().Equal(0, bytes.Compare(data[key], read[key])) + } + g.s.erase1DByteArray(idx) + read = g.s.read1DByteArray(idx) + g.Require().Len(read, 0) } } -func TestGovernanceStateHelper(t *testing.T) { - suite.Run(t, new(GovernanceStateHelperTestSuite)) +func TestGovernanceState(t *testing.T) { + suite.Run(t, new(GovernanceStateTestSuite)) } type OracleContractsTestSuite struct { @@ -129,7 +127,7 @@ type OracleContractsTestSuite struct { config *params.DexconConfig memDB *ethdb.MemDatabase stateDB *state.StateDB - s *GovernanceStateHelper + s *GovernanceState } func (g *OracleContractsTestSuite) SetupTest() { @@ -140,7 +138,7 @@ func (g *OracleContractsTestSuite) SetupTest() { } g.memDB = memDB g.stateDB = stateDB - g.s = &GovernanceStateHelper{stateDB} + g.s = &GovernanceState{stateDB} config := params.TestnetChainConfig.Dexcon config.LockupPeriod = 1000 @@ -156,7 +154,7 @@ func (g *OracleContractsTestSuite) SetupTest() { // Genesis CRS. crs := crypto.Keccak256Hash([]byte(config.GenesisCRSText)) - g.s.PushCRS(crs) + g.s.SetCRS(crs) // Round 0 height. g.s.PushRoundHeight(big.NewInt(0)) @@ -671,7 +669,7 @@ func (g *OracleContractsTestSuite) TestConfigurationReading() { _, addr := g.newPrefundAccount() // CRS. - input, err := GovernanceABI.ABI.Pack("crs", big.NewInt(0)) + input, err := GovernanceABI.ABI.Pack("crs") g.Require().NoError(err) res, err := g.call(GovernanceContractAddress, addr, input, big.NewInt(0)) g.Require().NoError(err) @@ -1082,7 +1080,7 @@ type testCoreMock struct { tsigReturn bool } -func (m *testCoreMock) SetState(GovernanceStateHelper) {} +func (m *testCoreMock) SetState(GovernanceState) {} func (m *testCoreMock) NewGroupPublicKey(*big.Int, int) (tsigVerifierIntf, error) { if m.newDKGGPKError != nil { @@ -1106,7 +1104,8 @@ func (g *OracleContractsTestSuite) TestResetDKG() { // Stake. amount := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e6)) - input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") + input, err := GovernanceABI.ABI.Pack("stake", pk, "Test1", + "test1@dexon.org", "Taipei, Taiwan", "https://dexon.org") g.Require().NoError(err) _, err = g.call(GovernanceContractAddress, addr, input, amount) g.Require().NoError(err) @@ -1114,10 +1113,29 @@ func (g *OracleContractsTestSuite) TestResetDKG() { g.Require().Len(g.s.QualifiedNodes(), int(g.config.DKGSetSize)) addrs := make(map[int][]common.Address) - addDKG := func(round int, final bool) { + dkgSets := make(map[int]map[coreTypes.NodeID]struct{}) + addDKG := func(round int, final, proposeCRS bool) { + if proposeCRS && uint64(round) > dexCore.DKGDelayRound { + // ProposeCRS and clear DKG state. + input, err := GovernanceABI.ABI.Pack( + "proposeCRS", big.NewInt(int64(round)), randomBytes(32, 32)) + g.Require().NoError(err) + _, err = g.call(GovernanceContractAddress, addrs[round-1][0], input, big.NewInt(0)) + g.Require().NoError(err) + + // Clear DKG states for next round. + dkgSet := dkgSets[round-1] + g.s.ClearDKGMasterPublicKeys() + g.s.ClearDKGComplaints() + g.s.ClearDKGMPKReady(dkgSet) + g.s.ResetDKGMPKReadysCount() + g.s.ClearDKGFinalized(dkgSet) + g.s.ResetDKGFinalizedsCount() + g.s.SetDKGRound(big.NewInt(int64(round))) + } + addrs[round] = []common.Address{} - r := big.NewInt(int64(round)) - target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.s.CRS(r))) + target := coreTypes.NewDKGSetTarget(coreCommon.Hash(g.s.CRS())) ns := coreTypes.NewNodeSet() for _, x := range g.s.QualifiedNodes() { @@ -1129,6 +1147,7 @@ func (g *OracleContractsTestSuite) TestResetDKG() { } dkgSet := ns.GetSubSet(int(g.s.DKGSetSize().Uint64()), target) g.Require().Len(dkgSet, int(g.config.DKGSetSize)) + dkgSets[round] = dkgSet for id := range dkgSet { offset := g.s.NodesOffsetByID(Bytes32(id.Hash)) @@ -1137,66 +1156,69 @@ func (g *OracleContractsTestSuite) TestResetDKG() { } node := g.s.Node(offset) // Prepare MPK. - g.s.PushDKGMasterPublicKey(r, randomBytes(32, 64)) + g.s.PushDKGMasterPublicKey(randomBytes(32, 64)) // Prepare Complaint. - g.s.PushDKGComplaint(r, randomBytes(32, 64)) + g.s.PushDKGComplaint(randomBytes(32, 64)) addr := node.Owner addrs[round] = append(addrs[round], addr) // Prepare MPK Ready. - g.s.PutDKGMPKReady(r, addr, true) - g.s.IncDKGMPKReadysCount(r) + g.s.PutDKGMPKReady(addr, true) + g.s.IncDKGMPKReadysCount() if final { // Prepare Finalized. - g.s.PutDKGFinalized(r, addr, true) - g.s.IncDKGFinalizedsCount(r) + g.s.PutDKGFinalized(addr, true) + g.s.IncDKGFinalizedsCount() } } dkgSetSize := len(dkgSet) - g.Require().Len(g.s.DKGMasterPublicKeys(r), dkgSetSize) - g.Require().Len(g.s.DKGComplaints(r), dkgSetSize) - g.Require().Equal(0, g.s.DKGMPKReadysCount(r).Cmp(big.NewInt(int64(dkgSetSize)))) + g.Require().Len(g.s.DKGMasterPublicKeys(), dkgSetSize) + g.Require().Len(g.s.DKGComplaints(), dkgSetSize) + g.Require().Equal(int64(dkgSetSize), g.s.DKGMPKReadysCount().Int64()) for _, addr := range addrs[round] { - g.Require().True(g.s.DKGMPKReady(r, addr)) + g.Require().True(g.s.DKGMPKReady(addr)) } + if final { - g.Require().Equal(0, g.s.DKGFinalizedsCount(r).Cmp(big.NewInt(int64(dkgSetSize)))) + g.Require().Equal(int64(dkgSetSize), g.s.DKGFinalizedsCount().Int64()) for _, addr := range addrs[round] { - g.Require().True(g.s.DKGFinalized(r, addr)) + g.Require().True(g.s.DKGFinalized(addr)) } } + } + mock := &testCoreMock{ + tsigReturn: true, + } + OracleContracts[GovernanceContractAddress].(*GovernanceContract).coreDKGUtils = mock + // Fill data for previous rounds. roundHeight := int64(g.config.RoundLength) - round := 3 + round := int(dexCore.DKGDelayRound) + 3 for i := 0; i <= round; i++ { - // Prepare CRS. - crs := common.BytesToHash(randomBytes(common.HashLength, common.HashLength)) - g.s.PushCRS(crs) + g.context.Round = big.NewInt(int64(i)) + // Prepare Round Height if i != 0 { g.s.PushRoundHeight(big.NewInt(int64(i) * roundHeight)) } - g.Require().Equal(0, g.s.LenCRS().Cmp(big.NewInt(int64(i+2)))) - g.Require().Equal(crs, g.s.CurrentCRS()) - } - for i := 0; i <= round; i++ { - addDKG(i, true) - } - mock := &testCoreMock{ - tsigReturn: true, + addDKG(i+1, true, true) } - OracleContracts[GovernanceContractAddress].(*GovernanceContract).coreDKGUtils = mock + + round++ + g.s.PushRoundHeight(big.NewInt(int64(round) * roundHeight)) + g.context.Round = big.NewInt(int64(round)) + addDKG(round+1, false, true) repeat := 3 for r := 0; r < repeat; r++ { - addDKG(round+1, false) // Add one finalized for test. roundPlusOne := big.NewInt(int64(round + 1)) - g.s.PutDKGFinalized(roundPlusOne, addrs[round+1][0], true) - g.s.IncDKGFinalizedsCount(roundPlusOne) + g.s.PutDKGFinalized(addrs[round+1][0], true) + g.s.IncDKGFinalizedsCount() - g.context.BlockNumber = big.NewInt(roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*80/100) + g.context.BlockNumber = big.NewInt( + roundHeight*int64(round) + roundHeight*int64(r) + roundHeight*80/100) _, addr := g.newPrefundAccount() newCRS := randomBytes(common.HashLength, common.HashLength) input, err := GovernanceABI.ABI.Pack("resetDKG", newCRS) @@ -1206,29 +1228,26 @@ func (g *OracleContractsTestSuite) TestResetDKG() { // Test if CRS is reset. newCRSHash := crypto.Keccak256Hash(newCRS) - g.Require().Equal(0, g.s.LenCRS().Cmp(big.NewInt(int64(round+2)))) - g.Require().Equal(newCRSHash, g.s.CurrentCRS()) - g.Require().Equal(newCRSHash, g.s.CRS(big.NewInt(int64(round+1)))) + g.Require().Equal(newCRSHash, g.s.CRS()) // Test if MPK is purged. - g.Require().Len(g.s.DKGMasterPublicKeys(big.NewInt(int64(round+1))), 0) + g.Require().Len(g.s.DKGMasterPublicKeys(), 0) // Test if MPKReady is purged. - g.Require().Equal(0, - g.s.DKGMPKReadysCount(big.NewInt(int64(round+1))).Cmp(big.NewInt(0))) + g.Require().Equal(int64(0), g.s.DKGMPKReadysCount().Int64()) for _, addr := range addrs[round+1] { - g.Require().False(g.s.DKGMPKReady(big.NewInt(int64(round+1)), addr)) + g.Require().False(g.s.DKGMPKReady(addr)) } // Test if Complaint is purged. - g.Require().Len(g.s.DKGComplaints(big.NewInt(int64(round+1))), 0) + g.Require().Len(g.s.DKGComplaints(), 0) // Test if Finalized is purged. - g.Require().Equal(0, - g.s.DKGFinalizedsCount(big.NewInt(int64(round+1))).Cmp(big.NewInt(0))) + g.Require().Equal(int64(0), g.s.DKGFinalizedsCount().Int64()) for _, addr := range addrs[round+1] { - g.Require().False(g.s.DKGFinalized(big.NewInt(int64(round+1)), addr)) + g.Require().False(g.s.DKGFinalized(addr)) } - g.Require().Equal(0, - g.s.DKGResetCount(roundPlusOne).Cmp(big.NewInt(int64(r+1)))) + g.Require().Equal(int64(r+1), g.s.DKGResetCount(roundPlusOne).Int64()) + + addDKG(round+1, false, false) } } diff --git a/dex/downloader/downloader.go b/dex/downloader/downloader.go index e15844668..3d3a78e18 100644 --- a/dex/downloader/downloader.go +++ b/dex/downloader/downloader.go @@ -496,17 +496,6 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, number ui } d.verifierCache = dexCore.NewTSigVerifierCache(d.gov, 5) - - // warm up verifierCache - if originHeader.Round > 0 { - ok, err := d.verifierCache.Update(originHeader.Round - 1) - if err != nil { - return err - } - if !ok { - return fmt.Errorf("can not update verifier cache") - } - } } // Initiate the sync using a concurrent header and content retrieval algorithm diff --git a/dex/downloader/testchain_test.go b/dex/downloader/testchain_test.go index 73d4863a5..722159bc0 100644 --- a/dex/downloader/testchain_test.go +++ b/dex/downloader/testchain_test.go @@ -21,6 +21,9 @@ import ( "fmt" "math/big" + dexCore "github.com/dexon-foundation/dexon-consensus/core" + coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" + "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/consensus/dexcon" "github.com/dexon-foundation/dexon/core" @@ -66,23 +69,23 @@ func genesisBlockForTesting(db ethdb.Database, Staked: new(big.Int), }, nodeaddr1: { - Balance: new(big.Int).Mul(big.NewInt(1000), ether), - Staked: new(big.Int).Mul(big.NewInt(500), ether), + Balance: new(big.Int).Mul(big.NewInt(2e6), ether), + Staked: new(big.Int).Mul(big.NewInt(1e6), ether), PublicKey: crypto.FromECDSAPub(&nodekey1.PublicKey), }, nodeaddr2: { - Balance: new(big.Int).Mul(big.NewInt(1000), ether), - Staked: new(big.Int).Mul(big.NewInt(500), ether), + Balance: new(big.Int).Mul(big.NewInt(2e6), ether), + Staked: new(big.Int).Mul(big.NewInt(1e6), ether), PublicKey: crypto.FromECDSAPub(&nodekey2.PublicKey), }, nodeaddr3: { - Balance: new(big.Int).Mul(big.NewInt(1000), ether), - Staked: new(big.Int).Mul(big.NewInt(500), ether), + Balance: new(big.Int).Mul(big.NewInt(2e6), ether), + Staked: new(big.Int).Mul(big.NewInt(1e6), ether), PublicKey: crypto.FromECDSAPub(&nodekey3.PublicKey), }, nodeaddr4: { - Balance: new(big.Int).Mul(big.NewInt(1000), ether), - Staked: new(big.Int).Mul(big.NewInt(500), ether), + Balance: new(big.Int).Mul(big.NewInt(2e6), ether), + Staked: new(big.Int).Mul(big.NewInt(1e6), ether), PublicKey: crypto.FromECDSAPub(&nodekey4.PublicKey), }, }, @@ -166,50 +169,23 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, nodes *dexc blocks, receipts := core.GenerateDexonChain(params.TestnetChainConfig, parent, engine, testDB, n, func(i int, block *core.DexonBlockGen) { block.SetCoinbase(common.Address{seed}) - if round == 0 { - switch i { - case 1: - testNodes.RunDKG(round, 2) - // Add DKG MasterPublicKeys - for _, node := range testNodes.Nodes(round) { - data, err := vm.PackAddDKGMasterPublicKey(round, node.MasterPublicKey(round)) - if err != nil { - panic(err) - } - addTx(block, node, data) - } - case 2: - // Add DKG MPKReady - for _, node := range testNodes.Nodes(round) { - data, err := vm.PackAddDKGMPKReady(round, node.DKGMPKReady(round)) - if err != nil { - panic(err) - } - addTx(block, node, data) - } - case 3: - // Add DKG Finalize - for _, node := range testNodes.Nodes(round) { - data, err := vm.PackAddDKGFinalize(round, node.DKGFinalize(round)) - if err != nil { - panic(err) - } - addTx(block, node, data) - } - } - } - + block.SetPosition(coreTypes.Position{ + Round: round, + Height: uint64(i), + }) half := roundInterval / 2 switch i % roundInterval { case half: - // Sign current CRS to geneate the next round CRS and propose it. - testNodes.SignCRS(round) - node := testNodes.Nodes(round)[0] - data, err := vm.PackProposeCRS(round, testNodes.SignedCRS(round+1)) - if err != nil { - panic(err) + if round >= dexCore.DKGDelayRound { + // Sign current CRS to geneate the next round CRS and propose it. + testNodes.SignCRS(round) + node := testNodes.Nodes(round)[0] + data, err := vm.PackProposeCRS(round, testNodes.SignedCRS(round+1)) + if err != nil { + panic(err) + } + addTx(block, node, data) } - addTx(block, node, data) case half + 1: // Run the DKG for next round. testNodes.RunDKG(round+1, 2) @@ -356,13 +332,13 @@ func (g *govStateFetcher) SnapshotRound(round uint64, root common.Hash) { g.rootByRound[round] = root } -func (g *govStateFetcher) GetGovStateHelperAtRound(round uint64) *vm.GovernanceStateHelper { +func (g *govStateFetcher) GetStateForConfigAtRound(round uint64) *vm.GovernanceState { if root, ok := g.rootByRound[round]; ok { s, err := state.New(root, g.db) if err != nil { panic(err) } - return &vm.GovernanceStateHelper{s} + return &vm.GovernanceState{s} } return nil } diff --git a/dex/governance.go b/dex/governance.go index 56d08975e..d9cf8fb65 100644 --- a/dex/governance.go +++ b/dex/governance.go @@ -67,7 +67,7 @@ func NewDexconGovernance(backend *DexAPIBackend, chainConfig *params.ChainConfig // DexconConfiguration return raw config in state. func (d *DexconGovernance) DexconConfiguration(round uint64) *params.DexconConfig { - return d.GetGovStateHelperAtRound(round).Configuration() + return d.GetStateForConfigAtRound(round).Configuration() } func (d *DexconGovernance) sendGovTx(ctx context.Context, data []byte) error { @@ -107,13 +107,32 @@ func (d *DexconGovernance) sendGovTx(ctx context.Context, data []byte) error { // CRS returns the CRS for a given round. func (d *DexconGovernance) CRS(round uint64) coreCommon.Hash { - s := d.GetHeadHelper() - return coreCommon.Hash(s.CRS(big.NewInt(int64(round)))) + if round <= dexCore.DKGDelayRound { + s := d.GetStateAtRound(0) + crs := s.CRS() + for i := uint64(0); i < round; i++ { + crs = crypto.Keccak256Hash(crs[:]) + } + return coreCommon.Hash(crs) + } + if round > d.CRSRound() { + return coreCommon.Hash{} + } + var s *vm.GovernanceState + if round == d.CRSRound() { + s = d.GetHeadState() + } else { + s = d.GetStateAtRound(round) + } + return coreCommon.Hash(s.CRS()) +} + +func (d *DexconGovernance) Round() uint64 { + return d.b.CurrentBlock().Round() } -func (d *DexconGovernance) LenCRS() uint64 { - s := d.GetHeadHelper() - return s.LenCRS().Uint64() +func (d *DexconGovernance) CRSRound() uint64 { + return d.GetHeadState().CRSRound().Uint64() } // ProposeCRS send proposals of a new CRS @@ -132,7 +151,7 @@ func (d *DexconGovernance) ProposeCRS(round uint64, signedCRS []byte) { // NodeSet returns the current node set. func (d *DexconGovernance) NodeSet(round uint64) []coreCrypto.PublicKey { - s := d.GetGovStateHelperAtRound(round) + s := d.GetStateForConfigAtRound(round) var pks []coreCrypto.PublicKey for _, n := range s.QualifiedNodes() { diff --git a/dex/handler.go b/dex/handler.go index 4ffa01244..5bd615c86 100644 --- a/dex/handler.go +++ b/dex/handler.go @@ -45,6 +45,7 @@ import ( "time" coreCommon "github.com/dexon-foundation/dexon-consensus/common" + dexCore "github.com/dexon-foundation/dexon-consensus/core" coreCrypto "github.com/dexon-foundation/dexon-consensus/core/crypto" coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" dkgTypes "github.com/dexon-foundation/dexon-consensus/core/types/dkg" @@ -1199,13 +1200,18 @@ func (pm *ProtocolManager) recordBroadcastLoop() { // a loop keep building and maintaining peers in notary set. // TODO: finish this func (pm *ProtocolManager) peerSetLoop() { - log.Debug("start peer set loop") - round := pm.gov.LenCRS() - 1 - log.Trace("first len crs", "len", round+1, "round", round) - if round >= 1 { - pm.peers.BuildConnection(round - 1) + log.Debug("ProtocolManager: started peer set loop") + + round := pm.gov.Round() + log.Trace("ProtocolManager: startup round", "round", round) + + if round < dexCore.DKGDelayRound { + for i := round; i <= dexCore.DKGDelayRound; i++ { + pm.peers.BuildConnection(i) + } + } else { + pm.peers.BuildConnection(round) } - pm.peers.BuildConnection(round) for { select { @@ -1216,11 +1222,16 @@ func (pm *ProtocolManager) peerSetLoop() { break } - newRound := pm.gov.LenCRS() - 1 - log.Trace("new round", "round", newRound) + newRound := pm.gov.CRSRound() + if newRound == 0 { + break + } + + log.Debug("ProtocolManager: new round", "round", newRound) if newRound == round { break } + if newRound == round+1 { pm.peers.BuildConnection(newRound) if round >= 1 { diff --git a/dex/helper_test.go b/dex/helper_test.go index 3f901e6ec..c8bf62a6b 100644 --- a/dex/helper_test.go +++ b/dex/helper_test.go @@ -215,7 +215,11 @@ type testGovernance struct { dkgSetFunc func(uint64) (map[string]struct{}, error) } -func (g *testGovernance) LenCRS() uint64 { +func (g *testGovernance) Round() uint64 { + return g.lenCRSFunc() +} + +func (g *testGovernance) CRSRound() uint64 { return g.lenCRSFunc() } diff --git a/dex/protocol.go b/dex/protocol.go index 0e3f50eba..d72e95478 100644 --- a/dex/protocol.go +++ b/dex/protocol.go @@ -152,7 +152,9 @@ type txPool interface { type governance interface { GetRoundHeight(uint64) uint64 - LenCRS() uint64 + Round() uint64 + + CRSRound() uint64 NotarySet(uint64) (map[string]struct{}, error) diff --git a/params/config.go b/params/config.go index 33b9a5ec2..b31427545 100644 --- a/params/config.go +++ b/params/config.go @@ -26,9 +26,9 @@ import ( // Genesis hashes to enforce below configs on. var ( - MainnetGenesisHash = common.HexToHash("0xf80aae99a7c44bc54d7b0cc8a16645fa3ea65c01b180339f17b31a698b031271") - TestnetGenesisHash = common.HexToHash("0x7f704c8d0a773d0fcca231d40bf39495553886bf8800b4a06920786a802103e1") - YilanGenesisHash = common.HexToHash("0x394f057bc19b7762eaccd7e250afa213e9b0e60d1204a234fd11ed03eabfb90e") + MainnetGenesisHash = common.HexToHash("0x605d2850786a493b48c428dc447785c73912cf649d792196532412561058e390") + TestnetGenesisHash = common.HexToHash("0x376d2e79e046907c8947df0985d43574dbfd23bd82c4bc3e85fc5f0d0599590a") + YilanGenesisHash = common.HexToHash("0xd9b4eb0bfd7bbc8193ed5afd11adf9b9b34f09df7b1e0a0f17f580242e22bf76") ) // TrustedCheckpoints associates each known checkpoint with the genesis hash of |