From 237111a5ba3eb2ceae9498f964fdb6af932734eb Mon Sep 17 00:00:00 2001 From: Tuna Date: Sat, 5 Jan 2019 16:25:23 +0700 Subject: [PATCH] modify logic to adapt new readers --- consensus/posv/posv.go | 22 +++++---- contracts/blockSignerReader.go | 2 +- contracts/randomizeReader.go | 10 ++-- contracts/utils.go | 87 ++++++++-------------------------- contracts/validatorReader.go | 4 +- eth/backend.go | 63 ++++++++---------------- internal/ethapi/api.go | 15 +++--- 7 files changed, 68 insertions(+), 135 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index a6f0613954..54fbddf1b8 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -224,10 +224,10 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields - HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) - HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) - HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) - HookVerifyMNs func(header *types.Header, signers []common.Address) error + HookReward func(state *state.StateDB, chain consensus.ChainReader, header *types.Header) (error, map[string]interface{}) + HookPenalty func(state *state.StateDB, chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) + HookValidator func(state *state.StateDB, header *types.Header, signers []common.Address) ([]byte, error) + HookVerifyMNs func(state *state.StateDB, header *types.Header, signers []common.Address) error } // New creates a PoSV proof-of-stake-voting consensus engine with the initial @@ -390,9 +390,11 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types. } // If the block is a checkpoint block, verify the signer list if number%c.config.Epoch == 0 { + database := state.NewDatabase(c.db) + state, _ := state.New(parent.Hash(), database) penPenalties := []common.Address{} if c.HookPenalty != nil { - penPenalties, err = c.HookPenalty(chain, number) + penPenalties, err = c.HookPenalty(state, chain, number) if err != nil { return err } @@ -417,7 +419,7 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types. return errInvalidCheckpointSigners } if c.HookVerifyMNs != nil { - err := c.HookVerifyMNs(header, signers) + err := c.HookVerifyMNs(state, header, signers) if err != nil { return err } @@ -775,8 +777,10 @@ 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 { + database := state.NewDatabase(c.db) + state, _ := state.New(parent.Hash(), database) if c.HookPenalty != nil { - penMasternodes, err := c.HookPenalty(chain, number) + penMasternodes, err := c.HookPenalty(state, chain, number) if err != nil { return err } @@ -799,7 +803,7 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error header.Extra = append(header.Extra, masternode[:]...) } if c.HookValidator != nil { - validators, err := c.HookValidator(header, masternodes) + validators, err := c.HookValidator(state, header, masternodes) if err != nil { return err } @@ -850,7 +854,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state rCheckpoint := chain.Config().Posv.RewardCheckpoint if c.HookReward != nil && number%rCheckpoint == 0 { - err, rewards := c.HookReward(chain, state, header) + err, rewards := c.HookReward(state, chain, header) if err != nil { return nil, err } diff --git a/contracts/blockSignerReader.go b/contracts/blockSignerReader.go index 6a99c9a17d..f270589d5d 100644 --- a/contracts/blockSignerReader.go +++ b/contracts/blockSignerReader.go @@ -20,7 +20,7 @@ var ( ParsedBlockSignerABI, _ = abi.JSON(strings.NewReader(blockSignerContract.BlockSignerABI)) ) -func GetSigners(statedb *state.StateDB, parsed abi.ABI, block *types.Block) []common.Address { +func GetSigners(statedb *state.StateDB, block *types.Block) []common.Address { methodName := "getSigners" fmt.Printf("---%s---\n", methodName) start := time.Now() diff --git a/contracts/randomizeReader.go b/contracts/randomizeReader.go index 5b68109bbd..fd2d4bc3a0 100644 --- a/contracts/randomizeReader.go +++ b/contracts/randomizeReader.go @@ -19,7 +19,7 @@ var ( ParsedRandomizeABI, _ = abi.JSON(strings.NewReader(randomizeContract.TomoRandomizeABI)) ) -func GetSecret(statedb *state.StateDB, parsed abi.ABI, address common.Address) [][]byte { +func GetSecret(statedb *state.StateDB, address common.Address) [][32]byte { start := time.Now() fmt.Printf("--------GetSecret---------\n") @@ -32,10 +32,10 @@ func GetSecret(statedb *state.StateDB, parsed abi.ABI, address common.Address) [ key := getLocDynamicArrAtElement(common.BigToHash(locSecret), i, 1) keys = append(keys, key) } - rets := [][]byte{} + rets := [][32]byte{} for _, key := range keys { ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), key) - rets = append(rets, ret.Bytes()) + rets = append(rets, ret) fmt.Printf("ret hex: %v - ret byte: %v\n", ret.Hex(), ret.Bytes()) } elapsed := time.Since(start) @@ -44,7 +44,7 @@ func GetSecret(statedb *state.StateDB, parsed abi.ABI, address common.Address) [ return rets } -func GetOpening(statedb *state.StateDB, parsed abi.ABI, address common.Address) []byte { +func GetOpening(statedb *state.StateDB, address common.Address) [32]byte { start := time.Now() fmt.Printf("--------GetOpening---------\n") @@ -54,5 +54,5 @@ func GetOpening(statedb *state.StateDB, parsed abi.ABI, address common.Address) 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.Bytes() + return ret } diff --git a/contracts/utils.go b/contracts/utils.go index faf86b1c55..ad7feaeff8 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -31,14 +31,10 @@ 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" @@ -199,41 +195,14 @@ 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) { - blockSigner, err := contract.NewBlockSigner(addrBlockSigner, client) - if err != nil { - log.Error("Fail get instance of blockSigner", "error", err) - return nil, err - } - opts := new(bind.CallOpts) - addrs, err := blockSigner.GetSigners(opts, blockHash) - if err != nil { - log.Error("Fail get block signers", "error", err) - return nil, err - } - - return addrs, nil +func GetSignersFromContract(state *state.StateDB, block *types.Block) ([]common.Address, error) { + return GetSigners(state, block), nil } // Get random from randomize contract. -func GetRandomizeFromContract(client bind.ContractBackend, addrMasternode common.Address) (int64, error) { - 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 - } - +func GetRandomizeFromContract(state *state.StateDB, addrMasternode common.Address) (int64, error) { + secrets := GetSecret(state, addrMasternode) + opening := GetOpening(state, addrMasternode) return DecryptRandomizeFromSecretsAndOpening(secrets, opening) } @@ -306,8 +275,7 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) return random, nil } -// Calculate reward for reward checkpoint. -func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common.Address, number uint64, rCheckpoint uint64, client bind.ContractBackend, totalSigner *uint64) (map[common.Address]*rewardLog, error) { +func GetRewardForCheckpoint(chain consensus.ChainReader, number uint64, rCheckpoint uint64, totalSigner *uint64, state *state.StateDB) (map[common.Address]*rewardLog, error) { // Not reward for singer of genesis block and only calculate reward at checkpoint block. prevCheckpoint := number - (rCheckpoint * 2) startBlockNumber := prevCheckpoint + 1 @@ -318,8 +286,10 @@ func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common. if len(masternodes) > 0 { for i := startBlockNumber; i <= endBlockNumber; i++ { - block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) + bheader := chain.GetHeaderByNumber(i) + bhash := bheader.Hash() + block := chain.GetBlock(bhash, i) + addrs, err := GetSignersFromContract(state, block) if err != nil { log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) return nil, err @@ -382,21 +352,13 @@ func CalculateRewardForSigner(chainReward *big.Int, signers map[common.Address]* } // Get candidate owner by address. -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 - } - +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 } @@ -407,21 +369,14 @@ func CalculateRewardForHolders(foudationWalletAddr common.Address, validator *co } 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.Error("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)) @@ -430,7 +385,7 @@ func GetRewardBalancesRate(foudationWalletAddr common.Address, masterAddr common // Get voters capacities. voterCaps := make(map[common.Address]*big.Int) for _, voteAddr := range voters { - voterCap, err := validator.GetVoterCap(opts, masterAddr, voteAddr) + voterCap, err := GetVoterCap(state, masterAddr, voteAddr) if err != nil { log.Error("Fail to get vote capacity", "error", err) return nil, err @@ -455,9 +410,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/validatorReader.go b/contracts/validatorReader.go index 0cd081afa1..b8b1ea2a84 100644 --- a/contracts/validatorReader.go +++ b/contracts/validatorReader.go @@ -50,7 +50,7 @@ func GetCandidates(statedb *state.StateDB, parsed abi.ABI) []common.Address { return rets } -func GetCandidateOwner(statedb *state.StateDB, parsed abi.ABI, candidate common.Address) common.Address { +func GetCandidateOwner(statedb *state.StateDB, candidate common.Address) common.Address { start := time.Now() fmt.Printf("--------GetCandidateOwner---------\n") @@ -81,7 +81,7 @@ func GetCandidateCap(statedb *state.StateDB, parsed abi.ABI, candidate common.Ad return ret.Hex() } -func GetVoters(statedb *state.StateDB, parsed abi.ABI, candidate common.Address) []common.Address { +func GetVoters(statedb *state.StateDB, candidate common.Address) []common.Address { start := time.Now() fmt.Printf("--------GetVoters---------\n") diff --git a/eth/backend.go b/eth/backend.go index ca31035aee..2553de199a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -34,7 +34,6 @@ 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" @@ -231,9 +230,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { eth.protocolManager.fetcher.SetAppendM2HeaderHook(appendM2HeaderHook) // Hook prepares validators M2 for the current epoch at checkpoint block - c.HookValidator = func(header *types.Header, signers []common.Address) ([]byte, error) { + c.HookValidator = func(state *state.StateDB, header *types.Header, signers []common.Address) ([]byte, error) { start := time.Now() - validators, err := GetValidators(eth.blockchain, signers) + validators, err := GetValidators(state, signers) if err != nil { return []byte{}, err } @@ -243,23 +242,20 @@ 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 - } + c.HookPenalty = func(state *state.StateDB, chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) { prevEpoc := blockNumberEpoc - chain.Config().Posv.Epoch if prevEpoc >= 0 { start := time.Now() 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(state, block) if err != nil { return nil, err } @@ -286,28 +282,25 @@ 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) - } + c.HookReward = func(state *state.StateDB, chain consensus.ChainReader, header *types.Header) (error, map[string]interface{}) { 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. - addr := common.HexToAddress(common.BlockSigners) // 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(chain, addr, number, rCheckpoint, client, totalSigner) + signers, err := contracts.GetRewardForCheckpoint(chain, number, rCheckpoint, totalSigner, state) + 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) } @@ -316,16 +309,11 @@ 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, state, signer, calcReward) if err != nil { log.Crit("Fail to calculate reward for holders.", "error", err) } @@ -339,11 +327,11 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } // Hook verifies masternodes set - c.HookVerifyMNs = func(header *types.Header, signers []common.Address) error { + c.HookVerifyMNs = func(state *state.StateDB, header *types.Header, signers []common.Address) error { number := header.Number.Int64() if number > 0 && number%common.EpocBlockRandomize == 0 { start := time.Now() - validators, err := GetValidators(eth.blockchain, signers) + validators, err := GetValidators(state, signers) log.Debug("Time Calculated HookVerifyMNs ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) if err != nil { return err @@ -642,25 +630,14 @@ func (s *Ethereum) Stop() error { return nil } -func GetValidators(bc *core.BlockChain, masternodes []common.Address) ([]byte, error) { - if bc.Config().Posv == nil { - return nil, core.ErrNotPoSV - } - client, err := bc.GetClient() - if err != nil { - return nil, err - } +func GetValidators(state *state.StateDB, masternodes []common.Address) ([]byte, error) { // Check m2 exists on chaindb. // Get secrets and opening at epoc block checkpoint. - var candidates []int64 - if err != nil { - return nil, err - } lenSigners := int64(len(masternodes)) if lenSigners > 0 { for _, addr := range masternodes { - random, err := contracts.GetRandomizeFromContract(client, addr) + random, err := contracts.GetRandomizeFromContract(state, addr) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f9ec6ad29a..8e384da6c5 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -855,21 +855,18 @@ 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 { - 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 {