diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index 846c27fed57d..047f34deac75 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -16,10 +16,13 @@ package validator import ( + "bytes" "context" "encoding/json" + "fmt" "math/big" "math/rand" + "reflect" "testing" "time" @@ -28,9 +31,12 @@ import ( "github.com/XinFinOrg/XDPoSChain/common" contractValidator "github.com/XinFinOrg/XDPoSChain/contracts/validator/contract" "github.com/XinFinOrg/XDPoSChain/core" + "github.com/XinFinOrg/XDPoSChain/core/state" + "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/params" + "github.com/XinFinOrg/XDPoSChain/rlp" ) var ( @@ -250,3 +256,127 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.XDCValidator, signe return owner } +func toyVoteTx(t *testing.T, nonce uint64, amount *big.Int, to, addr common.Address) *types.Transaction { + vote := "6dd7d8ea" // VoteMethod = "0x6dd7d8ea" + action := fmt.Sprintf("%s%s%s", vote, "000000000000000000000000", addr.String()[3:]) + data := common.Hex2Bytes(action) + gasPrice := big.NewInt(0) + tx := types.NewTransaction(nonce, to, amount, 5000000, gasPrice, data) + signedTX, err := types.SignTx(tx, types.FrontierSigner{}, acc4Key) + if err != nil { + t.Fatalf("cannot sign vote tx") + } + return signedTX +} +func TestStatedbUtils(t *testing.T) { + validatorCap := new(big.Int) + validatorCap.SetString("50000000000000000000000", 10) + voteAmount := new(big.Int) + voteAmount.SetString("25000000000000000000000", 10) + genesisAlloc := core.GenesisAlloc{ + addr: {Balance: big.NewInt(1000000000)}, + acc1Addr: {Balance: validatorCap}, + acc2Addr: {Balance: validatorCap}, + acc4Addr: {Balance: validatorCap}, + } + contractBackend := backends.NewXDCSimulatedBackend(genesisAlloc, 10000000, params.TestXDPoSMockChainConfig) + transactOpts := bind.NewKeyedTransactor(key) + + validatorAddress, _, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr, acc3Addr}, []*big.Int{validatorCap, validatorCap}, addr) + if err != nil { + t.Fatalf("can't deploy root registry: %v", err) + } + contractBackend.Commit() + //add an extra voter + voteTx := toyVoteTx(t, 0, voteAmount, validatorAddress, acc3Addr) + err = contractBackend.SendTransaction(context.TODO(), voteTx) + if err != nil { + t.Fatalf("can't send tx: %v", err) + } + contractBackend.Commit() + d := time.Now().Add(1000 * time.Millisecond) + ctx, cancel := context.WithDeadline(context.Background(), d) + defer cancel() + code, _ := contractBackend.CodeAt(ctx, validatorAddress, nil) + storage := make(map[common.Hash]common.Hash) + f := func(key, val common.Hash) bool { + decode := []byte{} + trim := bytes.TrimLeft(val.Bytes(), "\x00") + rlp.DecodeBytes(trim, &decode) + storage[key] = common.BytesToHash(decode) + // t.Log("DecodeBytes", "value", val.String(), "decode", storage[key].String()) + // t.Log("key", key.String(), "value", storage[key].String()) + return true + } + contractBackend.ForEachStorageAt(ctx, validatorAddress, nil, f) + genesisAlloc[common.HexToAddress(common.MasternodeVotingSMC)] = core.GenesisAccount{ + Balance: validatorCap, + Code: code, + Storage: storage, + } + contractBackendForValidator := backends.NewXDCSimulatedBackend(genesisAlloc, 10000000, params.TestXDPoSMockChainConfig) + validator, err := NewValidator(transactOpts, common.HexToAddress(common.MasternodeVotingSMC), contractBackendForValidator) + if err != nil { + t.Fatalf("can't get validator object: %v", err) + } + statedb, err := contractBackendForValidator.GetBlockChain().State() + if err != nil { + t.Fatalf("can't get statedb: %v", err) + } + candidates, err := validator.GetCandidates() + if err != nil { + t.Fatalf("can't get candidates: %v", err) + } + candidates_statedb := state.GetCandidates(statedb) + if !reflect.DeepEqual(candidates, candidates_statedb) { + t.Fatalf("candidates not equal, statedb utils is wrong,\nbind calling result\n%v\nstatedb result\n%v", candidates, candidates_statedb) + } + if len(candidates) == 0 { + t.Fatalf("candidates empty, smart contract init is wrong") + } + for _, it := range candidates { + cap, err := validator.GetCandidateCap(it) + if err != nil { + t.Fatalf("can't get candidate cap: %v", err) + } + cap_statedb := state.GetCandidateCap(statedb, it) + if cap.Cmp(cap_statedb) != 0 { + t.Fatalf("cap not equal, statedb utils is wrong") + } + if cap.Cmp(big.NewInt(0)) == 0 { + t.Fatalf("cap should not be zero") + } + owner, err := validator.GetCandidateOwner(it) + if err != nil { + t.Fatalf("can't get candidate owner: %v", err) + } + owner_statedb := state.GetCandidateOwner(statedb, it) + if !reflect.DeepEqual(owner, owner_statedb) { + t.Fatalf("owner not equal, statedb utils is wrong") + } + } + voters, err := validator.GetVoters(acc3Addr) + if err != nil { + t.Fatalf("can't get voters: %v", err) + } + voters_statedb := state.GetVoters(statedb, acc3Addr) + if !reflect.DeepEqual(voters, voters_statedb) { + t.Fatalf("voters not equal, statedb utils is wrong,\nbind calling result\n%v\nstatedb result\n%v", voters, voters_statedb) + } + if len(voters) == 0 { + t.Fatalf("voters empty, smart contract call Vote() is wrong") + } + for _, it := range voters { + cap, err := validator.GetVoterCap(acc3Addr, it) + if err != nil { + t.Fatalf("can't get voter cap: %v", err) + } + cap_statedb := state.GetVoterCap(statedb, acc3Addr, it) + if cap.Cmp(cap_statedb) != 0 { + t.Fatalf("cap not equal, statedb utils is wrong") + } + if cap.Cmp(big.NewInt(0)) == 0 { + t.Fatalf("cap should not be zero") + } + } +} \ No newline at end of file diff --git a/core/state/statedb_utils.go b/core/state/statedb_utils.go index 6b05bd3197dc..694bcdd12771 100644 --- a/core/state/statedb_utils.go +++ b/core/state/statedb_utils.go @@ -66,18 +66,20 @@ func GetOpening(statedb *StateDB, address common.Address) [32]byte { return ret } +// The smart contract and the compiled byte code (in corresponding *.go file) is at commit "KYC Layer added." 7f856ffe672162dfa9c4006c89afb45a24fb7f9f +// Notice that if smart contract and the compiled byte code (in corresponding *.go file) changes, below also changes var ( slotValidatorMapping = map[string]uint64{ "withdrawsState": 0, "validatorsState": 1, "voters": 2, - "candidates": 3, - "candidateCount": 4, - "minCandidateCap": 5, - "minVoterCap": 6, - "maxValidatorNumber": 7, - "candidateWithdrawDelay": 8, - "voterWithdrawDelay": 9, + "candidates": 8, + "candidateCount": 9, + "minCandidateCap": 11, + "minVoterCap": 12, + "maxValidatorNumber": 13, + "candidateWithdrawDelay": 14, + "voterWithdrawDelay": 15, } )