diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index fbeecee31a..d1bff61b65 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1256,6 +1256,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, }) } + Fatalf("Only support posv consensus") } if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 2dccf1cd37..153c026b26 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -778,7 +778,7 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error } header.Extra = header.Extra[:extraVanity] masternodes := snap.GetSigners() - if number > 0 && number%c.config.Epoch == 0 { + if number >= c.config.Epoch && number%c.config.Epoch == 0 { if c.HookPenalty != nil { penMasternodes, err := c.HookPenalty(chain, number) if err != nil { diff --git a/contracts/blockSignerReader.go b/contracts/blockSignerReader.go new file mode 100644 index 0000000000..46b72e889a --- /dev/null +++ b/contracts/blockSignerReader.go @@ -0,0 +1,33 @@ +package contracts + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" +) + +var ( + slotBlockSignerMapping = map[string]uint64{ + "blockSigners": 0, + "blocks": 1, + } +) + +func GetSigners(statedb *state.StateDB, block *types.Block) []common.Address { + slot := slotBlockSignerMapping["blockSigners"] + keys := []common.Hash{} + keyArrSlot := getLocMappingAtKey(block.Hash(), slot) + arrSlot := statedb.GetState(common.HexToAddress(common.BlockSigners), common.BigToHash(keyArrSlot)) + arrLength := arrSlot.Big().Uint64() + for i := uint64(0); i < arrLength; i++ { + key := getLocDynamicArrAtElement(common.BigToHash(keyArrSlot), i, 1) + keys = append(keys, key) + } + rets := []common.Address{} + for _, key := range keys { + ret := statedb.GetState(common.HexToAddress(common.BlockSigners), key) + rets = append(rets, common.HexToAddress(ret.Hex())) + } + + return rets +} diff --git a/contracts/randomizeReader.go b/contracts/randomizeReader.go new file mode 100644 index 0000000000..173e82afbb --- /dev/null +++ b/contracts/randomizeReader.go @@ -0,0 +1,37 @@ +package contracts + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" +) + +var ( + slotRandomizeMapping = map[string]uint64{ + "randomSecret": 0, + "randomOpening": 1, + } +) + +func GetSecret(statedb *state.StateDB, address common.Address) [][32]byte { + slot := slotRandomizeMapping["randomSecret"] + locSecret := getLocMappingAtKey(address.Hash(), slot) + arrLength := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locSecret)) + keys := []common.Hash{} + for i := uint64(0); i < arrLength.Big().Uint64(); i++ { + key := getLocDynamicArrAtElement(common.BigToHash(locSecret), i, 1) + keys = append(keys, key) + } + rets := [][32]byte{} + for _, key := range keys { + ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), key) + rets = append(rets, ret) + } + return rets +} + +func GetOpening(statedb *state.StateDB, address common.Address) [32]byte { + slot := slotRandomizeMapping["randomOpening"] + locOpening := getLocMappingAtKey(address.Hash(), slot) + ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locOpening)) + return ret +} diff --git a/contracts/smcUtils.go b/contracts/smcUtils.go new file mode 100644 index 0000000000..8c71c78164 --- /dev/null +++ b/contracts/smcUtils.go @@ -0,0 +1,34 @@ +package contracts + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +func getLocSimpleVariable(slot uint64) common.Hash { + slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) + return slotHash +} + +func getLocMappingAtKey(key common.Hash, slot uint64) *big.Int { + slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) + retByte := crypto.Keccak256(key.Bytes(), slotHash.Bytes()) + ret := new(big.Int) + ret.SetBytes(retByte) + return ret +} + +func getLocDynamicArrAtElement(slotHash common.Hash, index uint64, elementSize uint64) common.Hash { + slotKecBig := crypto.Keccak256Hash(slotHash.Bytes()).Big() + //arrBig = slotKecBig + index * elementSize + arrBig := slotKecBig.Add(slotKecBig, new(big.Int).SetUint64(index*elementSize)) + return common.BigToHash(arrBig) +} + +func getLocFixedArrAtElement(slot uint64, index uint64, elementSize uint64) common.Hash { + slotBig := new(big.Int).SetUint64(slot) + arrBig := slotBig.Add(slotBig, new(big.Int).SetUint64(index*elementSize)) + return common.BigToHash(arrBig) +} diff --git a/contracts/test.go b/contracts/test.go new file mode 100644 index 0000000000..a71056455e --- /dev/null +++ b/contracts/test.go @@ -0,0 +1,281 @@ +package contracts +// +//import ( +// "fmt" +// "math/big" +// "time" +// +// "github.com/ethereum/go-ethereum/common" +// "github.com/ethereum/go-ethereum/core" +// "github.com/ethereum/go-ethereum/core/state" +// "github.com/ethereum/go-ethereum/crypto" +// "github.com/ethereum/go-ethereum/ethdb" +// "github.com/ethereum/go-ethereum/core/types" +//) +// +//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, +// } +// slotBlockSignerMapping = map[string]uint64{ +// "blockSigners": 0, +// "blocks": 1, +// } +// slotRandomizeMapping = map[string]uint64{ +// "randomSecret": 0, +// "randomOpening": 1, +// } +// datadir = "/mnt/sgp1_tuna_chaindata3/data/tomo/chaindata" +// candidate = "0xd6fa3e7a89bf8c84f0ccd204a15c0d259daf2091" +//) +// +//func main() { +// //Init +// chaindb, err := ethdb.NewLDBDatabase(datadir, 0, 0) +// if err != nil || chaindb == nil { +// fmt.Printf("Can't get chaindb: %v", err) +// return +// } +// headHash := core.GetHeadBlockHash(chaindb) +// blockNumber := core.GetBlockNumber(chaindb, headHash) +// block := core.GetBlock(chaindb, headHash, blockNumber) +// if block == nil { +// fmt.Println("Can't get head block") +// return +// } +// database := state.NewDatabase(chaindb) +// headerRootHash := block.Header().Root +// headHeaderHash := core.GetHeadHeaderHash(chaindb) +// statedb, _ := state.New(headHeaderHash, database) +// if statedb == nil { +// headHeaderHash = headerRootHash +// } +// candidateAddress := common.HexToAddress(candidate) +// fmt.Printf("Block head :%d, header root:%v\n", blockNumber, headerRootHash.Hex()) +// statedb, _ = state.New(headHeaderHash, database) +// if statedb == nil { +// fmt.Println("Can't get state db") +// return +// } +// +// //GetCandidates +// _ = GetCandidates(statedb) +// +// //GetCandidateOwner +// _ = GetCandidateOwner(statedb, candidateAddress) +// +// //GetCandidateCap +// _ = GetCandidateCap(statedb, candidateAddress) +// +// //GetVoters +// voters := GetVoters(statedb, candidateAddress) +// +// start := time.Now() +// fmt.Printf("--------GetVoterCap---------\n") +// for _, voter := range voters { +// //GetVoterCap +// _ = GetVoterCap(statedb, candidateAddress, voter) +// } +// elapsed := time.Since(start) +// fmt.Printf("Execution time: %s\n", elapsed) +// +// //GetSigners +// blockInput := core.GetBlock(chaindb, common.HexToHash("0x632f2403ea19697082d794900275632eb3373f7a9943b1407461995bbbc2816a"), uint64(1800)) +// _ = GetSigners(statedb, blockInput) +// +// //GetOpening +// _ = GetOpening(statedb, candidateAddress) +// //GetSecret +// _ = GetSecret(statedb, candidateAddress) +//} +// +//func GetCandidates(statedb *state.StateDB) []common.Address { +// start := time.Now() +// fmt.Printf("--------GetCandidates---------\n") +// +// slot := slotValidatorMapping["candidates"] +// slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) +// arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), slotHash) +// fmt.Printf("Candidates length: %v\n", arrLength.Hex()) +// keys := []common.Hash{} +// for i := uint64(0); i < arrLength.Big().Uint64(); i++ { +// key := getLocDynamicArrAtElement(slotHash, i, 1) +// keys = append(keys, key) +// } +// rets := []common.Address{} +// for _, key := range keys { +// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key) +// rets = append(rets, common.HexToAddress(ret.Hex())) +// fmt.Printf("%v\n", common.HexToAddress(ret.Hex()).Hex()) +// } +// elapsed := time.Since(start) +// fmt.Printf("Execution time: %s\n", elapsed) +// return rets +//} +// +//func GetCandidateOwner(statedb *state.StateDB, candidate common.Address) common.Address { +// start := time.Now() +// fmt.Printf("--------GetCandidateOwner---------\n") +// +// slot := slotValidatorMapping["validatorsState"] +// // validatorsState[_candidate].owner; +// locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot) +// locCandidateOwner := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(0))) +// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateOwner)) +// fmt.Printf("ret: %v\n", common.HexToAddress(ret.Hex()).Hex()) +// +// elapsed := time.Since(start) +// fmt.Printf("Execution time: %s\n", elapsed) +// return common.HexToAddress(ret.Hex()) +//} +// +//func GetCandidateCap(statedb *state.StateDB, candidate common.Address) string { +// start := time.Now() +// fmt.Printf("--------GetCandidateCap---------\n") +// +// slot := slotValidatorMapping["validatorsState"] +// // validatorsState[_candidate].cap; +// locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot) +// locCandidateCap := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(1))) +// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateCap)) +// fmt.Printf("cap: %v\n", ret.Big().String()) +// +// elapsed := time.Since(start) +// fmt.Printf("Execution time: %s\n", elapsed) +// return ret.Hex() +//} +// +//func GetVoterCap(state *state.StateDB, candidate, voter common.Address) *big.Int { +// //validatorsState[_candidate].voters[_voter] +// slot := slotValidatorMapping["validatorsState"] +// locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot) +// locCandidateVoters := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(2))) +// retByte := crypto.Keccak256(voter.Hash().Bytes(), common.BigToHash(locCandidateVoters).Bytes()) +// ret := state.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BytesToHash(retByte)) +// fmt.Printf("voter: %v - cap: %v\n", voter.Hex(), ret.Big().String()) +// return ret.Big() +//} +// +//func GetVoters(statedb *state.StateDB, candidate common.Address) []common.Address { +// start := time.Now() +// fmt.Printf("--------GetVoters---------\n") +// +// //mapping(address => address[]) voters; +// slot := slotValidatorMapping["voters"] +// locVoters := getLocMappingAtKey(candidate.Hash(), slot) +// arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locVoters)) +// fmt.Printf("Voters length: %v\n", arrLength.Hex()) +// keys := []common.Hash{} +// for i := uint64(0); i < arrLength.Big().Uint64(); i++ { +// key := getLocDynamicArrAtElement(common.BigToHash(locVoters), i, 1) +// keys = append(keys, key) +// } +// rets := []common.Address{} +// for _, key := range keys { +// ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key) +// rets = append(rets, common.HexToAddress(ret.Hex())) +// fmt.Printf("%v\n", common.HexToAddress(ret.Hex()).Hex()) +// } +// +// elapsed := time.Since(start) +// fmt.Printf("Execution time: %s\n", elapsed) +// return rets +//} +// +//func GetSigners(statedb *state.StateDB, block *types.Block) []common.Address { +// methodName := "getSigners" +// fmt.Printf("---%s---\n", methodName) +// start := time.Now() +// slot := slotBlockSignerMapping["blockSigners"] +// keys := []common.Hash{} +// keyArrSlot := getLocMappingAtKey(block.Hash(), slot) +// arrSlot := statedb.GetState(common.HexToAddress(common.BlockSigners), common.BigToHash(keyArrSlot)) +// arrLength := arrSlot.Big().Uint64() +// for i := uint64(0); i < arrLength; i++ { +// key := getLocDynamicArrAtElement(common.BigToHash(keyArrSlot), i, 1) +// keys = append(keys, key) +// } +// rets := []common.Address{} +// for _, key := range keys { +// ret := statedb.GetState(common.HexToAddress(common.BlockSigners), key) +// rets = append(rets, common.HexToAddress(ret.Hex())) +// fmt.Printf("%v\n", common.HexToAddress(ret.Hex()).Hex()) +// } +// +// elapsed := time.Since(start) +// fmt.Printf("Execution time: %s\n", elapsed) +// return rets +//} +// +//func GetSecret(statedb *state.StateDB, address common.Address) [][32]byte { +// start := time.Now() +// fmt.Printf("--------GetSecret---------\n") +// +// slot := slotRandomizeMapping["randomSecret"] +// locSecret := getLocMappingAtKey(address.Hash(), slot) +// arrLength := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locSecret)) +// fmt.Printf("Secret length: %v\n", arrLength.Hex()) +// keys := []common.Hash{} +// for i := uint64(0); i < arrLength.Big().Uint64(); i++ { +// key := getLocDynamicArrAtElement(common.BigToHash(locSecret), i, 1) +// keys = append(keys, key) +// } +// rets := [][32]byte{} +// for _, key := range keys { +// ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), key) +// rets = append(rets, ret) +// fmt.Printf("ret hex: %v - ret byte: %v\n", ret.Hex(), ret.Bytes()) +// } +// elapsed := time.Since(start) +// +// fmt.Printf("Execution time: %s\n", elapsed) +// return rets +//} +// +//func GetOpening(statedb *state.StateDB, address common.Address) [32]byte { +// start := time.Now() +// fmt.Printf("--------GetOpening---------\n") +// +// slot := slotRandomizeMapping["randomOpening"] +// locOpening := getLocMappingAtKey(address.Hash(), slot) +// ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locOpening)) +// fmt.Printf("ret hex: %v - ret byte: %v\n", ret.Hex(), ret.Bytes()) +// elapsed := time.Since(start) +// fmt.Printf("Execution time: %s\n", elapsed) +// return ret +//} +// +// +////////////////////////////////////// +///////////// Common lib ///////////// +////////////////////////////////////// +// +//func getLocMappingAtKey(key common.Hash, slot uint64) *big.Int { +// slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) +// retByte := crypto.Keccak256(key.Bytes(), slotHash.Bytes()) +// ret := new(big.Int) +// ret.SetBytes(retByte) +// return ret +//} +// +//func getLocDynamicArrAtElement(slotHash common.Hash, index uint64, elementSize uint64) common.Hash { +// slotKecBig := crypto.Keccak256Hash(slotHash.Bytes()).Big() +// //arrBig = slotKecBig + index * elementSize +// arrBig := slotKecBig.Add(slotKecBig, new(big.Int).SetUint64(index*elementSize)) +// return common.BigToHash(arrBig) +//} +// +//func getLocFixedArrAtElement(slot uint64, index uint64, elementSize uint64) common.Hash { +// slotBig := new(big.Int).SetUint64(slot) +// arrBig := slotBig.Add(slotBig, new(big.Int).SetUint64(index*elementSize)) +// return common.BigToHash(arrBig) +//} diff --git a/contracts/utils.go b/contracts/utils.go index d48207e200..fed5a519c0 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -31,20 +31,19 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/posv" - "github.com/ethereum/go-ethereum/contracts/blocksigner/contract" - randomizeContract "github.com/ethereum/go-ethereum/contracts/randomize/contract" - contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/contracts/blocksigner/contract" + randomizeContract "github.com/ethereum/go-ethereum/contracts/randomize/contract" ) const ( @@ -199,7 +198,12 @@ func BuildTxOpeningRandomize(nonce uint64, randomizeAddr common.Address, randomi } // Get signers signed for blockNumber from blockSigner contract. -func GetSignersFromContract(addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) { +func GetSignersFromContract(state *state.StateDB, block *types.Block) ([]common.Address, error) { + return GetSigners(state, block), nil +} + +// Get signers signed for blockNumber from blockSigner contract. +func GetSignersFromContract1(addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) { blockSigner, err := contract.NewBlockSigner(addrBlockSigner, client) if err != nil { log.Error("Fail get instance of blockSigner", "error", err) @@ -219,18 +223,15 @@ func GetRandomizeFromContract(client bind.ContractBackend, addrMasternode common randomize, err := randomizeContract.NewTomoRandomize(common.HexToAddress(common.RandomizeSMC), client) if err != nil { log.Error("Fail to get instance of randomize", "error", err) - return -1, err } opts := new(bind.CallOpts) secrets, err := randomize.GetSecret(opts, addrMasternode) if err != nil { log.Error("Fail get secrets from randomize", "error", err) - return -1, err } opening, err := randomize.GetOpening(opts, addrMasternode) if err != nil { log.Error("Fail get opening from randomize", "error", err) - return -1, err } return DecryptRandomizeFromSecretsAndOpening(secrets, opening) @@ -420,46 +421,28 @@ func CalculateRewardForSigner(chainReward *big.Int, signers map[common.Address]* return resultSigners, nil } -func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, signerAddr common.Address) common.Address { - owner := signerAddr - opts := new(bind.CallOpts) - owner, err := validator.GetCandidateOwner(opts, signerAddr) - if err != nil { - log.Error("Fail get candidate owner", "error", err) - return owner - } - +// Get candidate owner by address. +func GetCandidatesOwnerBySigner(state *state.StateDB, signerAddr common.Address) common.Address { + owner := GetCandidateOwner(state, signerAddr) return owner } -// Calculate reward for holders. -func CalculateRewardForHolders(foudationWalletAddr common.Address, validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { - rewards, err := GetRewardBalancesRate(foudationWalletAddr, signer, calcReward, validator) +func CalculateRewardForHolders(foundationWalletAddr common.Address, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { + rewards, err := GetRewardBalancesRate(foundationWalletAddr, state, signer, calcReward) if err != nil { return err, nil } - if len(rewards) > 0 { - for holder, reward := range rewards { - state.AddBalance(holder, reward) - } - } return nil, rewards } -// Get reward balance rates for master node, founder and holders. -func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) { - owner := GetCandidatesOwnerBySigner(validator, masterAddr) +func GetRewardBalancesRate(foundationWalletAddr common.Address, state *state.StateDB, masterAddr common.Address, totalReward *big.Int) (map[common.Address]*big.Int, error) { + owner := GetCandidatesOwnerBySigner(state, masterAddr) balances := make(map[common.Address]*big.Int) rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardMasterPercent)) rewardMaster = new(big.Int).Div(rewardMaster, new(big.Int).SetInt64(100)) balances[owner] = rewardMaster // Get voters for masternode. - opts := new(bind.CallOpts) - voters, err := validator.GetVoters(opts, masterAddr) - if err != nil { - log.Crit("Fail to get voters", "error", err) - return nil, err - } + voters := GetVoters(state, masterAddr) if len(voters) > 0 { totalVoterReward := new(big.Int).Mul(totalReward, new(big.Int).SetUint64(common.RewardVoterPercent)) @@ -468,13 +451,7 @@ func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common // Get voters capacities. voterCaps := make(map[common.Address]*big.Int) for _, voteAddr := range voters { - var voterCap *big.Int - - voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) - if err != nil { - log.Crit("Fail to get vote capacity", "error", err) - } - + voterCap := GetVoterCap(state, masterAddr, voteAddr) totalCap.Add(totalCap, voterCap) voterCaps[voteAddr] = voterCap } @@ -494,9 +471,9 @@ func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common } } - foudationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardFoundationPercent)) - foudationReward = new(big.Int).Div(foudationReward, new(big.Int).SetInt64(100)) - balances[foudationWalletAddr] = foudationReward + foundationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardFoundationPercent)) + foundationReward = new(big.Int).Div(foundationReward, new(big.Int).SetInt64(100)) + balances[foundationWalletAddr] = foundationReward jsonHolders, err := json.Marshal(balances) if err != nil { diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index f3896db4b8..a1cbf6a386 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -20,15 +20,16 @@ import ( "math/big" "testing" "time" + "math/rand" + "encoding/json" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts" - "github.com/ethereum/go-ethereum/contracts/validator/contract" + contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" - "math/rand" + "github.com/ethereum/go-ethereum/log" ) var ( @@ -94,7 +95,7 @@ func TestRewardBalance(t *testing.T) { // validatorAddr, _, baseValidator, err := contract.DeployTomoValidator(transactOpts, contractBackend, big.NewInt(50000), big.NewInt(99), big.NewInt(100), big.NewInt(100)) validatorCap := new(big.Int) validatorCap.SetString("50000000000000000000000", 10) - validatorAddr, _, baseValidator, err := contract.DeployTomoValidator( + validatorAddr, _, baseValidator, err := contractValidator.DeployTomoValidator( transactOpts, contractBackend, []common.Address{addr}, @@ -144,7 +145,7 @@ func TestRewardBalance(t *testing.T) { foundationAddr := common.HexToAddress(common.FoudationAddr) totalReward := new(big.Int).SetInt64(15 * 1000) - rewards, err := contracts.GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator) + rewards, err := GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator) if err != nil { t.Error("Fail to get reward balances rate.", err) } @@ -175,3 +176,76 @@ func TestRewardBalance(t *testing.T) { } } + +func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) { + owner := GetCandidatesOwnerBySigner(validator, masterAddr) + balances := make(map[common.Address]*big.Int) + rewardMaster := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardMasterPercent)) + rewardMaster = new(big.Int).Div(rewardMaster, new(big.Int).SetInt64(100)) + balances[owner] = rewardMaster + // Get voters for masternode. + opts := new(bind.CallOpts) + voters, err := validator.GetVoters(opts, masterAddr) + if err != nil { + log.Crit("Fail to get voters", "error", err) + return nil, err + } + + if len(voters) > 0 { + totalVoterReward := new(big.Int).Mul(totalReward, new(big.Int).SetUint64(common.RewardVoterPercent)) + totalVoterReward = new(big.Int).Div(totalVoterReward, new(big.Int).SetUint64(100)) + totalCap := new(big.Int) + // Get voters capacities. + voterCaps := make(map[common.Address]*big.Int) + for _, voteAddr := range voters { + var voterCap *big.Int + + voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + if err != nil { + log.Crit("Fail to get vote capacity", "error", err) + } + + totalCap.Add(totalCap, voterCap) + voterCaps[voteAddr] = voterCap + } + if totalCap.Cmp(new(big.Int).SetInt64(0)) > 0 { + for addr, voteCap := range voterCaps { + // Only valid voter has cap > 0. + if voteCap.Cmp(new(big.Int).SetInt64(0)) > 0 { + rcap := new(big.Int).Mul(totalVoterReward, voteCap) + rcap = new(big.Int).Div(rcap, totalCap) + if balances[addr] != nil { + balances[addr].Add(balances[addr], rcap) + } else { + balances[addr] = rcap + } + } + } + } + } + + foudationReward := new(big.Int).Mul(totalReward, new(big.Int).SetInt64(common.RewardFoundationPercent)) + foudationReward = new(big.Int).Div(foudationReward, new(big.Int).SetInt64(100)) + balances[foudationWalletAddr] = foudationReward + + jsonHolders, err := json.Marshal(balances) + if err != nil { + log.Error("Fail to parse json holders", "error", err) + return nil, err + } + log.Info("Holders reward", "holders", string(jsonHolders), "master node", masterAddr.String()) + + return balances, nil +} + +func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, signerAddr common.Address) common.Address { + owner := signerAddr + opts := new(bind.CallOpts) + owner, err := validator.GetCandidateOwner(opts, signerAddr) + if err != nil { + log.Error("Fail get candidate owner", "error", err) + return owner + } + + return owner +} \ No newline at end of file diff --git a/contracts/validatorReader.go b/contracts/validatorReader.go new file mode 100644 index 0000000000..5311f2f8fe --- /dev/null +++ b/contracts/validatorReader.go @@ -0,0 +1,88 @@ +package contracts + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/crypto" +) + +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, + } +) + +func GetCandidates(statedb *state.StateDB) []common.Address { + slot := slotValidatorMapping["candidates"] + slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) + arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), slotHash) + keys := []common.Hash{} + for i := uint64(0); i < arrLength.Big().Uint64(); i++ { + key := getLocDynamicArrAtElement(slotHash, i, 1) + keys = append(keys, key) + } + rets := []common.Address{} + for _, key := range keys { + ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key) + rets = append(rets, common.HexToAddress(ret.Hex())) + } + return rets +} + +func GetCandidateOwner(statedb *state.StateDB, candidate common.Address) common.Address { + slot := slotValidatorMapping["validatorsState"] + // validatorsState[_candidate].owner; + locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot) + locCandidateOwner := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(0))) + ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateOwner)) + return common.HexToAddress(ret.Hex()) +} + +func GetCandidateCap(statedb *state.StateDB, parsed abi.ABI, candidate common.Address) string { + slot := slotValidatorMapping["validatorsState"] + // validatorsState[_candidate].cap; + locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot) + locCandidateCap := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(1))) + ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateCap)) + return ret.Hex() +} + +func GetVoters(statedb *state.StateDB, candidate common.Address) []common.Address { + //mapping(address => address[]) voters; + slot := slotValidatorMapping["voters"] + locVoters := getLocMappingAtKey(candidate.Hash(), slot) + arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locVoters)) + keys := []common.Hash{} + for i := uint64(0); i < arrLength.Big().Uint64(); i++ { + key := getLocDynamicArrAtElement(common.BigToHash(locVoters), i, 1) + keys = append(keys, key) + } + rets := []common.Address{} + for _, key := range keys { + ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key) + rets = append(rets, common.HexToAddress(ret.Hex())) + } + + return rets +} + +func GetVoterCap(state *state.StateDB, candidate, voter common.Address) *big.Int { + slot := slotValidatorMapping["validatorsState"] + locValidatorsState := getLocMappingAtKey(candidate.Hash(), slot) + locCandidateVoters := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(2))) + retByte := crypto.Keccak256(voter.Hash().Bytes(), common.BigToHash(locCandidateVoters).Bytes()) + ret := state.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BytesToHash(retByte)) + return ret.Big() +} diff --git a/core/block_validator_test.go b/core/block_validator_test.go index e334b3c3cd..c44def0148 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -48,7 +48,6 @@ func TestHeaderVerification(t *testing.T) { for i := 0; i < len(blocks); i++ { for j, valid := range []bool{true, false} { var results <-chan error - if valid { engine := ethash.NewFaker() _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) @@ -104,7 +103,6 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { // also an invalid chain (enough if one arbitrary block is invalid). for i, valid := range []bool{true, false} { var results <-chan error - if valid { chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) _, results = chain.engine.VerifyHeaders(chain, headers, seals) @@ -175,7 +173,6 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { // Start the verifications and immediately abort chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}) defer chain.Stop() - abort, results := chain.engine.VerifyHeaders(chain, headers, seals) close(abort) diff --git a/eth/backend.go b/eth/backend.go index e990093a89..d8eba90f7b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -34,10 +34,9 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/posv" "github.com/ethereum/go-ethereum/contracts" - "github.com/ethereum/go-ethereum/contracts/validator/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" - "github.com/ethereum/go-ethereum/core/state" + //"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" @@ -53,6 +52,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/core/state" ) type LesServer interface { @@ -244,9 +244,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Hook scans for bad masternodes and decide to penalty them c.HookPenalty = func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) { - client, err := eth.blockchain.GetClient() - if err != nil { - return nil, err + canonicalState, err := eth.blockchain.State() + if canonicalState == nil || err != nil { + log.Crit("Can't get state at head of canonical chain", "head number", eth.blockchain.CurrentHeader().Number.Uint64(), "err", err) } prevEpoc := blockNumberEpoc - chain.Config().Posv.Epoch if prevEpoc >= 0 { @@ -254,12 +254,13 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { prevHeader := chain.GetHeaderByNumber(prevEpoc) penSigners := c.GetMasternodes(chain, prevHeader) if len(penSigners) > 0 { - blockSignerAddr := common.HexToAddress(common.BlockSigners) // Loop for each block to check missing sign. for i := prevEpoc; i < blockNumberEpoc; i++ { - blockHeader := chain.GetHeaderByNumber(i) + bheader := chain.GetHeaderByNumber(i) + bhash := bheader.Hash() + block := chain.GetBlock(bhash, i) if len(penSigners) > 0 { - signedMasternodes, err := contracts.GetSignersFromContract(blockSignerAddr, client, blockHeader.Hash()) + signedMasternodes, err := contracts.GetSignersFromContract(canonicalState, block) if err != nil { return nil, err } @@ -287,25 +288,28 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Hook calculates reward for masternodes c.HookReward = func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) { - client, err := eth.blockchain.GetClient() - if err != nil { - log.Crit("Fail to connect IPC client for blockSigner", "error", err) + canonicalState, err := eth.blockchain.State() + if canonicalState == nil || err != nil { + log.Crit("Can't get state at head of canonical chain", "head number", header.Number.Uint64(), "err", err) } number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - foudationWalletAddr := chain.Config().Posv.FoudationWalletAddr - if foudationWalletAddr == (common.Address{}) { - log.Error("Foundation Wallet Address is empty", "error", foudationWalletAddr) + foundationWalletAddr := chain.Config().Posv.FoudationWalletAddr + if foundationWalletAddr == (common.Address{}) { + log.Error("Foundation Wallet Address is empty", "error", foundationWalletAddr) + return err, nil } rewards := make(map[string]interface{}) - if number > 0 && number-rCheckpoint > 0 && foudationWalletAddr != (common.Address{}) { + if number > 0 && number-rCheckpoint > 0 && foundationWalletAddr != (common.Address{}) { start := time.Now() + // Get signers in blockSigner smartcontract. // Get reward inflation. chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().Posv.Reward), new(big.Int).SetUint64(params.Ether)) chainReward = rewardInflation(chainReward, number, common.BlocksPerYear) totalSigner := new(uint64) signers, err := contracts.GetRewardForCheckpoint(c, chain, number, rCheckpoint, totalSigner) + log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) if err != nil { log.Crit("Fail to get signers for reward checkpoint", "error", err) @@ -315,19 +319,19 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { if err != nil { log.Crit("Fail to calculate reward for signers", "error", err) } - // Get validator. - validator, err := contract.NewTomoValidator(common.HexToAddress(common.MasternodeVotingSMC), client) - if err != nil { - log.Crit("Fail get instance of Tomo Validator", "error", err) - } // Add reward for coin holders. voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { for signer, calcReward := range rewardSigners { - err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) + err, rewards := contracts.CalculateRewardForHolders(foundationWalletAddr, canonicalState, signer, calcReward) if err != nil { log.Crit("Fail to calculate reward for holders.", "error", err) } + if len(rewards) > 0 { + for holder, reward := range rewards { + state.AddBalance(holder, reward) + } + } voterResults[signer] = rewards } } @@ -353,6 +357,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } return nil } + eth.txPool.IsMasterNode = func(address common.Address) bool { currentHeader := eth.blockchain.CurrentHeader() snap, err := c.GetSnapshot(eth.blockchain, currentHeader) @@ -404,6 +409,7 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai if chainConfig.Posv != nil { return posv.New(chainConfig.Posv, db) } + // Otherwise assume proof-of-work switch { case config.PowMode == ethash.ModeFake: diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a9a4c816fb..287d26a81d 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -855,22 +855,19 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx } fields["uncles"] = uncleHashes - // Get signers for block. - client, err := s.b.GetIPCClient() - if err != nil { - log.Error("Fail to connect IPC client for block status", "error", err) - return nil, err - } var signers []common.Address var filterSigners []common.Address finality := int32(0) if b.Number().Int64() > 0 { engine := s.b.GetEngine() - addrBlockSigner := common.HexToAddress(common.BlockSigners) - signers, err = contracts.GetSignersFromContract(addrBlockSigner, client, b.Hash()) + blockNr := rpc.BlockNumber(b.Number().Int64()) + state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) + if state == nil || err != nil { + return nil, err + } + signers, err = contracts.GetSignersFromContract(state, b) if err != nil { log.Error("Fail to get signers from block signer SC.", "error", err) - return nil, err } // Get block epoc latest. if s.b.ChainConfig().Posv != nil { diff --git a/miner/worker.go b/miner/worker.go index 9baefbce40..d71b39fe7b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -552,6 +552,7 @@ func (self *worker) commitNewWork() { if atomic.LoadInt32(&self.mining) == 1 { header.Coinbase = self.coinbase } + if err := self.engine.Prepare(self.chain, header); err != nil { log.Error("Failed to prepare header for new block", "err", err) return