From d9ea2dedb0fbd85131d5f181b27bf3e2d46369f7 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Sun, 30 Dec 2018 17:14:48 +0000 Subject: [PATCH 01/37] add runtime validator contract call --- core/vm/validator/env.go | 25 +++++ core/vm/validator/runtime.go | 156 ++++++++++++++++++++++++++++++ core/vm/validator/runtime_test.go | 135 ++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 core/vm/validator/env.go create mode 100644 core/vm/validator/runtime.go create mode 100644 core/vm/validator/runtime_test.go diff --git a/core/vm/validator/env.go b/core/vm/validator/env.go new file mode 100644 index 0000000000..9e24c696e3 --- /dev/null +++ b/core/vm/validator/env.go @@ -0,0 +1,25 @@ +package validator + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/vm" +) + +func NewEnv(cfg *Config) *vm.EVM { + context := vm.Context{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + GetHash: func(uint64) common.Hash { return common.Hash{} }, + + Origin: cfg.Origin, + Coinbase: cfg.Coinbase, + BlockNumber: cfg.BlockNumber, + Time: cfg.Time, + Difficulty: cfg.Difficulty, + GasLimit: cfg.GasLimit, + GasPrice: cfg.GasPrice, + } + + return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) +} diff --git a/core/vm/validator/runtime.go b/core/vm/validator/runtime.go new file mode 100644 index 0000000000..2db1621ce6 --- /dev/null +++ b/core/vm/validator/runtime.go @@ -0,0 +1,156 @@ +package validator + +import ( + "math" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" +) + +// Config is a basic type specifying certain configuration flags for running +// the EVM. +type Config struct { + ChainConfig *params.ChainConfig + Difficulty *big.Int + Origin common.Address + Coinbase common.Address + BlockNumber *big.Int + Time *big.Int + GasLimit uint64 + GasPrice *big.Int + Value *big.Int + Debug bool + EVMConfig vm.Config + + State *state.StateDB + GetHashFn func(n uint64) common.Hash +} + +// sets defaults on the config +func setDefaults(cfg *Config) { + if cfg.ChainConfig == nil { + cfg.ChainConfig = ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: new(big.Int), + DAOForkBlock: new(big.Int), + DAOForkSupport: false, + EIP150Block: new(big.Int), + EIP155Block: new(big.Int), + EIP158Block: new(big.Int), + } + } + + if cfg.Difficulty == nil { + cfg.Difficulty = new(big.Int) + } + if cfg.Time == nil { + cfg.Time = big.NewInt(time.Now().Unix()) + } + if cfg.GasLimit == 0 { + cfg.GasLimit = math.MaxUint64 + } + if cfg.GasPrice == nil { + cfg.GasPrice = new(big.Int) + } + if cfg.Value == nil { + cfg.Value = new(big.Int) + } + if cfg.BlockNumber == nil { + cfg.BlockNumber = new(big.Int) + } + if cfg.GetHashFn == nil { + cfg.GetHashFn = func(n uint64) common.Hash { + return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String()))) + } + } +} + +// Execute executes the code using the input as call data during the execution. +// It returns the EVM's return value, the new state and an error if it failed. +// +// Executes sets up a in memory, temporarily, environment for the execution of +// the given code. It makes sure that it's restored to it's original state afterwards. +func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { + if cfg == nil { + cfg = new(Config) + } + setDefaults(cfg) + + if cfg.State == nil { + db, _ := ethdb.NewMemDatabase() + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) + } + var ( + address = common.StringToAddress("contract") + vmenv = NewEnv(cfg) + sender = vm.AccountRef(cfg.Origin) + ) + cfg.State.CreateAccount(address) + // set the receiver's (the executing contract) code for execution. + cfg.State.SetCode(address, code) + // Call the code with the given configuration. + ret, _, err := vmenv.Call( + sender, + common.StringToAddress("contract"), + input, + cfg.GasLimit, + cfg.Value, + ) + + return ret, cfg.State, err +} + +// Create executes the code using the EVM create method +func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { + if cfg == nil { + cfg = new(Config) + } + setDefaults(cfg) + + if cfg.State == nil { + db, _ := ethdb.NewMemDatabase() + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) + } + var ( + vmenv = NewEnv(cfg) + sender = vm.AccountRef(cfg.Origin) + ) + + // Call the code with the given configuration. + code, address, leftOverGas, err := vmenv.Create( + sender, + input, + cfg.GasLimit, + cfg.Value, + ) + return code, address, leftOverGas, err +} + +// Call executes the code given by the contract's address. It will return the +// EVM's return value or an error if it failed. +// +// Call, unlike Execute, requires a config and also requires the State field to +// be set. +func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { + setDefaults(cfg) + + vmenv := NewEnv(cfg) + + sender := cfg.State.GetOrNewStateObject(cfg.Origin) + // Call the code with the given configuration. + ret, leftOverGas, err := vmenv.Call( + sender, + address, + input, + cfg.GasLimit, + cfg.Value, + ) + + return ret, leftOverGas, err +} diff --git a/core/vm/validator/runtime_test.go b/core/vm/validator/runtime_test.go new file mode 100644 index 0000000000..c431842371 --- /dev/null +++ b/core/vm/validator/runtime_test.go @@ -0,0 +1,135 @@ +package validator + +import ( + "math/big" + "strings" + "testing" + + "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/core/vm" + "github.com/ethereum/go-ethereum/ethdb" +) + +func TestDefaults(t *testing.T) { + cfg := new(Config) + setDefaults(cfg) + + if cfg.Difficulty == nil { + t.Error("expected difficulty to be non nil") + } + + if cfg.Time == nil { + t.Error("expected time to be non nil") + } + if cfg.GasLimit == 0 { + t.Error("didn't expect gaslimit to be zero") + } + if cfg.GasPrice == nil { + t.Error("expected time to be non nil") + } + if cfg.Value == nil { + t.Error("expected time to be non nil") + } + if cfg.GetHashFn == nil { + t.Error("expected time to be non nil") + } + if cfg.BlockNumber == nil { + t.Error("expected block number to be non nil") + } +} + +func TestEVM(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Fatalf("crashed with: %v", r) + } + }() + + Execute([]byte{ + byte(vm.DIFFICULTY), + byte(vm.TIMESTAMP), + byte(vm.GASLIMIT), + byte(vm.PUSH1), + byte(vm.ORIGIN), + byte(vm.BLOCKHASH), + byte(vm.COINBASE), + }, nil, nil) +} + +func TestExecute(t *testing.T) { + ret, _, err := Execute([]byte{ + byte(vm.PUSH1), 10, + byte(vm.PUSH1), 0, + byte(vm.MSTORE), + byte(vm.PUSH1), 32, + byte(vm.PUSH1), 0, + byte(vm.RETURN), + }, nil, nil) + if err != nil { + t.Fatal("didn't expect error", err) + } + + num := new(big.Int).SetBytes(ret) + if num.Cmp(big.NewInt(10)) != 0 { + t.Error("Expected 10, got", num) + } +} + +func TestCall(t *testing.T) { + db, _ := ethdb.NewMemDatabase() + state, _ := state.New(common.Hash{}, state.NewDatabase(db)) + address := common.HexToAddress("0x0a") + state.SetCode(address, []byte{ + byte(vm.PUSH1), 10, + byte(vm.PUSH1), 0, + byte(vm.MSTORE), + byte(vm.PUSH1), 32, + byte(vm.PUSH1), 0, + byte(vm.RETURN), + }) + + ret, _, err := Call(address, nil, &Config{State: state}) + if err != nil { + t.Fatal("didn't expect error", err) + } + + num := new(big.Int).SetBytes(ret) + if num.Cmp(big.NewInt(10)) != 0 { + t.Error("Expected 10, got", num) + } +} + +func BenchmarkCall(b *testing.B) { + var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]` + + var code = common.Hex2Bytes("6060604052361561006c5760e060020a600035046308551a53811461007457806335a063b4146100865780633fa4f245146100a6578063590e1ae3146100af5780637150d8ae146100cf57806373fac6f0146100e1578063c19d93fb146100fe578063d696069714610112575b610131610002565b610133600154600160a060020a031681565b610131600154600160a060020a0390811633919091161461015057610002565b61014660005481565b610131600154600160a060020a039081163391909116146102d557610002565b610133600254600160a060020a031681565b610131600254600160a060020a0333811691161461023757610002565b61014660025460ff60a060020a9091041681565b61013160025460009060ff60a060020a9091041681146101cc57610002565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60025460009060a060020a900460ff16811461016b57610002565b600154600160a060020a03908116908290301631606082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f72c874aeff0b183a56e2b79c71b46e1aed4dee5e09862134b8821ba2fddbf8bf9250a150565b80546002023414806101dd57610002565b6002805460a060020a60ff021973ffffffffffffffffffffffffffffffffffffffff1990911633171660a060020a1790557fd5d55c8a68912e9a110618df8d5e2e83b8d83211c57a8ddd1203df92885dc881826060a15050565b60025460019060a060020a900460ff16811461025257610002565b60025460008054600160a060020a0390921691606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517fe89152acd703c9d8c7d28829d443260b411454d45394e7995815140c8cbcbcf79250a150565b60025460019060a060020a900460ff1681146102f057610002565b6002805460008054600160a060020a0390921692909102606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f8616bbbbad963e4e65b1366f1d75dfb63f9e9704bbbf91fb01bec70849906cf79250a15056") + + abi, err := abi.JSON(strings.NewReader(definition)) + if err != nil { + b.Fatal(err) + } + + cpurchase, err := abi.Pack("confirmPurchase") + if err != nil { + b.Fatal(err) + } + creceived, err := abi.Pack("confirmReceived") + if err != nil { + b.Fatal(err) + } + refund, err := abi.Pack("refund") + if err != nil { + b.Fatal(err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 400; j++ { + Execute(code, cpurchase, nil) + Execute(code, creceived, nil) + Execute(code, refund, nil) + } + } +} From 2ad8d44e545f752aebd7d271954f403e24ddc32d Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Mon, 31 Dec 2018 09:03:06 +0000 Subject: [PATCH 02/37] evm mem db --- contracts/utils.go | 87 ++++++++ .../{vm/validator/env.go => env_validator.go} | 7 +- core/runtime_validator.go | 205 ++++++++++++++++++ core/vm/validator/runtime.go | 156 ------------- core/vm/validator/runtime_test.go | 135 ------------ eth/backend.go | 11 +- 6 files changed, 302 insertions(+), 299 deletions(-) rename core/{vm/validator/env.go => env_validator.go} (80%) create mode 100644 core/runtime_validator.go delete mode 100644 core/vm/validator/runtime.go delete mode 100644 core/vm/validator/runtime_test.go diff --git a/contracts/utils.go b/contracts/utils.go index 42643b4571..dd05e2d4b5 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -42,6 +42,7 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -374,6 +375,17 @@ func CalculateRewardForSigner(chainReward *big.Int, signers map[common.Address]* } // Get candidate owner by address. +func GetCandidatesOwnerBySigner2(vmenv *vm.EVM, signerAddr common.Address) common.Address { + owner := signerAddr + owner, err := core.GetCandidateOwner(signerAddr, vmenv) + if err != nil { + log.Error("Fail get candidate owner", "error", err) + return owner + } + + return owner +} + func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, signerAddr common.Address) common.Address { owner := signerAddr opts := new(bind.CallOpts) @@ -386,6 +398,81 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign return owner } +// Calculate reward for holders. +func CalculateRewardForHolders2(foudationWalletAddr common.Address, vmenv *vm.EVM, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { + rewards, err := GetRewardBalancesRate2(foudationWalletAddr, signer, calcReward, vmenv) + 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 GetRewardBalancesRate2(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, vmenv *vm.EVM) (map[common.Address]*big.Int, error) { + owner := GetCandidatesOwnerBySigner2(vmenv, 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. + voters, err := core.GetVoters(masterAddr, vmenv) + if err != nil { + log.Error("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 { + voterCap, err := core.GetVoterCap(masterAddr, voteAddr, vmenv) + if err != nil { + log.Error("Fail to get vote capacity", "error", err) + return nil, 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()) + fmt.Println("Holders reward", "holders", string(jsonHolders), "master node", masterAddr.String()) + + return balances, nil +} + // 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) diff --git a/core/vm/validator/env.go b/core/env_validator.go similarity index 80% rename from core/vm/validator/env.go rename to core/env_validator.go index 9e24c696e3..aa62c3a913 100644 --- a/core/vm/validator/env.go +++ b/core/env_validator.go @@ -1,15 +1,14 @@ -package validator +package core import ( "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" ) func NewEnv(cfg *Config) *vm.EVM { context := vm.Context{ - CanTransfer: core.CanTransfer, - Transfer: core.Transfer, + CanTransfer: CanTransfer, + Transfer: Transfer, GetHash: func(uint64) common.Hash { return common.Hash{} }, Origin: cfg.Origin, diff --git a/core/runtime_validator.go b/core/runtime_validator.go new file mode 100644 index 0000000000..f1f98dff63 --- /dev/null +++ b/core/runtime_validator.go @@ -0,0 +1,205 @@ +package core + +import ( + "math" + "math/big" + "strings" + "time" + + "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/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" +) + +// Config is a basic type specifying certain configuration flags for running +// the EVM. +type Config struct { + ChainConfig *params.ChainConfig + Difficulty *big.Int + Origin common.Address + Coinbase common.Address + BlockNumber *big.Int + Time *big.Int + GasLimit uint64 + GasPrice *big.Int + Value *big.Int + Debug bool + EVMConfig vm.Config + + State *state.StateDB + GetHashFn func(n uint64) common.Hash +} + +var abiValidator = `[{"constant":false,"inputs":[{"name":"_candidate","type":"address"}],"name":"propose","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_candidate","type":"address"},{"name":"_cap","type":"uint256"}],"name":"unvote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getCandidates","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_blockNumber","type":"uint256"}],"name":"getWithdrawCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"getVoters","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawBlockNumbers","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"},{"name":"_voter","type":"address"}],"name":"getVoterCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidates","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_blockNumber","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"getCandidateCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_candidate","type":"address"}],"name":"vote","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"candidateCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"voterWithdrawDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_candidate","type":"address"}],"name":"resign","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"getCandidateOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxValidatorNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"candidateWithdrawDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"isCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minCandidateCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minVoterCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_candidates","type":"address[]"},{"name":"_caps","type":"uint256[]"},{"name":"_firstOwner","type":"address"},{"name":"_minCandidateCap","type":"uint256"},{"name":"_minVoterCap","type":"uint256"},{"name":"_maxValidatorNumber","type":"uint256"},{"name":"_candidateWithdrawDelay","type":"uint256"},{"name":"_voterWithdrawDelay","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_voter","type":"address"},{"indexed":false,"name":"_candidate","type":"address"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Vote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_voter","type":"address"},{"indexed":false,"name":"_candidate","type":"address"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Unvote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_owner","type":"address"},{"indexed":false,"name":"_candidate","type":"address"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Propose","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_owner","type":"address"},{"indexed":false,"name":"_candidate","type":"address"}],"name":"Resign","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_owner","type":"address"},{"indexed":false,"name":"_blockNumber","type":"uint256"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Withdraw","type":"event"}]` + +// sets defaults on the config +func setDefaults(cfg *Config) { + if cfg.ChainConfig == nil { + cfg.ChainConfig = ¶ms.ChainConfig{ + ChainId: big.NewInt(1), + HomesteadBlock: new(big.Int), + DAOForkBlock: new(big.Int), + DAOForkSupport: false, + EIP150Block: new(big.Int), + EIP155Block: new(big.Int), + EIP158Block: new(big.Int), + } + } + + if cfg.Difficulty == nil { + cfg.Difficulty = new(big.Int) + } + if cfg.Time == nil { + cfg.Time = big.NewInt(time.Now().Unix()) + } + if cfg.GasLimit == 0 { + cfg.GasLimit = math.MaxUint64 + } + if cfg.GasPrice == nil { + cfg.GasPrice = new(big.Int) + } + if cfg.Value == nil { + cfg.Value = new(big.Int) + } + if cfg.BlockNumber == nil { + cfg.BlockNumber = new(big.Int) + } + if cfg.GetHashFn == nil { + cfg.GetHashFn = func(n uint64) common.Hash { + return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String()))) + } + } +} + +// Execute executes the code using the input as call data during the execution. +// It returns the EVM's return value, the new state and an error if it failed. +// +// Executes sets up a in memory, temporarily, environment for the execution of +// the given code. It makes sure that it's restored to it's original state afterwards. +/* +func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { + if cfg == nil { + cfg = new(Config) + } + setDefaults(cfg) + + if cfg.State == nil { + db, _ := ethdb.NewMemDatabase() + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) + } + var ( + address = common.StringToAddress("contract") + vmenv = NewEnv(cfg) + sender = vm.AccountRef(cfg.Origin) + ) + cfg.State.CreateAccount(address) + // set the receiver's (the executing contract) code for execution. + cfg.State.SetCode(address, code) + // Call the code with the given configuration. + ret, _, err := vmenv.Call( + sender, + common.StringToAddress("contract"), + input, + cfg.GasLimit, + cfg.Value, + ) + + return ret, cfg.State, err +} +*/ +func NewRuntimeEVM(chainState *state.StateDB) *vm.EVM { + cfg := new(Config) + setDefaults(cfg) + db, _ := ethdb.NewMemDatabase() + cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) + + var ( + address = common.HexToAddress(common.MasternodeVotingSMC) + vmenv = NewEnv(cfg) + ) + cfg.State.CreateAccount(address) + code := chainState.GetCode(common.HexToAddress(common.MasternodeVotingSMC)) + cfg.State.SetCode(address, code) + + f := func(key, val common.Hash) bool { + cfg.State.SetState(address, key, val) + return true + } + chainState.ForEachStorage(common.HexToAddress(common.MasternodeVotingSMC), f) + + return vmenv +} + +func GetVoters(candidate common.Address, vmenv *vm.EVM) ([]common.Address, error) { + + abi, err := abi.JSON(strings.NewReader(abiValidator)) + getVoters, err := abi.Pack("getVoters", candidate) + + // Call the code with the given configuration. + voters, _, err := vmenv.Call( + vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), + common.HexToAddress(common.MasternodeVotingSMC), + getVoters, + math.MaxUint64, + new(big.Int), + ) + + ret := common.ExtractAddressFromBytes(voters) + + return ret, err +} + +func GetCandidateOwner(candidate common.Address, vmenv *vm.EVM) (common.Address, error) { + + abi, err := abi.JSON(strings.NewReader(abiValidator)) + getCandidateOwner, err := abi.Pack("getCandidateOwner", candidate) + + // Call the code with the given configuration. + ret, _, err := vmenv.Call( + vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), + common.HexToAddress(common.MasternodeVotingSMC), + getCandidateOwner, + math.MaxUint64, + new(big.Int), + ) + + return common.BytesToAddress(ret), err +} + +func GetCandidateCap(candidate common.Address, vmenv *vm.EVM) (*big.Int, error) { + + abi, err := abi.JSON(strings.NewReader(abiValidator)) + getCandidateCap, err := abi.Pack("getCandidateCap", candidate) + + // Call the code with the given configuration. + ret, _, err := vmenv.Call( + vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), + common.HexToAddress(common.MasternodeVotingSMC), + getCandidateCap, + math.MaxUint64, + new(big.Int), + ) + + return new(big.Int).SetBytes(ret), err +} + +func GetVoterCap(candidate common.Address, voter common.Address, vmenv *vm.EVM) (*big.Int, error) { + + abi, err := abi.JSON(strings.NewReader(abiValidator)) + getVoterCap, err := abi.Pack("getVoterCap", candidate, voter) + + // Call the code with the given configuration. + ret, _, err := vmenv.Call( + vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), + common.HexToAddress(common.MasternodeVotingSMC), + getVoterCap, + math.MaxUint64, + new(big.Int), + ) + + return new(big.Int).SetBytes(ret), err +} diff --git a/core/vm/validator/runtime.go b/core/vm/validator/runtime.go deleted file mode 100644 index 2db1621ce6..0000000000 --- a/core/vm/validator/runtime.go +++ /dev/null @@ -1,156 +0,0 @@ -package validator - -import ( - "math" - "math/big" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/params" -) - -// Config is a basic type specifying certain configuration flags for running -// the EVM. -type Config struct { - ChainConfig *params.ChainConfig - Difficulty *big.Int - Origin common.Address - Coinbase common.Address - BlockNumber *big.Int - Time *big.Int - GasLimit uint64 - GasPrice *big.Int - Value *big.Int - Debug bool - EVMConfig vm.Config - - State *state.StateDB - GetHashFn func(n uint64) common.Hash -} - -// sets defaults on the config -func setDefaults(cfg *Config) { - if cfg.ChainConfig == nil { - cfg.ChainConfig = ¶ms.ChainConfig{ - ChainId: big.NewInt(1), - HomesteadBlock: new(big.Int), - DAOForkBlock: new(big.Int), - DAOForkSupport: false, - EIP150Block: new(big.Int), - EIP155Block: new(big.Int), - EIP158Block: new(big.Int), - } - } - - if cfg.Difficulty == nil { - cfg.Difficulty = new(big.Int) - } - if cfg.Time == nil { - cfg.Time = big.NewInt(time.Now().Unix()) - } - if cfg.GasLimit == 0 { - cfg.GasLimit = math.MaxUint64 - } - if cfg.GasPrice == nil { - cfg.GasPrice = new(big.Int) - } - if cfg.Value == nil { - cfg.Value = new(big.Int) - } - if cfg.BlockNumber == nil { - cfg.BlockNumber = new(big.Int) - } - if cfg.GetHashFn == nil { - cfg.GetHashFn = func(n uint64) common.Hash { - return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String()))) - } - } -} - -// Execute executes the code using the input as call data during the execution. -// It returns the EVM's return value, the new state and an error if it failed. -// -// Executes sets up a in memory, temporarily, environment for the execution of -// the given code. It makes sure that it's restored to it's original state afterwards. -func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { - if cfg == nil { - cfg = new(Config) - } - setDefaults(cfg) - - if cfg.State == nil { - db, _ := ethdb.NewMemDatabase() - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) - } - var ( - address = common.StringToAddress("contract") - vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) - ) - cfg.State.CreateAccount(address) - // set the receiver's (the executing contract) code for execution. - cfg.State.SetCode(address, code) - // Call the code with the given configuration. - ret, _, err := vmenv.Call( - sender, - common.StringToAddress("contract"), - input, - cfg.GasLimit, - cfg.Value, - ) - - return ret, cfg.State, err -} - -// Create executes the code using the EVM create method -func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { - if cfg == nil { - cfg = new(Config) - } - setDefaults(cfg) - - if cfg.State == nil { - db, _ := ethdb.NewMemDatabase() - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) - } - var ( - vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) - ) - - // Call the code with the given configuration. - code, address, leftOverGas, err := vmenv.Create( - sender, - input, - cfg.GasLimit, - cfg.Value, - ) - return code, address, leftOverGas, err -} - -// Call executes the code given by the contract's address. It will return the -// EVM's return value or an error if it failed. -// -// Call, unlike Execute, requires a config and also requires the State field to -// be set. -func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { - setDefaults(cfg) - - vmenv := NewEnv(cfg) - - sender := cfg.State.GetOrNewStateObject(cfg.Origin) - // Call the code with the given configuration. - ret, leftOverGas, err := vmenv.Call( - sender, - address, - input, - cfg.GasLimit, - cfg.Value, - ) - - return ret, leftOverGas, err -} diff --git a/core/vm/validator/runtime_test.go b/core/vm/validator/runtime_test.go deleted file mode 100644 index c431842371..0000000000 --- a/core/vm/validator/runtime_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package validator - -import ( - "math/big" - "strings" - "testing" - - "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/core/vm" - "github.com/ethereum/go-ethereum/ethdb" -) - -func TestDefaults(t *testing.T) { - cfg := new(Config) - setDefaults(cfg) - - if cfg.Difficulty == nil { - t.Error("expected difficulty to be non nil") - } - - if cfg.Time == nil { - t.Error("expected time to be non nil") - } - if cfg.GasLimit == 0 { - t.Error("didn't expect gaslimit to be zero") - } - if cfg.GasPrice == nil { - t.Error("expected time to be non nil") - } - if cfg.Value == nil { - t.Error("expected time to be non nil") - } - if cfg.GetHashFn == nil { - t.Error("expected time to be non nil") - } - if cfg.BlockNumber == nil { - t.Error("expected block number to be non nil") - } -} - -func TestEVM(t *testing.T) { - defer func() { - if r := recover(); r != nil { - t.Fatalf("crashed with: %v", r) - } - }() - - Execute([]byte{ - byte(vm.DIFFICULTY), - byte(vm.TIMESTAMP), - byte(vm.GASLIMIT), - byte(vm.PUSH1), - byte(vm.ORIGIN), - byte(vm.BLOCKHASH), - byte(vm.COINBASE), - }, nil, nil) -} - -func TestExecute(t *testing.T) { - ret, _, err := Execute([]byte{ - byte(vm.PUSH1), 10, - byte(vm.PUSH1), 0, - byte(vm.MSTORE), - byte(vm.PUSH1), 32, - byte(vm.PUSH1), 0, - byte(vm.RETURN), - }, nil, nil) - if err != nil { - t.Fatal("didn't expect error", err) - } - - num := new(big.Int).SetBytes(ret) - if num.Cmp(big.NewInt(10)) != 0 { - t.Error("Expected 10, got", num) - } -} - -func TestCall(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - state, _ := state.New(common.Hash{}, state.NewDatabase(db)) - address := common.HexToAddress("0x0a") - state.SetCode(address, []byte{ - byte(vm.PUSH1), 10, - byte(vm.PUSH1), 0, - byte(vm.MSTORE), - byte(vm.PUSH1), 32, - byte(vm.PUSH1), 0, - byte(vm.RETURN), - }) - - ret, _, err := Call(address, nil, &Config{State: state}) - if err != nil { - t.Fatal("didn't expect error", err) - } - - num := new(big.Int).SetBytes(ret) - if num.Cmp(big.NewInt(10)) != 0 { - t.Error("Expected 10, got", num) - } -} - -func BenchmarkCall(b *testing.B) { - var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]` - - var code = common.Hex2Bytes("6060604052361561006c5760e060020a600035046308551a53811461007457806335a063b4146100865780633fa4f245146100a6578063590e1ae3146100af5780637150d8ae146100cf57806373fac6f0146100e1578063c19d93fb146100fe578063d696069714610112575b610131610002565b610133600154600160a060020a031681565b610131600154600160a060020a0390811633919091161461015057610002565b61014660005481565b610131600154600160a060020a039081163391909116146102d557610002565b610133600254600160a060020a031681565b610131600254600160a060020a0333811691161461023757610002565b61014660025460ff60a060020a9091041681565b61013160025460009060ff60a060020a9091041681146101cc57610002565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60025460009060a060020a900460ff16811461016b57610002565b600154600160a060020a03908116908290301631606082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f72c874aeff0b183a56e2b79c71b46e1aed4dee5e09862134b8821ba2fddbf8bf9250a150565b80546002023414806101dd57610002565b6002805460a060020a60ff021973ffffffffffffffffffffffffffffffffffffffff1990911633171660a060020a1790557fd5d55c8a68912e9a110618df8d5e2e83b8d83211c57a8ddd1203df92885dc881826060a15050565b60025460019060a060020a900460ff16811461025257610002565b60025460008054600160a060020a0390921691606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517fe89152acd703c9d8c7d28829d443260b411454d45394e7995815140c8cbcbcf79250a150565b60025460019060a060020a900460ff1681146102f057610002565b6002805460008054600160a060020a0390921692909102606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f8616bbbbad963e4e65b1366f1d75dfb63f9e9704bbbf91fb01bec70849906cf79250a15056") - - abi, err := abi.JSON(strings.NewReader(definition)) - if err != nil { - b.Fatal(err) - } - - cpurchase, err := abi.Pack("confirmPurchase") - if err != nil { - b.Fatal(err) - } - creceived, err := abi.Pack("confirmReceived") - if err != nil { - b.Fatal(err) - } - refund, err := abi.Pack("refund") - if err != nil { - b.Fatal(err) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - for j := 0; j < 400; j++ { - Execute(code, cpurchase, nil) - Execute(code, creceived, nil) - Execute(code, refund, nil) - } - } -} diff --git a/eth/backend.go b/eth/backend.go index c05909bfd6..dc15a048e2 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -37,7 +37,7 @@ 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/contracts/validator/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" @@ -323,7 +323,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return err, nil } // Get validator. - validator, err := contract.NewTomoValidator(common.HexToAddress(common.MasternodeVotingSMC), client) + // validator, err := contract.NewTomoValidator(common.HexToAddress(common.MasternodeVotingSMC), client) if err != nil { log.Error("Fail get instance of Tomo Validator", "error", err) return err, nil @@ -331,8 +331,10 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Add reward for coin holders. voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { + vmenv := core.NewRuntimeEVM(state) for signer, calcReward := range rewardSigners { - err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) + // err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) + err, rewards := contracts.CalculateRewardForHolders2(foudationWalletAddr, vmenv, state, signer, calcReward) if err != nil { log.Error("Fail to calculate reward for holders.", "error", err) return err, nil @@ -341,7 +343,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } rewards["rewards"] = voterResults - log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) + // log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) + fmt.Println("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) } return nil, rewards } From 51cc41b52502ec849ac34558b9e5f500a31de27c Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Mon, 31 Dec 2018 17:25:29 +0000 Subject: [PATCH 03/37] goroutine get signers --- contracts/utils.go | 81 ++++++++++++++++++++++++++++------------------ eth/backend.go | 11 ++++--- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/contracts/utils.go b/contracts/utils.go index dd05e2d4b5..ab68c9d002 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -310,38 +310,57 @@ func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common. masternodes := posv.GetMasternodesFromCheckpointHeader(prevHeaderCheckpoint) if len(masternodes) > 0 { - for i := startBlockNumber; i <= endBlockNumber; i++ { - block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) - if err != nil { - log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - return nil, err - } - // Filter duplicate address. - if len(addrs) > 0 { - addrSigners := make(map[common.Address]bool) - for _, masternode := range masternodes { - for _, addr := range addrs { - if addr == masternode { - if _, ok := addrSigners[addr]; !ok { - addrSigners[addr] = true - } - break - } - } - } - for addr := range addrSigners { - _, exist := signers[addr] - if exist { - signers[addr].Sign++ - } else { - signers[addr] = &rewardLog{1, new(big.Int)} - } - *totalSigner++ - } - } - } + var wg sync.WaitGroup + squeue := make(chan []common.Address, 1) + wg.Add(900) + + for i := startBlockNumber; i <= endBlockNumber; i++ { + go func(i uint64) { + block := chain.GetHeaderByNumber(i) + addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) + if err != nil { + log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) + // return nil, err + } + squeue <- addrs + }(i) + } + + fsigner := func() { + for addrs := range squeue { + // Filter duplicate address. + if len(addrs) > 0 { + addrSigners := make(map[common.Address]bool) + for _, masternode := range masternodes { + for _, addr := range addrs { + if addr == masternode { + if _, ok := addrSigners[addr]; !ok { + addrSigners[addr] = true + } + break + } + } + } + + for addr := range addrSigners { + _, exist := signers[addr] + if exist { + signers[addr].Sign++ + } else { + signers[addr] = &rewardLog{1, new(big.Int)} + } + *totalSigner++ + } + } + wg.Done() + } + } + + go fsigner() + + wg.Wait() + fmt.Println("totalSigner", *totalSigner) } log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber) diff --git a/eth/backend.go b/eth/backend.go index dc15a048e2..688f04fad7 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -37,7 +37,7 @@ 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/contracts/validator/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/state" @@ -312,6 +312,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { totalSigner := new(uint64) signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) + fmt.Println("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) if err != nil { log.Error("Fail to get signers for reward checkpoint", "error", err) return err, nil @@ -323,7 +324,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return err, nil } // Get validator. - // validator, err := contract.NewTomoValidator(common.HexToAddress(common.MasternodeVotingSMC), client) + validator, err := contract.NewTomoValidator(common.HexToAddress(common.MasternodeVotingSMC), client) if err != nil { log.Error("Fail get instance of Tomo Validator", "error", err) return err, nil @@ -331,10 +332,10 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Add reward for coin holders. voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { - vmenv := core.NewRuntimeEVM(state) + // vmenv := core.NewRuntimeEVM(state) for signer, calcReward := range rewardSigners { - // err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) - err, rewards := contracts.CalculateRewardForHolders2(foudationWalletAddr, vmenv, state, signer, calcReward) + err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) + // err, rewards := contracts.CalculateRewardForHolders2(foudationWalletAddr, vmenv, state, signer, calcReward) if err != nil { log.Error("Fail to calculate reward for holders.", "error", err) return err, nil From c00d2dc9aa91b9909e85aee66bd11d439b7332d6 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Wed, 2 Jan 2019 11:49:50 +0000 Subject: [PATCH 04/37] tx from --- contracts/utils.go | 98 ++++++++++++++++++--------------------- core/types/transaction.go | 20 ++++++++ 2 files changed, 65 insertions(+), 53 deletions(-) diff --git a/contracts/utils.go b/contracts/utils.go index ab4befaa15..3f8350f187 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -86,8 +86,7 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m // Add tx signed to local tx pool. err = pool.AddLocal(txSigned) if err != nil { - log.Error("Fail to add tx sign to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) - return err + log.Warn("Fail to add tx sign to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) } // Create secret tx. @@ -116,7 +115,6 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m err = pool.AddLocal(txSigned) if err != nil { log.Error("Fail to add tx secret to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) - return err } // Put randomize key into chainDb. @@ -128,7 +126,6 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m randomizeKeyValue, err := chainDb.Get(randomizeKeyName) if err != nil { log.Error("Fail to get randomize key from state db.", "error", err) - return err } tx, err := BuildTxOpeningRandomize(nonce+1, common.HexToAddress(common.RandomizeSMC), randomizeKeyValue) @@ -145,7 +142,6 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m err = pool.AddLocal(txSigned) if err != nil { log.Error("Fail to add tx opening to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) - return err } // Clear randomize key in state db. @@ -221,18 +217,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) @@ -297,7 +290,6 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) intNumber, err := strconv.Atoi(decryptSecret) if err != nil { log.Error("Can not convert string to integer", "error", err) - return -1, err } random = int64(intNumber) } @@ -319,56 +311,56 @@ func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common. if len(masternodes) > 0 { - var wg sync.WaitGroup - squeue := make(chan []common.Address, 1) - wg.Add(900) + var wg sync.WaitGroup + squeue := make(chan []common.Address, 1) + wg.Add(900) for i := startBlockNumber; i <= endBlockNumber; i++ { - go func(i uint64) { - block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) - if err != nil { - log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - // return nil, err - } - squeue <- addrs - }(i) - } + go func(i uint64) { + block := chain.GetHeaderByNumber(i) + addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) + if err != nil { + log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) + // return nil, err + } + squeue <- addrs + }(i) + } - fsigner := func() { - for addrs := range squeue { - // Filter duplicate address. - if len(addrs) > 0 { - addrSigners := make(map[common.Address]bool) - for _, masternode := range masternodes { - for _, addr := range addrs { - if addr == masternode { - if _, ok := addrSigners[addr]; !ok { - addrSigners[addr] = true - } - break - } - } - } + fsigner := func() { + for addrs := range squeue { + // Filter duplicate address. + if len(addrs) > 0 { + addrSigners := make(map[common.Address]bool) + for _, masternode := range masternodes { + for _, addr := range addrs { + if addr == masternode { + if _, ok := addrSigners[addr]; !ok { + addrSigners[addr] = true + } + break + } + } + } - for addr := range addrSigners { - _, exist := signers[addr] - if exist { - signers[addr].Sign++ - } else { - signers[addr] = &rewardLog{1, new(big.Int)} - } - *totalSigner++ - } - } - wg.Done() - } - } + for addr := range addrSigners { + _, exist := signers[addr] + if exist { + signers[addr].Sign++ + } else { + signers[addr] = &rewardLog{1, new(big.Int)} + } + *totalSigner++ + } + } + wg.Done() + } + } - go fsigner() + go fsigner() - wg.Wait() - fmt.Println("totalSigner", *totalSigner) + wg.Wait() + fmt.Println("totalSigner", *totalSigner) } log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber) diff --git a/core/types/transaction.go b/core/types/transaction.go index 653498a851..d7c8c3086b 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -195,6 +195,19 @@ func (tx *Transaction) To() *common.Address { return &to } +func (tx *Transaction) From() *common.Address { + if tx.data.V != nil { + signer := deriveSigner(tx.data.V) + if f, err := Sender(signer, tx); err != nil { + return nil + } else { + return &f + } + } else { + return nil + } +} + // Hash hashes the RLP encoding of tx. // It uniquely identifies the transaction. func (tx *Transaction) Hash() common.Hash { @@ -274,6 +287,13 @@ func (tx *Transaction) IsSpecialTransaction() bool { return tx.To().String() == common.RandomizeSMC || tx.To().String() == common.BlockSigners } +func (tx *Transaction) IsSigningTransaction() bool { + if tx.To() == nil { + return false + } + return tx.To().String() == common.BlockSigners +} + func (tx *Transaction) String() string { var from, to string if tx.data.V != nil { From d3ad6c39f27da5b7c98c28c5449c6a6358a1400d Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Wed, 2 Jan 2019 12:50:05 +0000 Subject: [PATCH 05/37] try use cache for blocksigners --- consensus/posv/posv.go | 20 ++++++++++++++++++-- contracts/utils.go | 26 +++++++++++++++++++++++--- eth/backend.go | 3 ++- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index a6f0613954..09f97207b6 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -48,8 +48,9 @@ import ( ) const ( - inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory - M2ByteLength = 4 + inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory + blockSignersCacheLimit = 1800 + M2ByteLength = 4 ) type Masternode struct { @@ -224,6 +225,7 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields + BlockSigners *lru.ARCCache 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) @@ -239,6 +241,7 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { conf.Epoch = epochLength } // Allocate the snapshot caches and create the engine + BlockSigners, _ := lru.NewARC(blockSignersCacheLimit) recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySnapshots) validatorSignatures, _ := lru.NewARC(inmemorySnapshots) @@ -246,6 +249,7 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { return &Posv{ config: &conf, db: db, + BlockSigners: BlockSigners, recents: recents, signatures: signatures, verifiedHeaders: verifiedHeaders, @@ -254,6 +258,10 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { } } +func (c *Posv) GetBlockSigners() *lru.ARCCache { + return c.BlockSigners +} + // Author implements consensus.Engine, returning the Ethereum address recovered // from the signature in the header's extra-data section. func (c *Posv) Author(header *types.Header) (common.Address, error) { @@ -849,6 +857,14 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint + var lAddr []common.Address + for _, tx := range txs { + if tx.IsSigningTransaction() { + lAddr = append(lAddr, *tx.From()) + } + } + c.BlockSigners.Add(header.Hash(), lAddr) + if c.HookReward != nil && number%rCheckpoint == 0 { err, rewards := c.HookReward(chain, state, header) if err != nil { diff --git a/contracts/utils.go b/contracts/utils.go index 3f8350f187..c24f90c3b7 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -208,10 +208,29 @@ func GetSignersFromContract(addrBlockSigner common.Address, client bind.Contract log.Error("Fail get block signers", "error", err) return nil, err } - return addrs, nil } +func GetSignersFromContract2(c *posv.Posv, 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) + if caddrs, ok := c.GetBlockSigners().Get(blockHash); !ok { + addrs, err := blockSigner.GetSigners(opts, blockHash) + if err != nil { + log.Error("Fail get block signers", "error", err) + return nil, err + } + return addrs, nil + } else { + return caddrs.([]common.Address), nil + } + return nil, 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) @@ -300,7 +319,7 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) } // 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(c *posv.Posv, chain consensus.ChainReader, blockSignerAddr common.Address, number uint64, rCheckpoint uint64, client bind.ContractBackend, totalSigner *uint64) (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,7 +337,8 @@ func GetRewardForCheckpoint(chain consensus.ChainReader, blockSignerAddr common. for i := startBlockNumber; i <= endBlockNumber; i++ { go func(i uint64) { block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) + addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) + // addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) if err != nil { log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) // return nil, err diff --git a/eth/backend.go b/eth/backend.go index 6c2022e19c..2f0b5fcd3c 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -307,7 +307,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { chainReward = rewardInflation(chainReward, number, common.BlocksPerYear) totalSigner := new(uint64) - signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) + signers, err := contracts.GetRewardForCheckpoint(c, chain, addr, number, rCheckpoint, client, totalSigner) + // signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) fmt.Println("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) From e526f6334a68d0424f8f8847861fbd5fdec95d72 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Wed, 2 Jan 2019 17:21:14 +0000 Subject: [PATCH 06/37] get blocksigner from cached --- consensus/posv/posv.go | 34 +++++++++++++++++++++++++++++++--- contracts/utils.go | 2 +- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 09f97207b6..cf397112e4 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -18,7 +18,9 @@ package posv import ( "bytes" +// "strings" "encoding/json" +// "encoding/hex" "errors" "fmt" "io/ioutil" @@ -30,6 +32,7 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts" + // "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" @@ -857,13 +860,38 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - var lAddr []common.Address + /* + abiJSON := `[{"inputs":[{"name":"_blockNumber","type":"uint256"},{"name":"_blockHash","type":"bytes32"}],"name":"sign","type":"function"}]` + abiReader, err := abi.JSON(strings.NewReader(abiJSON)) + if err != nil { + log.Error("Abi parser error", err) + } + + type Sign struct { + BlockNumber *big.Int + BlockHash common.Hash + } + var s Sign + */ + for _, tx := range txs { if tx.IsSigningTransaction() { - lAddr = append(lAddr, *tx.From()) + /* + err = abiReader.Unpack(&s, "sign", tx.Data()) + if err != nil { + log.Error("Abi unpack error", err) + } + blkHash := s.BlockHash + */ + blkHash := tx.Data()[len(tx.Data())-32:] + + if cached, ok := c.BlockSigners.Get(blkHash); ok { + lAddr := cached.([]common.Address) + lAddr = append(lAddr, *tx.From()) + c.BlockSigners.Add(blkHash, lAddr) + } } } - c.BlockSigners.Add(header.Hash(), lAddr) if c.HookReward != nil && number%rCheckpoint == 0 { err, rewards := c.HookReward(chain, state, header) diff --git a/contracts/utils.go b/contracts/utils.go index c24f90c3b7..231eb48ea6 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -217,8 +217,8 @@ func GetSignersFromContract2(c *posv.Posv, addrBlockSigner common.Address, clien log.Error("Fail get instance of blockSigner", "error", err) return nil, err } - opts := new(bind.CallOpts) if caddrs, ok := c.GetBlockSigners().Get(blockHash); !ok { + opts := new(bind.CallOpts) addrs, err := blockSigner.GetSigners(opts, blockHash) if err != nil { log.Error("Fail get block signers", "error", err) From a210d7ad1453f179c27b7e438993d366e0219e84 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 04:15:20 +0000 Subject: [PATCH 07/37] remove case after use --- consensus/posv/posv.go | 60 ++++++++++++++++++++++-------------------- contracts/utils.go | 5 ++-- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index cf397112e4..7129c19475 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -18,9 +18,9 @@ package posv import ( "bytes" -// "strings" + // "strings" "encoding/json" -// "encoding/hex" + // "encoding/hex" "errors" "fmt" "io/ioutil" @@ -52,7 +52,7 @@ import ( const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory - blockSignersCacheLimit = 1800 + blockSignersCacheLimit = 3600 M2ByteLength = 4 ) @@ -860,36 +860,40 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - /* - abiJSON := `[{"inputs":[{"name":"_blockNumber","type":"uint256"},{"name":"_blockHash","type":"bytes32"}],"name":"sign","type":"function"}]` - abiReader, err := abi.JSON(strings.NewReader(abiJSON)) - if err != nil { - log.Error("Abi parser error", err) - } + /* + abiJSON := `[{"inputs":[{"name":"_blockNumber","type":"uint256"},{"name":"_blockHash","type":"bytes32"}],"name":"sign","type":"function"}]` + abiReader, err := abi.JSON(strings.NewReader(abiJSON)) + if err != nil { + log.Error("Abi parser error", err) + } - type Sign struct { - BlockNumber *big.Int - BlockHash common.Hash - } - var s Sign - */ + type Sign struct { + BlockNumber *big.Int + BlockHash common.Hash + } + var s Sign + */ for _, tx := range txs { if tx.IsSigningTransaction() { - /* - err = abiReader.Unpack(&s, "sign", tx.Data()) - if err != nil { - log.Error("Abi unpack error", err) - } - blkHash := s.BlockHash - */ - blkHash := tx.Data()[len(tx.Data())-32:] + /* + err = abiReader.Unpack(&s, "sign", tx.Data()) + if err != nil { + log.Error("Abi unpack error", err) + } + blkHash := s.BlockHash + */ + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + txHash := *tx.From() - if cached, ok := c.BlockSigners.Get(blkHash); ok { - lAddr := cached.([]common.Address) - lAddr = append(lAddr, *tx.From()) - c.BlockSigners.Add(blkHash, lAddr) - } + var lAddr []common.Address + if cached, ok := c.BlockSigners.Get(blkHash); ok { + lAddr = cached.([]common.Address) + lAddr = append(lAddr, txHash) + } else { + lAddr = []common.Address{txHash} + } + c.BlockSigners.Add(blkHash, lAddr) } } diff --git a/contracts/utils.go b/contracts/utils.go index 231eb48ea6..a11e4cdf42 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -217,8 +217,8 @@ func GetSignersFromContract2(c *posv.Posv, addrBlockSigner common.Address, clien log.Error("Fail get instance of blockSigner", "error", err) return nil, err } - if caddrs, ok := c.GetBlockSigners().Get(blockHash); !ok { - opts := new(bind.CallOpts) + if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || c.BlockSigners.Len() < 1800 { + opts := new(bind.CallOpts) addrs, err := blockSigner.GetSigners(opts, blockHash) if err != nil { log.Error("Fail get block signers", "error", err) @@ -226,6 +226,7 @@ func GetSignersFromContract2(c *posv.Posv, addrBlockSigner common.Address, clien } return addrs, nil } else { + c.BlockSigners.Remove(blockHash) return caddrs.([]common.Address), nil } return nil, nil From 752ac2b4264d1edf7b136c3e154b8866c738b541 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 05:04:26 +0000 Subject: [PATCH 08/37] clear redundant code --- contracts/utils.go | 107 +------------------- core/env_validator.go | 24 ----- core/runtime_validator.go | 205 -------------------------------------- eth/backend.go | 5 +- internal/ethapi/api.go | 4 +- 5 files changed, 7 insertions(+), 338 deletions(-) delete mode 100644 core/env_validator.go delete mode 100644 core/runtime_validator.go diff --git a/contracts/utils.go b/contracts/utils.go index a11e4cdf42..6df27772f2 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -42,7 +42,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -196,22 +195,7 @@ 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 GetSignersFromContract2(c *posv.Posv, addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) { +func GetSignersFromContract(c *posv.Posv, 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) @@ -338,7 +322,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign for i := startBlockNumber; i <= endBlockNumber; i++ { go func(i uint64) { block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) + addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) // addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) if err != nil { log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) @@ -414,18 +398,6 @@ func CalculateRewardForSigner(chainReward *big.Int, signers map[common.Address]* return resultSigners, nil } -// Get candidate owner by address. -func GetCandidatesOwnerBySigner2(vmenv *vm.EVM, signerAddr common.Address) common.Address { - owner := signerAddr - owner, err := core.GetCandidateOwner(signerAddr, vmenv) - if err != nil { - log.Error("Fail get candidate owner", "error", err) - return owner - } - - return owner -} - func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, signerAddr common.Address) common.Address { owner := signerAddr opts := new(bind.CallOpts) @@ -438,81 +410,6 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign return owner } -// Calculate reward for holders. -func CalculateRewardForHolders2(foudationWalletAddr common.Address, vmenv *vm.EVM, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { - rewards, err := GetRewardBalancesRate2(foudationWalletAddr, signer, calcReward, vmenv) - 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 GetRewardBalancesRate2(foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, vmenv *vm.EVM) (map[common.Address]*big.Int, error) { - owner := GetCandidatesOwnerBySigner2(vmenv, 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. - voters, err := core.GetVoters(masterAddr, vmenv) - if err != nil { - log.Error("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 { - voterCap, err := core.GetVoterCap(masterAddr, voteAddr, vmenv) - if err != nil { - log.Error("Fail to get vote capacity", "error", err) - return nil, 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()) - fmt.Println("Holders reward", "holders", string(jsonHolders), "master node", masterAddr.String()) - - return balances, nil -} - // 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) diff --git a/core/env_validator.go b/core/env_validator.go deleted file mode 100644 index aa62c3a913..0000000000 --- a/core/env_validator.go +++ /dev/null @@ -1,24 +0,0 @@ -package core - -import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/vm" -) - -func NewEnv(cfg *Config) *vm.EVM { - context := vm.Context{ - CanTransfer: CanTransfer, - Transfer: Transfer, - GetHash: func(uint64) common.Hash { return common.Hash{} }, - - Origin: cfg.Origin, - Coinbase: cfg.Coinbase, - BlockNumber: cfg.BlockNumber, - Time: cfg.Time, - Difficulty: cfg.Difficulty, - GasLimit: cfg.GasLimit, - GasPrice: cfg.GasPrice, - } - - return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) -} diff --git a/core/runtime_validator.go b/core/runtime_validator.go deleted file mode 100644 index f1f98dff63..0000000000 --- a/core/runtime_validator.go +++ /dev/null @@ -1,205 +0,0 @@ -package core - -import ( - "math" - "math/big" - "strings" - "time" - - "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/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/params" -) - -// Config is a basic type specifying certain configuration flags for running -// the EVM. -type Config struct { - ChainConfig *params.ChainConfig - Difficulty *big.Int - Origin common.Address - Coinbase common.Address - BlockNumber *big.Int - Time *big.Int - GasLimit uint64 - GasPrice *big.Int - Value *big.Int - Debug bool - EVMConfig vm.Config - - State *state.StateDB - GetHashFn func(n uint64) common.Hash -} - -var abiValidator = `[{"constant":false,"inputs":[{"name":"_candidate","type":"address"}],"name":"propose","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_candidate","type":"address"},{"name":"_cap","type":"uint256"}],"name":"unvote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getCandidates","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_blockNumber","type":"uint256"}],"name":"getWithdrawCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"getVoters","outputs":[{"name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getWithdrawBlockNumbers","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"},{"name":"_voter","type":"address"}],"name":"getVoterCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidates","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_blockNumber","type":"uint256"},{"name":"_index","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"getCandidateCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_candidate","type":"address"}],"name":"vote","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"candidateCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"voterWithdrawDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_candidate","type":"address"}],"name":"resign","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"getCandidateOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxValidatorNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"candidateWithdrawDelay","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_candidate","type":"address"}],"name":"isCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minCandidateCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minVoterCap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_candidates","type":"address[]"},{"name":"_caps","type":"uint256[]"},{"name":"_firstOwner","type":"address"},{"name":"_minCandidateCap","type":"uint256"},{"name":"_minVoterCap","type":"uint256"},{"name":"_maxValidatorNumber","type":"uint256"},{"name":"_candidateWithdrawDelay","type":"uint256"},{"name":"_voterWithdrawDelay","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_voter","type":"address"},{"indexed":false,"name":"_candidate","type":"address"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Vote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_voter","type":"address"},{"indexed":false,"name":"_candidate","type":"address"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Unvote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_owner","type":"address"},{"indexed":false,"name":"_candidate","type":"address"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Propose","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_owner","type":"address"},{"indexed":false,"name":"_candidate","type":"address"}],"name":"Resign","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_owner","type":"address"},{"indexed":false,"name":"_blockNumber","type":"uint256"},{"indexed":false,"name":"_cap","type":"uint256"}],"name":"Withdraw","type":"event"}]` - -// sets defaults on the config -func setDefaults(cfg *Config) { - if cfg.ChainConfig == nil { - cfg.ChainConfig = ¶ms.ChainConfig{ - ChainId: big.NewInt(1), - HomesteadBlock: new(big.Int), - DAOForkBlock: new(big.Int), - DAOForkSupport: false, - EIP150Block: new(big.Int), - EIP155Block: new(big.Int), - EIP158Block: new(big.Int), - } - } - - if cfg.Difficulty == nil { - cfg.Difficulty = new(big.Int) - } - if cfg.Time == nil { - cfg.Time = big.NewInt(time.Now().Unix()) - } - if cfg.GasLimit == 0 { - cfg.GasLimit = math.MaxUint64 - } - if cfg.GasPrice == nil { - cfg.GasPrice = new(big.Int) - } - if cfg.Value == nil { - cfg.Value = new(big.Int) - } - if cfg.BlockNumber == nil { - cfg.BlockNumber = new(big.Int) - } - if cfg.GetHashFn == nil { - cfg.GetHashFn = func(n uint64) common.Hash { - return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String()))) - } - } -} - -// Execute executes the code using the input as call data during the execution. -// It returns the EVM's return value, the new state and an error if it failed. -// -// Executes sets up a in memory, temporarily, environment for the execution of -// the given code. It makes sure that it's restored to it's original state afterwards. -/* -func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { - if cfg == nil { - cfg = new(Config) - } - setDefaults(cfg) - - if cfg.State == nil { - db, _ := ethdb.NewMemDatabase() - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) - } - var ( - address = common.StringToAddress("contract") - vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) - ) - cfg.State.CreateAccount(address) - // set the receiver's (the executing contract) code for execution. - cfg.State.SetCode(address, code) - // Call the code with the given configuration. - ret, _, err := vmenv.Call( - sender, - common.StringToAddress("contract"), - input, - cfg.GasLimit, - cfg.Value, - ) - - return ret, cfg.State, err -} -*/ -func NewRuntimeEVM(chainState *state.StateDB) *vm.EVM { - cfg := new(Config) - setDefaults(cfg) - db, _ := ethdb.NewMemDatabase() - cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) - - var ( - address = common.HexToAddress(common.MasternodeVotingSMC) - vmenv = NewEnv(cfg) - ) - cfg.State.CreateAccount(address) - code := chainState.GetCode(common.HexToAddress(common.MasternodeVotingSMC)) - cfg.State.SetCode(address, code) - - f := func(key, val common.Hash) bool { - cfg.State.SetState(address, key, val) - return true - } - chainState.ForEachStorage(common.HexToAddress(common.MasternodeVotingSMC), f) - - return vmenv -} - -func GetVoters(candidate common.Address, vmenv *vm.EVM) ([]common.Address, error) { - - abi, err := abi.JSON(strings.NewReader(abiValidator)) - getVoters, err := abi.Pack("getVoters", candidate) - - // Call the code with the given configuration. - voters, _, err := vmenv.Call( - vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), - common.HexToAddress(common.MasternodeVotingSMC), - getVoters, - math.MaxUint64, - new(big.Int), - ) - - ret := common.ExtractAddressFromBytes(voters) - - return ret, err -} - -func GetCandidateOwner(candidate common.Address, vmenv *vm.EVM) (common.Address, error) { - - abi, err := abi.JSON(strings.NewReader(abiValidator)) - getCandidateOwner, err := abi.Pack("getCandidateOwner", candidate) - - // Call the code with the given configuration. - ret, _, err := vmenv.Call( - vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), - common.HexToAddress(common.MasternodeVotingSMC), - getCandidateOwner, - math.MaxUint64, - new(big.Int), - ) - - return common.BytesToAddress(ret), err -} - -func GetCandidateCap(candidate common.Address, vmenv *vm.EVM) (*big.Int, error) { - - abi, err := abi.JSON(strings.NewReader(abiValidator)) - getCandidateCap, err := abi.Pack("getCandidateCap", candidate) - - // Call the code with the given configuration. - ret, _, err := vmenv.Call( - vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), - common.HexToAddress(common.MasternodeVotingSMC), - getCandidateCap, - math.MaxUint64, - new(big.Int), - ) - - return new(big.Int).SetBytes(ret), err -} - -func GetVoterCap(candidate common.Address, voter common.Address, vmenv *vm.EVM) (*big.Int, error) { - - abi, err := abi.JSON(strings.NewReader(abiValidator)) - getVoterCap, err := abi.Pack("getVoterCap", candidate, voter) - - // Call the code with the given configuration. - ret, _, err := vmenv.Call( - vm.AccountRef(common.HexToAddress(common.MasternodeVotingSMC)), - common.HexToAddress(common.MasternodeVotingSMC), - getVoterCap, - math.MaxUint64, - new(big.Int), - ) - - return new(big.Int).SetBytes(ret), err -} diff --git a/eth/backend.go b/eth/backend.go index 2f0b5fcd3c..d5ee7ab205 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -259,7 +259,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { for i := prevEpoc; i < blockNumberEpoc; i++ { blockHeader := chain.GetHeaderByNumber(i) if len(penSigners) > 0 { - signedMasternodes, err := contracts.GetSignersFromContract(blockSignerAddr, client, blockHeader.Hash()) + signedMasternodes, err := contracts.GetSignersFromContract(c, blockSignerAddr, client, blockHeader.Hash()) if err != nil { return nil, err } @@ -279,7 +279,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } } - log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) + // log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) + fmt.Println("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) return penSigners, nil } return []common.Address{}, nil diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f9ec6ad29a..2c009c5b90 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -865,15 +865,15 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx 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()) + signers, err = contracts.GetSignersFromContract(engine.(*posv.Posv), addrBlockSigner, client, b.Hash()) 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 { - engine := s.b.GetEngine() lastCheckpointNumber := rpc.BlockNumber(b.Number().Uint64() - (b.Number().Uint64() % s.b.ChainConfig().Posv.Epoch)) prevCheckpointBlock, _ := s.b.BlockByNumber(ctx, lastCheckpointNumber) if prevCheckpointBlock != nil { From 5a51506652511b8d548186204cd38b16701c5fa4 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 09:57:50 +0000 Subject: [PATCH 09/37] cache votercap --- common/types.go | 9 ++++ consensus/posv/posv.go | 54 +++++++++++----------- contracts/utils.go | 97 +++++++++++++++++++++++++++++---------- core/types/transaction.go | 38 +++++++++++++++ eth/backend.go | 4 +- 5 files changed, 146 insertions(+), 56 deletions(-) diff --git a/common/types.go b/common/types.go index 871700758e..ad06240675 100644 --- a/common/types.go +++ b/common/types.go @@ -35,6 +35,10 @@ const ( RandomizeSMC = "0x0000000000000000000000000000000000000090" FoudationAddr = "0x0000000000000000000000000000000000000068" TeamAddr = "0x0000000000000000000000000000000000000099" + VoteMethod = "0x6dd7d8ea" + UnvoteMethod = "0x02aa9be2" + ProposeMethod = "0x01267951" + ResignMethod = "0xae6e43f5" ) var ( @@ -45,6 +49,11 @@ var ( // Hash represents the 32 byte Keccak256 hash of arbitrary data. type Hash [HashLength]byte +type Vote struct { + Masternode Address + Voter Address +} + func BytesToHash(b []byte) Hash { var h Hash h.SetBytes(b) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 7129c19475..b196707201 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -53,6 +53,7 @@ import ( const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory blockSignersCacheLimit = 3600 + votingCacheLimit = 1500000 M2ByteLength = 4 ) @@ -228,7 +229,9 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields + EnableCache bool BlockSigners *lru.ARCCache + Votes *lru.ARCCache 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) @@ -245,6 +248,7 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { } // Allocate the snapshot caches and create the engine BlockSigners, _ := lru.NewARC(blockSignersCacheLimit) + Votes, _ := lru.NewARC(votingCacheLimit) recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySnapshots) validatorSignatures, _ := lru.NewARC(inmemorySnapshots) @@ -252,7 +256,9 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { return &Posv{ config: &conf, db: db, + EnableCache: false, BlockSigners: BlockSigners, + Votes: Votes, recents: recents, signatures: signatures, verifiedHeaders: verifiedHeaders, @@ -261,10 +267,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { } } -func (c *Posv) GetBlockSigners() *lru.ARCCache { - return c.BlockSigners -} - // Author implements consensus.Engine, returning the Ethereum address recovered // from the signature in the header's extra-data section. func (c *Posv) Author(header *types.Header) (common.Address, error) { @@ -860,42 +862,38 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - /* - abiJSON := `[{"inputs":[{"name":"_blockNumber","type":"uint256"},{"name":"_blockHash","type":"bytes32"}],"name":"sign","type":"function"}]` - abiReader, err := abi.JSON(strings.NewReader(abiJSON)) - if err != nil { - log.Error("Abi parser error", err) - } - - type Sign struct { - BlockNumber *big.Int - BlockHash common.Hash - } - var s Sign - */ - + start := time.Now() for _, tx := range txs { if tx.IsSigningTransaction() { - /* - err = abiReader.Unpack(&s, "sign", tx.Data()) - if err != nil { - log.Error("Abi unpack error", err) - } - blkHash := s.BlockHash - */ blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - txHash := *tx.From() + from := *tx.From() var lAddr []common.Address if cached, ok := c.BlockSigners.Get(blkHash); ok { lAddr = cached.([]common.Address) - lAddr = append(lAddr, txHash) + lAddr = append(lAddr, from) } else { - lAddr = []common.Address{txHash} + lAddr = []common.Address{from} } c.BlockSigners.Add(blkHash, lAddr) + } else { + + b, addr := tx.IsVotingTransaction() + if b && addr != nil { + var vote common.Vote + vote.Masternode = *addr + vote.Voter = *tx.From() + + c.Votes.Remove(vote) + } } } + fmt.Println("Time Calculate Cache", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) + + if !c.EnableCache && c.BlockSigners.Len() >= 1800 { + fmt.Println("EnableCache true") + c.EnableCache = true + } if c.HookReward != nil && number%rCheckpoint == 0 { err, rewards := c.HookReward(chain, state, header) diff --git a/contracts/utils.go b/contracts/utils.go index 6df27772f2..17059a6c8f 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -201,7 +201,7 @@ func GetSignersFromContract(c *posv.Posv, addrBlockSigner common.Address, client log.Error("Fail get instance of blockSigner", "error", err) return nil, err } - if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || c.BlockSigners.Len() < 1800 { + if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || !c.EnableCache { opts := new(bind.CallOpts) addrs, err := blockSigner.GetSigners(opts, blockHash) if err != nil { @@ -315,25 +315,14 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign if len(masternodes) > 0 { - var wg sync.WaitGroup - squeue := make(chan []common.Address, 1) - wg.Add(900) - - for i := startBlockNumber; i <= endBlockNumber; i++ { - go func(i uint64) { + if !c.EnableCache { + for i := startBlockNumber; i <= endBlockNumber; i++ { block := chain.GetHeaderByNumber(i) addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) - // addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) if err != nil { - log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - // return nil, err + log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) + return nil, err } - squeue <- addrs - }(i) - } - - fsigner := func() { - for addrs := range squeue { // Filter duplicate address. if len(addrs) > 0 { addrSigners := make(map[common.Address]bool) @@ -358,13 +347,60 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign *totalSigner++ } } - wg.Done() } + } else { + var wg sync.WaitGroup + squeue := make(chan []common.Address, 1) + wg.Add(900) + + for i := startBlockNumber; i <= endBlockNumber; i++ { + go func(i uint64) { + block := chain.GetHeaderByNumber(i) + addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) + // addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) + if err != nil { + log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) + // return nil, err + } + squeue <- addrs + }(i) + } + + fsigner := func() { + for addrs := range squeue { + // Filter duplicate address. + if len(addrs) > 0 { + addrSigners := make(map[common.Address]bool) + for _, masternode := range masternodes { + for _, addr := range addrs { + if addr == masternode { + if _, ok := addrSigners[addr]; !ok { + addrSigners[addr] = true + } + break + } + } + } + + for addr := range addrSigners { + _, exist := signers[addr] + if exist { + signers[addr].Sign++ + } else { + signers[addr] = &rewardLog{1, new(big.Int)} + } + *totalSigner++ + } + } + wg.Done() + } + } + + go fsigner() + + wg.Wait() } - - go fsigner() - - wg.Wait() + fmt.Println("c.BlockSigners.Len()", c.BlockSigners.Len()) fmt.Println("totalSigner", *totalSigner) } @@ -411,8 +447,8 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign } // 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(c *posv.Posv, foudationWalletAddr common.Address, validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { + rewards, err := GetRewardBalancesRate(c, foudationWalletAddr, signer, calcReward, validator) if err != nil { return err, nil } @@ -425,7 +461,7 @@ func CalculateRewardForHolders(foudationWalletAddr common.Address, validator *co } // 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) { +func GetRewardBalancesRate(c *posv.Posv, 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)) @@ -446,7 +482,18 @@ 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) + var vote common.Vote + var voterCap *big.Int + + vote.Masternode = masterAddr + vote.Voter = voteAddr + + if vCap, ok := c.Votes.Get(vote); ok { + voterCap = vCap.(*big.Int) + } else { + voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + c.Votes.Add(vote, voterCap) + } if err != nil { log.Error("Fail to get vote capacity", "error", err) return nil, err diff --git a/core/types/transaction.go b/core/types/transaction.go index d7c8c3086b..9bc42013b0 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -294,6 +294,44 @@ func (tx *Transaction) IsSigningTransaction() bool { return tx.To().String() == common.BlockSigners } +func (tx *Transaction) IsVotingTransaction() (bool, *common.Address) { + if tx.To() == nil { + return false, nil + } + b := (tx.To().String() == common.MasternodeVotingSMC) + + if !b { + return b, nil + } + + method := common.ToHex(tx.Data()[0:4]) + if b = (method == common.VoteMethod); b { + addr := tx.Data()[len(tx.Data())-20:] + m := common.BytesToAddress(addr) + return b, &m + } + + if b = (method == common.UnvoteMethod); b { + addr := tx.Data()[len(tx.Data())-32-20 : len(tx.Data())-32] + m := common.BytesToAddress(addr) + return b, &m + } + + if b = (method == common.ProposeMethod); b { + addr := tx.Data()[len(tx.Data())-20:] + m := common.BytesToAddress(addr) + return b, &m + } + + if b = (method == common.ResignMethod); b { + addr := tx.Data()[len(tx.Data())-20:] + m := common.BytesToAddress(addr) + return b, &m + } + + return b, nil +} + func (tx *Transaction) String() string { var from, to string if tx.data.V != nil { diff --git a/eth/backend.go b/eth/backend.go index d5ee7ab205..131bc88748 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -327,10 +327,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Add reward for coin holders. voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { - // vmenv := core.NewRuntimeEVM(state) for signer, calcReward := range rewardSigners { - err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) - // err, rewards := contracts.CalculateRewardForHolders2(foudationWalletAddr, vmenv, state, signer, calcReward) + err, rewards := contracts.CalculateRewardForHolders(c, foudationWalletAddr, validator, state, signer, calcReward) if err != nil { log.Crit("Fail to calculate reward for holders.", "error", err) } From 53861bdcfd507193c82969eccb928cd3cf6a330f Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 11:32:14 +0000 Subject: [PATCH 10/37] move ARC to normal cache --- consensus/posv/posv.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index b196707201..7c84ad88f2 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -230,8 +230,8 @@ type Posv struct { lock sync.RWMutex // Protects the signer fields EnableCache bool - BlockSigners *lru.ARCCache - Votes *lru.ARCCache + BlockSigners *lru.Cache + Votes *lru.Cache 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) @@ -862,7 +862,6 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - start := time.Now() for _, tx := range txs { if tx.IsSigningTransaction() { blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) @@ -888,7 +887,6 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } } - fmt.Println("Time Calculate Cache", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) if !c.EnableCache && c.BlockSigners.Len() >= 1800 { fmt.Println("EnableCache true") From d80f8f06126cf65315c99fc0f1462fd2a758115f Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 11:33:43 +0000 Subject: [PATCH 11/37] move ARC to normal cache --- consensus/posv/posv.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 7c84ad88f2..065d524322 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -247,8 +247,8 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { conf.Epoch = epochLength } // Allocate the snapshot caches and create the engine - BlockSigners, _ := lru.NewARC(blockSignersCacheLimit) - Votes, _ := lru.NewARC(votingCacheLimit) + BlockSigners, _ := lru.New(blockSignersCacheLimit) + Votes, _ := lru.New(votingCacheLimit) recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySnapshots) validatorSignatures, _ := lru.NewARC(inmemorySnapshots) From 2ce17e99b4efe933b03264359ef7ef7349237ffb Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 14:25:10 +0000 Subject: [PATCH 12/37] collect 2700 cache before enable read cache --- consensus/posv/posv.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 065d524322..cd62a5843d 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -888,8 +888,8 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } - if !c.EnableCache && c.BlockSigners.Len() >= 1800 { - fmt.Println("EnableCache true") + if !c.EnableCache && c.BlockSigners.Len() >= 2700 { + fmt.Println("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) c.EnableCache = true } From 885babf92d628d2877fc5966a97262e8378a016f Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 3 Jan 2019 15:11:59 +0000 Subject: [PATCH 13/37] not remove after read --- consensus/posv/posv.go | 10 +++++----- contracts/utils.go | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index cd62a5843d..4939b0708e 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -888,12 +888,12 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } - if !c.EnableCache && c.BlockSigners.Len() >= 2700 { - fmt.Println("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) - c.EnableCache = true - } - if c.HookReward != nil && number%rCheckpoint == 0 { + if !c.EnableCache && c.BlockSigners.Len() >= 2700 { + fmt.Println("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) + c.EnableCache = true + } + err, rewards := c.HookReward(chain, state, header) if err != nil { return nil, err diff --git a/contracts/utils.go b/contracts/utils.go index 17059a6c8f..fb63499e78 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -210,7 +210,6 @@ func GetSignersFromContract(c *posv.Posv, addrBlockSigner common.Address, client } return addrs, nil } else { - c.BlockSigners.Remove(blockHash) return caddrs.([]common.Address), nil } return nil, nil @@ -357,10 +356,8 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign go func(i uint64) { block := chain.GetHeaderByNumber(i) addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) - // addrs, err := GetSignersFromContract2(c, blockSignerAddr, client, block.Hash()) if err != nil { log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - // return nil, err } squeue <- addrs }(i) From 2ed47cf48e6c8ccb98721039a1ab6887975cbf4e Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 4 Jan 2019 04:11:34 +0000 Subject: [PATCH 14/37] improve cache size --- consensus/posv/posv.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 4939b0708e..6e0cfef64f 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -52,7 +52,7 @@ import ( const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory - blockSignersCacheLimit = 3600 + blockSignersCacheLimit = 36000 votingCacheLimit = 1500000 M2ByteLength = 4 ) @@ -889,10 +889,10 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } if c.HookReward != nil && number%rCheckpoint == 0 { - if !c.EnableCache && c.BlockSigners.Len() >= 2700 { - fmt.Println("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) - c.EnableCache = true - } + if !c.EnableCache && c.BlockSigners.Len() >= 2700 { + fmt.Println("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) + c.EnableCache = true + } err, rewards := c.HookReward(chain, state, header) if err != nil { From 3c7ced7e1e5d02d320112dfba65bd5e675764f3e Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 4 Jan 2019 09:42:41 +0000 Subject: [PATCH 15/37] check tx receipt status --- consensus/posv/posv.go | 13 +++++++++++++ contracts/utils.go | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 6e0cfef64f..7fd611fb85 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -867,6 +867,19 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) from := *tx.From() + var b uint + for _, r := range receipts { + if r.TxHash == tx.Hash() { + b = r.Status + break + } + } + + if b == types.ReceiptStatusFailed { + fmt.Println("Tx receipt status false") + continue + } + var lAddr []common.Address if cached, ok := c.BlockSigners.Get(blkHash); ok { lAddr = cached.([]common.Address) diff --git a/contracts/utils.go b/contracts/utils.go index fb63499e78..b42df94207 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -397,7 +397,6 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign wg.Wait() } - fmt.Println("c.BlockSigners.Len()", c.BlockSigners.Len()) fmt.Println("totalSigner", *totalSigner) } From b1ab315b19d3b8a4e9980bddea942a5f49644e00 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Sat, 5 Jan 2019 15:23:21 +0000 Subject: [PATCH 16/37] correct error log --- contracts/utils.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/utils.go b/contracts/utils.go index b42df94207..5901843347 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -488,12 +488,11 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas voterCap = vCap.(*big.Int) } else { voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + if err != nil { + log.Crit("Fail to get vote capacity", "error", err) + } c.Votes.Add(vote, voterCap) } - if err != nil { - log.Error("Fail to get vote capacity", "error", err) - return nil, err - } totalCap.Add(totalCap, voterCap) voterCaps[voteAddr] = voterCap From fe0eb4fc2139eb4f758c65ceedfb92ed226b3fca Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Sat, 5 Jan 2019 15:24:55 +0000 Subject: [PATCH 17/37] change log type --- contracts/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils.go b/contracts/utils.go index 5901843347..d35e86f1d5 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -467,7 +467,7 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas opts := new(bind.CallOpts) voters, err := validator.GetVoters(opts, masterAddr) if err != nil { - log.Error("Fail to get voters", "error", err) + log.Crit("Fail to get voters", "error", err) return nil, err } From ba4b904cf8c5ddf0371612499f35bffb99ca3dab Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Sun, 6 Jan 2019 20:21:21 +0700 Subject: [PATCH 18/37] rollback fix duplicate count reward --- miner/worker.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index a5d5167fb4..9baefbce40 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -612,12 +612,12 @@ func (self *worker) commitNewWork() { delete(self.possibleUncles, hash) } } + // Create the new block to seal with the consensus engine + if work.Block, err = self.engine.Finalize(self.chain, header, work.state, work.txs, uncles, work.receipts); err != nil { + log.Error("Failed to finalize block for sealing", "err", err) + return + } if atomic.LoadInt32(&self.mining) == 1 { - // Create the new block to seal with the consensus engine - if work.Block, err = self.engine.Finalize(self.chain, header, work.state, work.txs, uncles, work.receipts); err != nil { - log.Error("Failed to finalize block for sealing", "err", err) - return - } log.Info("Committing new block", "number", work.Block.Number(), "txs", work.tcount, "special txs", len(specialTxs), "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart))) self.unconfirmed.Shift(work.Block.NumberU64() - 1) self.lastParentBlockCommit = parent.Hash().Hex() From 00b49e91cf8243207c3d2ce0b3f6cde7f9dc4e0d Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Mon, 7 Jan 2019 02:50:25 +0000 Subject: [PATCH 19/37] add more logs to debug --- consensus/posv/posv.go | 3 ++- contracts/utils.go | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 7fd611fb85..cff6bf6c9c 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -876,7 +876,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } if b == types.ReceiptStatusFailed { - fmt.Println("Tx receipt status false") + fmt.Println("Tx receipt status false", tx.Hash().Hex()) continue } @@ -896,6 +896,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state vote.Masternode = *addr vote.Voter = *tx.From() + fmt.Println("Remove from Votes cache", vote.Masternode.String(), vote.Voter.String()) c.Votes.Remove(vote) } } diff --git a/contracts/utils.go b/contracts/utils.go index b42df94207..7a1a40389d 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -488,12 +488,12 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas voterCap = vCap.(*big.Int) } else { voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + if err != nil { + log.Crit("Fail to get vote capacity", "error", err) + } + fmt.Println("Add to Votes cache", vote.Masternode.String(), vote.Voter.String(), voterCap.String()) c.Votes.Add(vote, voterCap) } - if err != nil { - log.Error("Fail to get vote capacity", "error", err) - return nil, err - } totalCap.Add(totalCap, voterCap) voterCaps[voteAddr] = voterCap From 3aba8f4c26c7351cb435c3e5fc7c7d7246c2a895 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Mon, 7 Jan 2019 07:22:41 +0000 Subject: [PATCH 20/37] fix unit test --- consensus/posv/posv.go | 2 +- contracts/utils.go | 17 ++++++++++++----- contracts/validator/validator_test.go | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index cff6bf6c9c..d981050555 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -903,7 +903,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } if c.HookReward != nil && number%rCheckpoint == 0 { - if !c.EnableCache && c.BlockSigners.Len() >= 2700 { + if !c.EnableCache && uint64(c.BlockSigners.Len()) >= (rCheckpoint*3) { fmt.Println("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) c.EnableCache = true } diff --git a/contracts/utils.go b/contracts/utils.go index a91f6c2fc1..991f71bd6a 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -350,7 +350,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign } else { var wg sync.WaitGroup squeue := make(chan []common.Address, 1) - wg.Add(900) + wg.Add(int(rCheckpoint)) for i := startBlockNumber; i <= endBlockNumber; i++ { go func(i uint64) { @@ -484,15 +484,22 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas vote.Masternode = masterAddr vote.Voter = voteAddr - if vCap, ok := c.Votes.Get(vote); ok { - voterCap = vCap.(*big.Int) + if c != nil { + if vCap, ok := c.Votes.Get(vote); ok { + voterCap = vCap.(*big.Int) + } else { + voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + if err != nil { + log.Crit("Fail to get vote capacity", "error", err) + } + fmt.Println("Add to Votes cache", vote.Masternode.String(), vote.Voter.String(), voterCap.String()) + c.Votes.Add(vote, voterCap) + } } else { voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) if err != nil { log.Crit("Fail to get vote capacity", "error", err) } - fmt.Println("Add to Votes cache", vote.Masternode.String(), vote.Voter.String(), voterCap.String()) - c.Votes.Add(vote, voterCap) } totalCap.Add(totalCap, voterCap) diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index f3896db4b8..e5df78d42f 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -144,7 +144,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 := contracts.GetRewardBalancesRate(nil, foundationAddr, acc3Addr, totalReward, baseValidator) if err != nil { t.Error("Fail to get reward balances rate.", err) } From 65ff031f16062ab582a77735e99d1287d7623960 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Mon, 7 Jan 2019 07:30:47 +0000 Subject: [PATCH 21/37] fix tests unreachable code --- contracts/utils.go | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/utils.go b/contracts/utils.go index 991f71bd6a..5e353e2616 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -212,7 +212,6 @@ func GetSignersFromContract(c *posv.Posv, addrBlockSigner common.Address, client } else { return caddrs.([]common.Address), nil } - return nil, nil } // Get random from randomize contract. From b19694afe333222707a0d6cce4c4850fcd0bc2ad Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Mon, 7 Jan 2019 10:29:43 +0000 Subject: [PATCH 22/37] concurrent process txs --- consensus/posv/posv.go | 91 +++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index d981050555..c0cd72b3a6 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -18,9 +18,7 @@ package posv import ( "bytes" - // "strings" "encoding/json" - // "encoding/hex" "errors" "fmt" "io/ioutil" @@ -32,7 +30,6 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts" - // "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" @@ -862,45 +859,9 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - for _, tx := range txs { - if tx.IsSigningTransaction() { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - - var b uint - for _, r := range receipts { - if r.TxHash == tx.Hash() { - b = r.Status - break - } - } - - if b == types.ReceiptStatusFailed { - fmt.Println("Tx receipt status false", tx.Hash().Hex()) - continue - } - - var lAddr []common.Address - if cached, ok := c.BlockSigners.Get(blkHash); ok { - lAddr = cached.([]common.Address) - lAddr = append(lAddr, from) - } else { - lAddr = []common.Address{from} - } - c.BlockSigners.Add(blkHash, lAddr) - } else { - - b, addr := tx.IsVotingTransaction() - if b && addr != nil { - var vote common.Vote - vote.Masternode = *addr - vote.Voter = *tx.From() - - fmt.Println("Remove from Votes cache", vote.Masternode.String(), vote.Voter.String()) - c.Votes.Remove(vote) - } - } - } + start := time.Now() + _ = c.cacheData(txs, receipts) + fmt.Println("Time processed txs", len(txs), "time", common.PrettyDuration(time.Since(start))) if c.HookReward != nil && number%rCheckpoint == 0 { if !c.EnableCache && uint64(c.BlockSigners.Len()) >= (rCheckpoint*3) { @@ -1078,6 +1039,52 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea return masternodes } +func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) error { + for _, tx := range txs { + go func(tx *types.Transaction) error { + if tx.IsSigningTransaction() { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + + var b uint + for _, r := range receipts { + if r.TxHash == tx.Hash() { + b = r.Status + return nil + } + } + + if b == types.ReceiptStatusFailed { + fmt.Println("Tx receipt status false", tx.Hash().Hex()) + return nil + } + + var lAddr []common.Address + if cached, ok := c.BlockSigners.Get(blkHash); ok { + lAddr = cached.([]common.Address) + lAddr = append(lAddr, from) + } else { + lAddr = []common.Address{from} + } + c.BlockSigners.Add(blkHash, lAddr) + } else { + + b, addr := tx.IsVotingTransaction() + if b && addr != nil { + var vote common.Vote + vote.Masternode = *addr + vote.Voter = *tx.From() + + fmt.Println("Remove from Votes cache", vote.Masternode.String(), vote.Voter.String()) + c.Votes.Remove(vote) + } + } + return nil + }(tx) + } + return nil +} + // Extract validators from byte array. func RemovePenaltiesFromBlock(chain consensus.ChainReader, masternodes []common.Address, epochNumber uint64) []common.Address { if epochNumber <= 0 { From 177750f1e744185ab3b14069613f7814b8a9151a Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Mon, 7 Jan 2019 14:04:24 +0000 Subject: [PATCH 23/37] sync wait --- consensus/posv/posv.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index c0cd72b3a6..06f7bd85e2 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -1040,6 +1040,10 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea } func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) error { + var wg sync.WaitGroup + + wg.Add(len(txs)) + for _, tx := range txs { go func(tx *types.Transaction) error { if tx.IsSigningTransaction() { @@ -1050,12 +1054,14 @@ func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) er for _, r := range receipts { if r.TxHash == tx.Hash() { b = r.Status + wg.Done() return nil } } if b == types.ReceiptStatusFailed { fmt.Println("Tx receipt status false", tx.Hash().Hex()) + wg.Done() return nil } @@ -1079,9 +1085,12 @@ func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) er c.Votes.Remove(vote) } } + wg.Done() return nil }(tx) } + + wg.Wait() return nil } From b042f3ca8195d4eb654cc9ceba98e053356be7a6 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Tue, 8 Jan 2019 03:25:31 +0000 Subject: [PATCH 24/37] remove fmt print --- consensus/posv/posv.go | 19 ++++++++----------- contracts/utils.go | 3 +-- eth/backend.go | 9 +++------ 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 06f7bd85e2..b825c80f58 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -859,13 +859,11 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - start := time.Now() _ = c.cacheData(txs, receipts) - fmt.Println("Time processed txs", len(txs), "time", common.PrettyDuration(time.Since(start))) if c.HookReward != nil && number%rCheckpoint == 0 { if !c.EnableCache && uint64(c.BlockSigners.Len()) >= (rCheckpoint*3) { - fmt.Println("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) + log.Debug("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) c.EnableCache = true } @@ -1040,9 +1038,9 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea } func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) error { - var wg sync.WaitGroup + var wg sync.WaitGroup - wg.Add(len(txs)) + wg.Add(len(txs)) for _, tx := range txs { go func(tx *types.Transaction) error { @@ -1054,14 +1052,13 @@ func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) er for _, r := range receipts { if r.TxHash == tx.Hash() { b = r.Status - wg.Done() + wg.Done() return nil } } if b == types.ReceiptStatusFailed { - fmt.Println("Tx receipt status false", tx.Hash().Hex()) - wg.Done() + wg.Done() return nil } @@ -1081,16 +1078,16 @@ func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) er vote.Masternode = *addr vote.Voter = *tx.From() - fmt.Println("Remove from Votes cache", vote.Masternode.String(), vote.Voter.String()) + log.Debug("Remove from Votes cache", vote.Masternode.String(), vote.Voter.String()) c.Votes.Remove(vote) } } - wg.Done() + wg.Done() return nil }(tx) } - wg.Wait() + wg.Wait() return nil } diff --git a/contracts/utils.go b/contracts/utils.go index 5e353e2616..2c086f35ab 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -396,7 +396,6 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign wg.Wait() } - fmt.Println("totalSigner", *totalSigner) } log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber) @@ -491,7 +490,7 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas if err != nil { log.Crit("Fail to get vote capacity", "error", err) } - fmt.Println("Add to Votes cache", vote.Masternode.String(), vote.Voter.String(), voterCap.String()) + log.Debug("Add to Votes cache", vote.Masternode.String(), vote.Voter.String(), voterCap.String()) c.Votes.Add(vote, voterCap) } } else { diff --git a/eth/backend.go b/eth/backend.go index 131bc88748..e28231d2fb 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -279,8 +279,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } } - // log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) - fmt.Println("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) + log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) return penSigners, nil } return []common.Address{}, nil @@ -309,8 +308,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { totalSigner := new(uint64) signers, err := contracts.GetRewardForCheckpoint(c, chain, addr, number, rCheckpoint, client, totalSigner) - // signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) - fmt.Println("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) + 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) } @@ -336,8 +334,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } rewards["rewards"] = voterResults - // log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) - fmt.Println("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) + log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) } return nil, rewards } From 8bbd8eddc932c1dbe62888644b0521bb7ec4e6f8 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Tue, 8 Jan 2019 12:29:57 +0700 Subject: [PATCH 25/37] Update posv.go --- consensus/posv/posv.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index a6f0613954..f4d09ecd48 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -930,8 +930,7 @@ func (c *Posv) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan if limit := uint64(2); number < limit || seen > number-limit { // Only take into account the non-epoch blocks if number%c.config.Epoch != 0 { - log.Info("len(masternodes)", len(masternodes), "number", number, "limit", limit, "seen", seen, "recent", recent.String(), "snap.Recents", snap.Recents) - log.Info("Signed recently, must wait for others") + log.Info("Signed recently, must wait for others ", "len(masternodes)", len(masternodes), "number", number, "limit", limit, "seen", seen, "recent", recent.String(), "snap.Recents", snap.Recents) <-stop return nil, nil } From d8ac726f307a3fa8a29683fdf5f09f3d4fd754c4 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Tue, 8 Jan 2019 05:45:42 +0000 Subject: [PATCH 26/37] fix bug logging, async --- consensus/posv/posv.go | 81 ++++++++++++++++++------------------------ contracts/utils.go | 2 +- 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index b825c80f58..f075ddf3b6 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -862,8 +862,8 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state _ = c.cacheData(txs, receipts) if c.HookReward != nil && number%rCheckpoint == 0 { - if !c.EnableCache && uint64(c.BlockSigners.Len()) >= (rCheckpoint*3) { - log.Debug("EnableCache true c.BlockSigners.Len()", c.BlockSigners.Len()) + if !c.EnableCache && int(c.BlockSigners.Len()) >= int(rCheckpoint*3) { + log.Debug("EnableCache true c.BlockSigners.Len() ", "BlockSigners.Len", c.BlockSigners.Len()) c.EnableCache = true } @@ -1038,56 +1038,45 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea } func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) error { - var wg sync.WaitGroup - - wg.Add(len(txs)) - for _, tx := range txs { - go func(tx *types.Transaction) error { - if tx.IsSigningTransaction() { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() + if tx.IsSigningTransaction() { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() - var b uint - for _, r := range receipts { - if r.TxHash == tx.Hash() { - b = r.Status - wg.Done() - return nil - } - } - - if b == types.ReceiptStatusFailed { - wg.Done() - return nil - } - - var lAddr []common.Address - if cached, ok := c.BlockSigners.Get(blkHash); ok { - lAddr = cached.([]common.Address) - lAddr = append(lAddr, from) - } else { - lAddr = []common.Address{from} - } - c.BlockSigners.Add(blkHash, lAddr) - } else { - - b, addr := tx.IsVotingTransaction() - if b && addr != nil { - var vote common.Vote - vote.Masternode = *addr - vote.Voter = *tx.From() - - log.Debug("Remove from Votes cache", vote.Masternode.String(), vote.Voter.String()) - c.Votes.Remove(vote) + var b uint + for _, r := range receipts { + if r.TxHash == tx.Hash() { + b = r.Status + break } } - wg.Done() - return nil - }(tx) + + if b == types.ReceiptStatusFailed { + continue + } + + var lAddr []common.Address + if cached, ok := c.BlockSigners.Get(blkHash); ok { + lAddr = cached.([]common.Address) + lAddr = append(lAddr, from) + } else { + lAddr = []common.Address{from} + } + c.BlockSigners.Add(blkHash, lAddr) + } else { + + b, addr := tx.IsVotingTransaction() + if b && addr != nil { + var vote common.Vote + vote.Masternode = *addr + vote.Voter = *tx.From() + + log.Debug("Remove from Votes cache ", "Masternode", vote.Masternode.String(), "Voter", vote.Voter.String()) + c.Votes.Remove(vote) + } + } } - wg.Wait() return nil } diff --git a/contracts/utils.go b/contracts/utils.go index 2c086f35ab..af645d2f3b 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -490,7 +490,7 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas if err != nil { log.Crit("Fail to get vote capacity", "error", err) } - log.Debug("Add to Votes cache", vote.Masternode.String(), vote.Voter.String(), voterCap.String()) + log.Debug("Add to Votes cache ", "vote.Masternode", vote.Masternode.String(), "vote.Voter", vote.Voter.String(), "voterCap", voterCap.String()) c.Votes.Add(vote, voterCap) } } else { From 1c1b833815ed444e8b59c62c25e545ab6151602d Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Tue, 8 Jan 2019 15:40:36 +0000 Subject: [PATCH 27/37] fix vote/unvote in checkpoint issue --- consensus/posv/posv.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index f075ddf3b6..ff7e0bb231 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -859,8 +859,6 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - _ = c.cacheData(txs, receipts) - if c.HookReward != nil && number%rCheckpoint == 0 { if !c.EnableCache && int(c.BlockSigners.Len()) >= int(rCheckpoint*3) { log.Debug("EnableCache true c.BlockSigners.Len() ", "BlockSigners.Len", c.BlockSigners.Len()) @@ -882,6 +880,8 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } + _ = c.cacheData(txs, receipts) + // the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) From 4e9510e3bbf2c5b59bfc914efc1124af04058b86 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Wed, 9 Jan 2019 03:44:20 +0000 Subject: [PATCH 28/37] return when error --- contracts/utils.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/utils.go b/contracts/utils.go index af645d2f3b..60f1f103ac 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -85,7 +85,8 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m // Add tx signed to local tx pool. err = pool.AddLocal(txSigned) if err != nil { - log.Warn("Fail to add tx sign to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) + log.Error("Fail to add tx sign to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) + return err } // Create secret tx. @@ -114,6 +115,7 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m err = pool.AddLocal(txSigned) if err != nil { log.Error("Fail to add tx secret to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) + return err } // Put randomize key into chainDb. @@ -125,6 +127,7 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m randomizeKeyValue, err := chainDb.Get(randomizeKeyName) if err != nil { log.Error("Fail to get randomize key from state db.", "error", err) + return err } tx, err := BuildTxOpeningRandomize(nonce+1, common.HexToAddress(common.RandomizeSMC), randomizeKeyValue) @@ -141,6 +144,7 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m err = pool.AddLocal(txSigned) if err != nil { log.Error("Fail to add tx opening to local pool.", "error", err, "number", block.NumberU64(), "hash", block.Hash().Hex(), "from", account.Address, "nonce", nonce) + return err } // Clear randomize key in state db. From e9a3e7b887333401d742b087e2bab030417aefa2 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Wed, 9 Jan 2019 03:48:16 +0000 Subject: [PATCH 29/37] return when logs --- contracts/utils.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/utils.go b/contracts/utils.go index 60f1f103ac..d40ab6945f 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -223,15 +223,18 @@ 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) @@ -296,6 +299,7 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) intNumber, err := strconv.Atoi(decryptSecret) if err != nil { log.Error("Can not convert string to integer", "error", err) + return -1, err } random = int64(intNumber) } From 73efc02259ff9d1ae0bed8a5cc9a228ba1757f60 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Thu, 10 Jan 2019 09:50:45 +0000 Subject: [PATCH 30/37] refactor cache BlockSigners --- consensus/posv/posv.go | 52 ++++++------ contracts/utils.go | 112 +++++++++----------------- contracts/validator/validator_test.go | 2 +- eth/backend.go | 2 +- internal/ethapi/api.go | 2 +- 5 files changed, 66 insertions(+), 104 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index f38fb6932e..d30a4f2b32 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -50,7 +50,6 @@ import ( const ( inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory blockSignersCacheLimit = 36000 - votingCacheLimit = 1500000 M2ByteLength = 4 ) @@ -245,7 +244,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { } // Allocate the snapshot caches and create the engine BlockSigners, _ := lru.New(blockSignersCacheLimit) - Votes, _ := lru.New(votingCacheLimit) recents, _ := lru.NewARC(inmemorySnapshots) signatures, _ := lru.NewARC(inmemorySnapshots) validatorSignatures, _ := lru.NewARC(inmemorySnapshots) @@ -255,7 +253,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { db: db, EnableCache: false, BlockSigners: BlockSigners, - Votes: Votes, recents: recents, signatures: signatures, verifiedHeaders: verifiedHeaders, @@ -880,7 +877,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } - _ = c.cacheData(txs, receipts) + _ = c.cacheData(header, txs, receipts) // the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) @@ -1036,12 +1033,10 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea return masternodes } -func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) error { +func (c *Posv) cacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) error { + var signTxs []*types.Transaction for _, tx := range txs { if tx.IsSigningTransaction() { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - var b uint for _, r := range receipts { if r.TxHash == tx.Hash() { @@ -1054,31 +1049,34 @@ func (c *Posv) cacheData(txs []*types.Transaction, receipts []*types.Receipt) er continue } - var lAddr []common.Address - if cached, ok := c.BlockSigners.Get(blkHash); ok { - lAddr = cached.([]common.Address) - lAddr = append(lAddr, from) - } else { - lAddr = []common.Address{from} - } - c.BlockSigners.Add(blkHash, lAddr) - } else { - - b, addr := tx.IsVotingTransaction() - if b && addr != nil { - var vote common.Vote - vote.Masternode = *addr - vote.Voter = *tx.From() - - log.Debug("Remove from Votes cache ", "Masternode", vote.Masternode.String(), "Voter", vote.Voter.String()) - c.Votes.Remove(vote) - } + signTxs = append(signTxs, tx) } } + c.BlockSigners.Add(header.Hash(), signTxs) + return nil } +func (c *Posv) GetSignData(chain consensus.ChainReader, startBlockNumber uint64, endBlockNumber uint64) (map[common.Hash][]common.Address, error) { + data := make(map[common.Hash][]common.Address) + for i := startBlockNumber; i < chain.CurrentHeader().Number.Uint64(); i++ { + block := chain.GetHeaderByNumber(i) + + if signData, ok := c.BlockSigners.Get(block.Hash()); ok { + txs := signData.([]*types.Transaction) + for _, tx := range txs { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) + } + } else { + return nil, errors.New("Failed get blocksigners from cache") + } + } + return data, nil +} + // Extract validators from byte array. func RemovePenaltiesFromBlock(chain consensus.ChainReader, masternodes []common.Address, epochNumber uint64) []common.Address { if epochNumber <= 0 { diff --git a/contracts/utils.go b/contracts/utils.go index d40ab6945f..078a0b69be 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -199,23 +199,19 @@ func BuildTxOpeningRandomize(nonce uint64, randomizeAddr common.Address, randomi } // Get signers signed for blockNumber from blockSigner contract. -func GetSignersFromContract(c *posv.Posv, addrBlockSigner common.Address, client bind.ContractBackend, blockHash common.Hash) ([]common.Address, error) { +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 } - if caddrs, ok := c.BlockSigners.Get(blockHash); !ok || !c.EnableCache { - 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 - } else { - return caddrs.([]common.Address), nil + 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 } // Get random from randomize contract. @@ -324,7 +320,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign if !c.EnableCache { for i := startBlockNumber; i <= endBlockNumber; i++ { block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) + addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) if err != nil { log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) return nil, err @@ -355,54 +351,39 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign } } } else { - var wg sync.WaitGroup - squeue := make(chan []common.Address, 1) - wg.Add(int(rCheckpoint)) + data, err := c.GetSignData(chain, startBlockNumber, endBlockNumber) + if err != nil { + log.Crit("Fail to get signers from cache.", "endBlockNumber", startBlockNumber, "startBlockNumber", endBlockNumber) + } for i := startBlockNumber; i <= endBlockNumber; i++ { - go func(i uint64) { - block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(c, blockSignerAddr, client, block.Hash()) - if err != nil { - log.Crit("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - } - squeue <- addrs - }(i) - } - - fsigner := func() { - for addrs := range squeue { - // Filter duplicate address. - if len(addrs) > 0 { - addrSigners := make(map[common.Address]bool) - for _, masternode := range masternodes { - for _, addr := range addrs { - if addr == masternode { - if _, ok := addrSigners[addr]; !ok { - addrSigners[addr] = true - } - break + block := chain.GetHeaderByNumber(i) + addrs := data[block.Hash()] + // Filter duplicate address. + if len(addrs) > 0 { + addrSigners := make(map[common.Address]bool) + for _, masternode := range masternodes { + for _, addr := range addrs { + if addr == masternode { + if _, ok := addrSigners[addr]; !ok { + addrSigners[addr] = true } + break } } - - for addr := range addrSigners { - _, exist := signers[addr] - if exist { - signers[addr].Sign++ - } else { - signers[addr] = &rewardLog{1, new(big.Int)} - } - *totalSigner++ - } } - wg.Done() + + for addr := range addrSigners { + _, exist := signers[addr] + if exist { + signers[addr].Sign++ + } else { + signers[addr] = &rewardLog{1, new(big.Int)} + } + *totalSigner++ + } } } - - go fsigner() - - wg.Wait() } } @@ -450,7 +431,7 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign // Calculate reward for holders. func CalculateRewardForHolders(c *posv.Posv, foudationWalletAddr common.Address, validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { - rewards, err := GetRewardBalancesRate(c, foudationWalletAddr, signer, calcReward, validator) + rewards, err := GetRewardBalancesRate(foudationWalletAddr, signer, calcReward, validator) if err != nil { return err, nil } @@ -463,7 +444,7 @@ func CalculateRewardForHolders(c *posv.Posv, foudationWalletAddr common.Address, } // Get reward balance rates for master node, founder and holders. -func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, masterAddr common.Address, totalReward *big.Int, validator *contractValidator.TomoValidator) (map[common.Address]*big.Int, error) { +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)) @@ -484,28 +465,11 @@ func GetRewardBalancesRate(c *posv.Posv, foudationWalletAddr common.Address, mas // Get voters capacities. voterCaps := make(map[common.Address]*big.Int) for _, voteAddr := range voters { - var vote common.Vote var voterCap *big.Int - vote.Masternode = masterAddr - vote.Voter = voteAddr - - if c != nil { - if vCap, ok := c.Votes.Get(vote); ok { - voterCap = vCap.(*big.Int) - } else { - voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) - if err != nil { - log.Crit("Fail to get vote capacity", "error", err) - } - log.Debug("Add to Votes cache ", "vote.Masternode", vote.Masternode.String(), "vote.Voter", vote.Voter.String(), "voterCap", voterCap.String()) - c.Votes.Add(vote, voterCap) - } - } else { - voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) - if err != nil { - log.Crit("Fail to get vote capacity", "error", err) - } + voterCap, err = validator.GetVoterCap(opts, masterAddr, voteAddr) + if err != nil { + log.Crit("Fail to get vote capacity", "error", err) } totalCap.Add(totalCap, voterCap) diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index e5df78d42f..f3896db4b8 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -144,7 +144,7 @@ func TestRewardBalance(t *testing.T) { foundationAddr := common.HexToAddress(common.FoudationAddr) totalReward := new(big.Int).SetInt64(15 * 1000) - rewards, err := contracts.GetRewardBalancesRate(nil, foundationAddr, acc3Addr, totalReward, baseValidator) + rewards, err := contracts.GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator) if err != nil { t.Error("Fail to get reward balances rate.", err) } diff --git a/eth/backend.go b/eth/backend.go index e28231d2fb..c3fe173fad 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -259,7 +259,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { for i := prevEpoc; i < blockNumberEpoc; i++ { blockHeader := chain.GetHeaderByNumber(i) if len(penSigners) > 0 { - signedMasternodes, err := contracts.GetSignersFromContract(c, blockSignerAddr, client, blockHeader.Hash()) + signedMasternodes, err := contracts.GetSignersFromContract(blockSignerAddr, client, blockHeader.Hash()) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2c009c5b90..a9a4c816fb 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -867,7 +867,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx if b.Number().Int64() > 0 { engine := s.b.GetEngine() addrBlockSigner := common.HexToAddress(common.BlockSigners) - signers, err = contracts.GetSignersFromContract(engine.(*posv.Posv), addrBlockSigner, client, b.Hash()) + signers, err = contracts.GetSignersFromContract(addrBlockSigner, client, b.Hash()) if err != nil { log.Error("Fail to get signers from block signer SC.", "error", err) return nil, err From e50c789c77eb28d06815b77a45c225e85d745d0f Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 11 Jan 2019 04:58:10 +0000 Subject: [PATCH 31/37] move cache data to insert func --- consensus/posv/posv.go | 7 ++++--- contracts/utils.go | 2 +- core/blockchain.go | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index d30a4f2b32..893edca3e8 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -877,7 +877,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } - _ = c.cacheData(header, txs, receipts) + // _ = c.cacheData(header, txs, receipts) // the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) @@ -1033,7 +1033,7 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea return masternodes } -func (c *Posv) cacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) error { +func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) error { var signTxs []*types.Transaction for _, tx := range txs { if tx.IsSigningTransaction() { @@ -1054,6 +1054,7 @@ func (c *Posv) cacheData(header *types.Header, txs []*types.Transaction, receipt } c.BlockSigners.Add(header.Hash(), signTxs) + fmt.Println("Add cache BLockSigners", header.Hash().String(), len(signTxs), c.BlockSigners.Len()) return nil } @@ -1071,7 +1072,7 @@ func (c *Posv) GetSignData(chain consensus.ChainReader, startBlockNumber uint64, data[blkHash] = append(data[blkHash], from) } } else { - return nil, errors.New("Failed get blocksigners from cache") + return nil, errors.New("Failed get blocksigners from cache " + block.Hash().String() + " " + block.Number.String()) } } return data, nil diff --git a/contracts/utils.go b/contracts/utils.go index 078a0b69be..f085c7b8f3 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -353,7 +353,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign } else { data, err := c.GetSignData(chain, startBlockNumber, endBlockNumber) if err != nil { - log.Crit("Fail to get signers from cache.", "endBlockNumber", startBlockNumber, "startBlockNumber", endBlockNumber) + log.Crit("Fail to get signers from cache.", "startBlockNumber", startBlockNumber, "endBlockNumber", endBlockNumber, "error", err) } for i := startBlockNumber; i <= endBlockNumber; i++ { diff --git a/core/blockchain.go b/core/blockchain.go index 4d6c2cc011..5bd0a709be 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -506,6 +506,10 @@ func (bc *BlockChain) insert(block *types.Block) { } bc.currentBlock.Store(block) + // save cache BlockSigners + engine := bc.Engine().(*posv.Posv) + engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) + // If the block is better than our head or is on a different chain, force update heads if updateHeads { bc.hc.SetCurrentHeader(block.Header()) From 5e8df83303eaeb7987e16b6ce05e7958e4df3759 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 11 Jan 2019 07:00:46 +0000 Subject: [PATCH 32/37] read signing data from blocks --- consensus/posv/posv.go | 19 +------- contracts/utils.go | 102 ++++++++++++++++++++--------------------- 2 files changed, 53 insertions(+), 68 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 893edca3e8..fcf7d367fa 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -1059,23 +1059,8 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt return nil } -func (c *Posv) GetSignData(chain consensus.ChainReader, startBlockNumber uint64, endBlockNumber uint64) (map[common.Hash][]common.Address, error) { - data := make(map[common.Hash][]common.Address) - for i := startBlockNumber; i < chain.CurrentHeader().Number.Uint64(); i++ { - block := chain.GetHeaderByNumber(i) - - if signData, ok := c.BlockSigners.Get(block.Hash()); ok { - txs := signData.([]*types.Transaction) - for _, tx := range txs { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - data[blkHash] = append(data[blkHash], from) - } - } else { - return nil, errors.New("Failed get blocksigners from cache " + block.Hash().String() + " " + block.Number.String()) - } - } - return data, nil +func (c *Posv) GetDb() ethdb.Database { + return c.db } // Extract validators from byte array. diff --git a/contracts/utils.go b/contracts/utils.go index f085c7b8f3..e554caa659 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -317,71 +317,71 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign if len(masternodes) > 0 { - if !c.EnableCache { - for i := startBlockNumber; i <= endBlockNumber; i++ { - block := chain.GetHeaderByNumber(i) - addrs, err := GetSignersFromContract(blockSignerAddr, client, block.Hash()) - if err != nil { - log.Error("Fail to get signers from smartcontract.", "error", err, "blockNumber", i) - return nil, err + data := make(map[common.Hash][]common.Address) + for i := startBlockNumber; i <= chain.CurrentHeader().Number.Uint64(); i++ { + header := chain.GetHeaderByNumber(i) + + if signData, ok := c.BlockSigners.Get(header.Hash()); ok { + txs := signData.([]*types.Transaction) + for _, tx := range txs { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) } - // Filter duplicate address. - if len(addrs) > 0 { - addrSigners := make(map[common.Address]bool) - for _, masternode := range masternodes { - for _, addr := range addrs { - if addr == masternode { - if _, ok := addrSigners[addr]; !ok { - addrSigners[addr] = true - } + } else { + log.Info("Failed get from cached", "startBlock", startBlockNumber, "endBlock", endBlockNumber) + block := chain.GetBlock(header.Hash(), i) + txs := block.Transactions() + receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i) + + for _, tx := range txs { + if tx.IsSigningTransaction() { + var b uint + for _, r := range receipts { + if r.TxHash == tx.Hash() { + b = r.Status break } } - } - for addr := range addrSigners { - _, exist := signers[addr] - if exist { - signers[addr].Sign++ - } else { - signers[addr] = &rewardLog{1, new(big.Int)} + if b == types.ReceiptStatusFailed { + continue } - *totalSigner++ + + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) } } - } - } else { - data, err := c.GetSignData(chain, startBlockNumber, endBlockNumber) - if err != nil { - log.Crit("Fail to get signers from cache.", "startBlockNumber", startBlockNumber, "endBlockNumber", endBlockNumber, "error", err) - } - for i := startBlockNumber; i <= endBlockNumber; i++ { - block := chain.GetHeaderByNumber(i) - addrs := data[block.Hash()] - // Filter duplicate address. - if len(addrs) > 0 { - addrSigners := make(map[common.Address]bool) - for _, masternode := range masternodes { - for _, addr := range addrs { - if addr == masternode { - if _, ok := addrSigners[addr]; !ok { - addrSigners[addr] = true - } - break + } + } + + for i := startBlockNumber; i <= endBlockNumber; i++ { + block := chain.GetHeaderByNumber(i) + addrs := data[block.Hash()] + // Filter duplicate address. + if len(addrs) > 0 { + addrSigners := make(map[common.Address]bool) + for _, masternode := range masternodes { + for _, addr := range addrs { + if addr == masternode { + if _, ok := addrSigners[addr]; !ok { + addrSigners[addr] = true } + break } } + } - for addr := range addrSigners { - _, exist := signers[addr] - if exist { - signers[addr].Sign++ - } else { - signers[addr] = &rewardLog{1, new(big.Int)} - } - *totalSigner++ + for addr := range addrSigners { + _, exist := signers[addr] + if exist { + signers[addr].Sign++ + } else { + signers[addr] = &rewardLog{1, new(big.Int)} } + *totalSigner++ } } } From f9ae05c5d5b78a067f163a291e2c51e11a4a26d6 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 11 Jan 2019 07:42:30 +0000 Subject: [PATCH 33/37] cache all after 1 epoch --- consensus/posv/posv.go | 12 ++---------- contracts/utils.go | 9 ++++++--- core/blockchain.go | 4 ---- eth/backend.go | 4 +--- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index fcf7d367fa..dd740ce6b5 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -225,7 +225,6 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields - EnableCache bool BlockSigners *lru.Cache Votes *lru.Cache HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) @@ -251,7 +250,6 @@ func New(config *params.PosvConfig, db ethdb.Database) *Posv { return &Posv{ config: &conf, db: db, - EnableCache: false, BlockSigners: BlockSigners, recents: recents, signatures: signatures, @@ -856,12 +854,9 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - if c.HookReward != nil && number%rCheckpoint == 0 { - if !c.EnableCache && int(c.BlockSigners.Len()) >= int(rCheckpoint*3) { - log.Debug("EnableCache true c.BlockSigners.Len() ", "BlockSigners.Len", c.BlockSigners.Len()) - c.EnableCache = true - } + _ = c.CacheData(header, txs, receipts) + if c.HookReward != nil && number%rCheckpoint == 0 { err, rewards := c.HookReward(chain, state, header) if err != nil { return nil, err @@ -877,8 +872,6 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state } } - // _ = c.cacheData(header, txs, receipts) - // the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) @@ -1054,7 +1047,6 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt } c.BlockSigners.Add(header.Hash(), signTxs) - fmt.Println("Add cache BLockSigners", header.Hash().String(), len(signTxs), c.BlockSigners.Len()) return nil } diff --git a/contracts/utils.go b/contracts/utils.go index e554caa659..9fb2203be3 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -306,7 +306,7 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) } // Calculate reward for reward checkpoint. -func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSignerAddr common.Address, number uint64, rCheckpoint uint64, client bind.ContractBackend, totalSigner *uint64) (map[common.Address]*rewardLog, error) { +func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, number uint64, rCheckpoint uint64, totalSigner *uint64) (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,7 +318,7 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign if len(masternodes) > 0 { data := make(map[common.Hash][]common.Address) - for i := startBlockNumber; i <= chain.CurrentHeader().Number.Uint64(); i++ { + for i := startBlockNumber; i <= prevCheckpoint+(rCheckpoint*2)-1; i++ { header := chain.GetHeaderByNumber(i) if signData, ok := c.BlockSigners.Get(header.Hash()); ok { @@ -329,11 +329,12 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign data[blkHash] = append(data[blkHash], from) } } else { - log.Info("Failed get from cached", "startBlock", startBlockNumber, "endBlock", endBlockNumber) + log.Info("Failed get from cached", "hash", header.Hash().String(), "number", i) block := chain.GetBlock(header.Hash(), i) txs := block.Transactions() receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i) + var signTxs []*types.Transaction for _, tx := range txs { if tx.IsSigningTransaction() { var b uint @@ -348,11 +349,13 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, blockSign continue } + signTxs = append(signTxs, tx) blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) from := *tx.From() data[blkHash] = append(data[blkHash], from) } } + c.BlockSigners.Add(header.Hash(), signTxs) } } diff --git a/core/blockchain.go b/core/blockchain.go index 5bd0a709be..4d6c2cc011 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -506,10 +506,6 @@ func (bc *BlockChain) insert(block *types.Block) { } bc.currentBlock.Store(block) - // save cache BlockSigners - engine := bc.Engine().(*posv.Posv) - engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) - // If the block is better than our head or is on a different chain, force update heads if updateHeads { bc.hc.SetCurrentHeader(block.Header()) diff --git a/eth/backend.go b/eth/backend.go index c3fe173fad..6fb12e0897 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -300,14 +300,12 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { rewards := make(map[string]interface{}) if number > 0 && number-rCheckpoint > 0 && foudationWalletAddr != (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(c, chain, addr, number, rCheckpoint, client, totalSigner) + 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) From 46c96249bf3b9d8cb806762319f723cf7247c249 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 11 Jan 2019 10:55:02 +0000 Subject: [PATCH 34/37] cache only blocksigners --- consensus/posv/posv.go | 1 - contracts/utils.go | 34 ++++++++++++++++------------------ eth/backend.go | 2 +- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index dd740ce6b5..ef4b2ae1d0 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -226,7 +226,6 @@ type Posv struct { lock sync.RWMutex // Protects the signer fields BlockSigners *lru.Cache - Votes *lru.Cache 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) diff --git a/contracts/utils.go b/contracts/utils.go index 9fb2203be3..bdfde9828c 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -329,31 +329,29 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, number ui data[blkHash] = append(data[blkHash], from) } } else { - log.Info("Failed get from cached", "hash", header.Hash().String(), "number", i) + log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i) block := chain.GetBlock(header.Hash(), i) txs := block.Transactions() receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i) var signTxs []*types.Transaction for _, tx := range txs { - if tx.IsSigningTransaction() { - var b uint - for _, r := range receipts { - if r.TxHash == tx.Hash() { - b = r.Status - break - } + var b uint + for _, r := range receipts { + if r.TxHash == tx.Hash() { + b = r.Status + break } - - if b == types.ReceiptStatusFailed { - continue - } - - signTxs = append(signTxs, tx) - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - data[blkHash] = append(data[blkHash], from) } + + if b == types.ReceiptStatusFailed { + continue + } + + signTxs = append(signTxs, tx) + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) } c.BlockSigners.Add(header.Hash(), signTxs) @@ -433,7 +431,7 @@ func GetCandidatesOwnerBySigner(validator *contractValidator.TomoValidator, sign } // Calculate reward for holders. -func CalculateRewardForHolders(c *posv.Posv, foudationWalletAddr common.Address, validator *contractValidator.TomoValidator, state *state.StateDB, signer common.Address, calcReward *big.Int) (error, map[common.Address]*big.Int) { +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) if err != nil { return err, nil diff --git a/eth/backend.go b/eth/backend.go index 6fb12e0897..e990093a89 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -324,7 +324,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { for signer, calcReward := range rewardSigners { - err, rewards := contracts.CalculateRewardForHolders(c, foudationWalletAddr, validator, state, signer, calcReward) + err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) if err != nil { log.Crit("Fail to calculate reward for holders.", "error", err) } From cd81c5c8b6d7d38dc13117260b7a390a25595a63 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 11 Jan 2019 15:32:48 +0000 Subject: [PATCH 35/37] move cache to insert func --- consensus/posv/posv.go | 3 ++- core/blockchain.go | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index ef4b2ae1d0..2dccf1cd37 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -853,7 +853,7 @@ func (c *Posv) Finalize(chain consensus.ChainReader, header *types.Header, state number := header.Number.Uint64() rCheckpoint := chain.Config().Posv.RewardCheckpoint - _ = c.CacheData(header, txs, receipts) + // _ = c.CacheData(header, txs, receipts) if c.HookReward != nil && number%rCheckpoint == 0 { err, rewards := c.HookReward(chain, state, header) @@ -1045,6 +1045,7 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt } } + log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs)) c.BlockSigners.Add(header.Hash(), signTxs) return nil diff --git a/core/blockchain.go b/core/blockchain.go index 4d6c2cc011..5bd0a709be 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -506,6 +506,10 @@ func (bc *BlockChain) insert(block *types.Block) { } bc.currentBlock.Store(block) + // save cache BlockSigners + engine := bc.Engine().(*posv.Posv) + engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) + // If the block is better than our head or is on a different chain, force update heads if updateHeads { bc.hc.SetCurrentHeader(block.Header()) From 381864d869a2c53f9f2d01ab810db4a757692e32 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Fri, 11 Jan 2019 17:14:12 +0000 Subject: [PATCH 36/37] verify signing tx --- common/types.go | 1 + contracts/utils.go | 28 +++++++++++++++------------- core/types/transaction.go | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/common/types.go b/common/types.go index ad06240675..6a7be73c98 100644 --- a/common/types.go +++ b/common/types.go @@ -39,6 +39,7 @@ const ( UnvoteMethod = "0x02aa9be2" ProposeMethod = "0x01267951" ResignMethod = "0xae6e43f5" + SignMethod = "0xe341eaa4" ) var ( diff --git a/contracts/utils.go b/contracts/utils.go index bdfde9828c..d48207e200 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -336,22 +336,24 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, number ui var signTxs []*types.Transaction for _, tx := range txs { - var b uint - for _, r := range receipts { - if r.TxHash == tx.Hash() { - b = r.Status - break + if tx.IsSigningTransaction() { + var b uint + for _, r := range receipts { + if r.TxHash == tx.Hash() { + b = r.Status + break + } } - } - if b == types.ReceiptStatusFailed { - continue - } + if b == types.ReceiptStatusFailed { + continue + } - signTxs = append(signTxs, tx) - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - data[blkHash] = append(data[blkHash], from) + signTxs = append(signTxs, tx) + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) + } } c.BlockSigners.Add(header.Hash(), signTxs) diff --git a/core/types/transaction.go b/core/types/transaction.go index 9bc42013b0..339e3562f5 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -291,7 +291,22 @@ func (tx *Transaction) IsSigningTransaction() bool { if tx.To() == nil { return false } - return tx.To().String() == common.BlockSigners + + if tx.To().String() != common.BlockSigners { + return false + } + + method := common.ToHex(tx.Data()[0:4]) + + if method != common.SignMethod { + return false + } + + if len(tx.Data()) != (32*2 + 4) { + return false + } + + return true } func (tx *Transaction) IsVotingTransaction() (bool, *common.Address) { From f8ab12876c4c1857778186972ae0c51d38caf5e5 Mon Sep 17 00:00:00 2001 From: Nguyen Sy Thanh Son Date: Sat, 12 Jan 2019 04:57:34 +0000 Subject: [PATCH 37/37] fix unittest --- core/blockchain.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 5bd0a709be..2f0dc16531 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -507,8 +507,10 @@ func (bc *BlockChain) insert(block *types.Block) { bc.currentBlock.Store(block) // save cache BlockSigners - engine := bc.Engine().(*posv.Posv) - engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) + if bc.chainConfig.Posv != nil { + engine := bc.Engine().(*posv.Posv) + engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) + } // If the block is better than our head or is on a different chain, force update heads if updateHeads {