From 745af2576c1b734de74fff2c641a8fbc541fb380 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Fri, 25 Aug 2023 21:08:28 +0800 Subject: [PATCH 01/12] Refactor system transactions --- consensus/clique/clique.go | 9 +- consensus/consensus.go | 8 +- consensus/ethash/consensus.go | 11 +- consensus/hotstuff/backend/backend.go | 3 - consensus/hotstuff/backend/economic.go | 2 +- consensus/hotstuff/backend/engine.go | 100 ++++++++------ consensus/hotstuff/backend/governance.go | 83 +++++------- consensus/hotstuff/backend/utils.go | 161 +---------------------- core/state_processor.go | 55 ++++---- 9 files changed, 140 insertions(+), 292 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index b03c636d..eddfc8dd 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -568,14 +568,19 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. -func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs *[]*types.Transaction, - uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, usedGas *uint64) error { +func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, uncles []*types.Header) error { // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) return nil } +// Filter out system transactions from common transactions +func (c *Clique) BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, + func(*types.Transaction, *big.Int) types.Message, error) { + return block.Transactions(), nil, nil, nil +} + // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // nor block rewards given, and returns the final block. func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, diff --git a/consensus/consensus.go b/consensus/consensus.go index 3b83923c..6bfb94c0 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -96,13 +96,17 @@ type Engine interface { // rules of a particular engine. The changes are executed inline. Prepare(chain ChainHeaderReader, header *types.Header) error + // Filter out system transactions from common transactions + // returns common transactions, system transactions and system transaction message provider + BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, + func(*types.Transaction, *big.Int) types.Message, error) + // Finalize runs any post-transaction state modifications (e.g. block rewards) // but does not assemble the block. // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). - Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs *[]*types.Transaction, - uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, usedGas *uint64) error + Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, uncles []*types.Header) error // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block // rewards) and assembles the final block. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 6b0d72c3..e2e9832c 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -586,20 +586,25 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H // Finalize implements consensus.Engine, accumulating the block and uncle rewards, // setting the final state on the header -func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs *[]*types.Transaction, - uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, usedGas *uint64) error { +func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, uncles []*types.Header) error { // Accumulate any block and uncle rewards and commit the final state root accumulateRewards(chain.Config(), state, header, uncles) header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) return nil } +// Filter out system transactions from common transactions +func (ethash *Ethash) BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, + func(*types.Transaction, *big.Int) types.Message, error) { + return block.Transactions(), nil, nil, nil +} + // FinalizeAndAssemble implements consensus.Engine, accumulating the block and // uncle rewards, setting the final state and assembling the block. func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, []*types.Receipt, error) { - ethash.Finalize(chain, header, state, &txs, uncles, nil, nil, nil) + ethash.Finalize(chain, header, state, uncles) // Header seems complete, assemble into a block and return return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), receipts, nil diff --git a/consensus/hotstuff/backend/backend.go b/consensus/hotstuff/backend/backend.go index beae5e38..79192b61 100644 --- a/consensus/hotstuff/backend/backend.go +++ b/consensus/hotstuff/backend/backend.go @@ -69,7 +69,6 @@ type backend struct { currentBlock func() *types.Block getBlockByHash func(hash common.Hash) *types.Block hasBadBlock func(db ethdb.Reader, hash common.Hash) bool - systemTxHook SystemTxFn } func New(chainConfig *params.ChainConfig, config *hotstuff.Config, privateKey *ecdsa.PrivateKey, db ethdb.Database, mock bool) *backend { @@ -92,10 +91,8 @@ func New(chainConfig *params.ChainConfig, config *hotstuff.Config, privateKey *e } if mock { - backend.systemTxHook = nil backend.core = core.New(backend, config, signer, db, nil) } else { - backend.systemTxHook = backend.executeSystemTxs backend.core = core.New(backend, config, signer, db, backend.CheckPoint) } diff --git a/consensus/hotstuff/backend/economic.go b/consensus/hotstuff/backend/economic.go index f6582a9d..e49b7857 100644 --- a/consensus/hotstuff/backend/economic.go +++ b/consensus/hotstuff/backend/economic.go @@ -55,7 +55,7 @@ func (s *backend) reward(state *state.StateDB, height *big.Int) error { // prepare for slashing... // todo(fuk): slash for governance func (s *backend) slash(ctx *systemTxContext) error { - return s.executeTransaction(ctx, contractAddr, nil) + return nil } func (s *backend) getRewardList(state *state.StateDB, height *big.Int) ([]*economic.RewardAmount, error) { diff --git a/consensus/hotstuff/backend/engine.go b/consensus/hotstuff/backend/engine.go index fd260303..8db4b97a 100644 --- a/consensus/hotstuff/backend/engine.go +++ b/consensus/hotstuff/backend/engine.go @@ -24,11 +24,15 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/hotstuff" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/contracts/native/utils" + "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/rpc" @@ -109,15 +113,47 @@ func (s *backend) Prepare(chain consensus.ChainHeaderReader, header *types.Heade return nil } -func (s *backend) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs *[]*types.Transaction, - uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, usedGas *uint64) error { +// Filter out system transactions from common transactions +func (s *backend) BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, + func(*types.Transaction, *big.Int) types.Message, error) { + systemTransactions, err := s.blockEndSystemTransactions(state, block.NumberU64()) + if err != nil { + return nil, nil, nil, err + } + allTransactions := block.Transactions() + commonTransactionCount := len(allTransactions) - len(systemTransactions) + if commonTransactionCount < 0 { + return nil, nil, nil, fmt.Errorf("missing required system transactions, count %v", len(systemTransactions)) + } - if s.HasSystemTxHook() { - if err := s.executeSystemTxs(chain, header, state, txs, receipts, systemTxs, usedGas, false); err != nil { - return err + signer := types.MakeSigner(s.chainConfig, block.Number()) + for i, tx := range systemTransactions { + includedTx := allTransactions[commonTransactionCount + i] + if includedTx.Hash() != tx.Hash() { + return nil, nil, nil, fmt.Errorf("unexpected system tx hash detected", "index", commonTransactionCount + i, "hash", includedTx.Hash(), "expected", tx.Hash()) + } + from, err := signer.Sender(includedTx) + if err != nil { + return nil, nil, nil, fmt.Errorf("check system tx signature failed, %w", err) + } + if from != block.Coinbase() { + return nil, nil, nil, fmt.Errorf("check system tx signature failed, wrong signer %s", from) } } + return allTransactions[:commonTransactionCount], systemTransactions, s.asSystemMessage, nil +} +// Change message from as valid system transaction sender +func(s *backend) asSystemMessage(tx *types.Transaction, baseFee *big.Int) types.Message { + gasPrice := new(big.Int).Set(tx.GasPrice()) + if baseFee != nil { + gasPrice = math.BigMin(gasPrice.Add(tx.GasTipCap(), baseFee), tx.GasFeeCap()) + } + return types.NewMessage(utils.SystemTxSender, tx.To(), tx.Nonce(), tx.Value(), tx.Gas(), gasPrice, + new(big.Int).Set(tx.GasFeeCap()), new(big.Int).Set(tx.GasTipCap()), tx.Data(), tx.AccessList(), true) +} + +func (s *backend) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, uncles []*types.Header) error { header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = nilUncleHash return nil @@ -134,10 +170,24 @@ func (s *backend) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header receipts = make([]*types.Receipt, 0) } - if s.HasSystemTxHook() { - if err := s.executeSystemTxs(chain, header, state, &txs, &receipts, nil, &header.GasUsed, true); err != nil { + systemTransantions, err := s.blockEndSystemTransactions(state, header.Number.Uint64()) + if err != nil { + return nil, nil, err + } + + for _, tx := range systemTransantions { + chainContext := chainContext{Chain: chain, engine: s} + gp := new(core.GasPool).AddGas(header.GasLimit) + if err := gp.SubGas(header.GasUsed); err != nil { + return nil, nil, err + } + state.Prepare(tx.Hash(), common.Hash{}, len(txs)) + receipt, err := core.ApplyTransactionWithCustomMessageProvider(s.asSystemMessage, s.chainConfig, chainContext, nil, gp, state, header, tx, &header.GasUsed, vm.Config{}) + if err != nil { return nil, nil, err } + txs = append(txs, tx) + receipts = append(receipts, receipt) } // Assemble and return the final block for sealing @@ -145,42 +195,6 @@ func (s *backend) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header return block, receipts, nil } -type SystemTxFn func(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs *[]*types.Transaction, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, usedGas *uint64, mining bool) error - -func (s *backend) HasSystemTxHook() bool { - return s.systemTxHook != nil -} - -// executeSystemTxs governance tx execution do not allow failure, the consensus will halt if tx failed and return error. -func (s *backend) executeSystemTxs(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, - txs *[]*types.Transaction, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, usedGas *uint64, mining bool) error { - - // genesis block DONT need to execute system transaction - if header.Number.Uint64() == 0 { - return nil - } - - if err := s.reward(state, header.Number); err != nil { - return err - } - - ctx := &systemTxContext{ - chain: chain, - state: state, - header: header, - chainCtx: chainContext{Chain: chain, engine: s}, - txs: txs, - sysTxs: systemTxs, - receipts: receipts, - usedGas: usedGas, - mining: mining, - } - if err := s.execEndBlock(ctx); err != nil { - return err - } - return s.execEpochChange(state, header, ctx) -} - func (s *backend) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) (err error) { // update the block header timestamp and signature and propose the block to core engine header := block.Header() diff --git a/consensus/hotstuff/backend/governance.go b/consensus/hotstuff/backend/governance.go index baf9e660..2697b4a6 100644 --- a/consensus/hotstuff/backend/governance.go +++ b/consensus/hotstuff/backend/governance.go @@ -21,6 +21,7 @@ package backend import ( "fmt" "sync/atomic" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" @@ -112,56 +113,43 @@ func (s *backend) Validators(height uint64, mining bool) hotstuff.ValidatorSet { return vals } -// IsSystemTransaction used by state processor while sync block. -func (s *backend) IsSystemTransaction(tx *types.Transaction, header *types.Header) (string, bool) { - // consider that tx is deploy transaction, so the tx.to will be nil - if tx == nil || len(tx.Data()) < 4 || tx.To() == nil { - return "", false - } - if *tx.To() != contractAddr { - return "", false - } - id := common.Bytes2Hex(tx.Data()[:4]) - if _, exist := specMethod[id]; !exist { - return id, false +func (s *backend) blockEndSystemTransactions(state *state.StateDB, height uint64) (types.Transactions, error) { + // Genesis block has no system transaction? + if height == 0 { + return nil, nil } - signer := types.MakeSigner(s.chainConfig, header.Number) - addr, err := signer.Sender(tx) - if err != nil { - return id, false - } - if header.Coinbase != addr { - return id, false - } else { - return id, true + var txs types.Transactions + systemSenderNonce := state.GetNonce(utils.SystemTxSender) + // SystemTransaction: NodeManager.EndBlock + { + payload, err := new(nm.EndBlockParam).Encode() + if err != nil { + return nil, err + } + txs = append(txs, types.NewTransaction(systemSenderNonce, utils.NodeManagerContractAddress, common.Big0, systemGas, big.NewInt(systemGasPrice), payload)) } -} - -// header height in front of state height -func (s *backend) execEpochChange(state *state.StateDB, header *types.Header, ctx *systemTxContext) error { - epoch, err := s.getGovernanceInfo(state) - if err != nil { - return err - } + // SystemTransaction: NodeManager.ChangeEpoch + { + epoch, err := s.getGovernanceInfo(state) + if err != nil { + return nil, err + } - end := epoch.EndHeight.Uint64() - height := header.Number.Uint64() - if height != end-1 { - return nil - } + if epoch == nil || epoch.EndHeight == nil { + return nil, fmt.Errorf("unexpected epoch or epoch end height missing") + } - payload, err := new(nm.ChangeEpochParam).Encode() - if err != nil { - return err - } - if err := s.executeTransaction(ctx, contractAddr, payload); err != nil { - return err + if height + 1 == epoch.EndHeight.Uint64() { + payload, err := new(nm.ChangeEpochParam).Encode() + if err != nil { + return nil, err + } + txs = append(txs, types.NewTransaction(systemSenderNonce + 1, utils.NodeManagerContractAddress, common.Big0, systemGas, big.NewInt(systemGasPrice), payload)) + } } - - log.Info("Execute governance EpochChange", "end", end, "current", height) - return nil + return txs, nil } // getGovernanceInfo call governance contract method and retrieve related info. @@ -173,15 +161,6 @@ func (s *backend) getGovernanceInfo(state *state.StateDB) (*nm.EpochInfo, error) return epoch, nil } -// execEndBlock execute governance contract method of `EndBlock` -func (s *backend) execEndBlock(ctx *systemTxContext) error { - payload, err := new(nm.EndBlockParam).Encode() - if err != nil { - return err - } - return s.executeTransaction(ctx, contractAddr, payload) -} - // getValidatorsByHeader check if current header height is an new epoch start and retrieve the validators. func (s *backend) getValidatorsByHeader(header, parent *types.Header, chain consensus.ChainHeaderReader) ( bool, hotstuff.ValidatorSet, error) { diff --git a/consensus/hotstuff/backend/utils.go b/consensus/hotstuff/backend/utils.go index 16c56d6a..16e9442c 100644 --- a/consensus/hotstuff/backend/utils.go +++ b/consensus/hotstuff/backend/utils.go @@ -19,12 +19,8 @@ package backend import ( - "bytes" - "encoding/hex" - "fmt" "math" "math/big" - "sync" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -36,9 +32,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/log" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" ) @@ -99,156 +92,13 @@ func (s *backend) getSystemCaller(state *state.StateDB, height *big.Int) *native return native.NewContractRef(state, caller, caller, height, hash, systemGas, nil) } -// applyTransaction execute transaction without miner worker, and only succeed tx will be packed in block. -func (s *backend) applyTransaction( - chain consensus.ChainHeaderReader, - msg callmsg, - state *state.StateDB, - header *types.Header, - chainContext core.ChainContext, - commonTxs *[]*types.Transaction, receipts *[]*types.Receipt, - sysTxs *[]*types.Transaction, usedGas *uint64, mining bool, -) (err error) { - - // check msg sender - if msg.From() != utils.SystemTxSender { - return fmt.Errorf("system tx sender invalid") - } - - nonce := state.GetNonce(msg.From()) - expectedTx := types.NewTransaction(nonce, *msg.To(), msg.Value(), msg.Gas(), msg.GasPrice(), msg.Data()) - signer := types.MakeSigner(chain.Config(), header.Number) - - // miner worker execute `finalizeAndAssemble` in which the param of `mining` is true, it's denote - // that this tx comes from miner, and `validator` send governance tx in the same nonce is forbidden. - // the sender of system tx is an unusual address, let the miner `signTx` to keep the signature in tx.Data - // which denote that the system tx is mined by some one validator. this tx and the `actual` tx which - // others sync node received should be compared and ensure that they are extreme the same. - if mining { - expectedTx, err = s.signer.SignTx(expectedTx, signer) - if err != nil { - return err - } - } else { - // system tx CAN'T be nil or empty - if sysTxs == nil || len(*sysTxs) == 0 || (*sysTxs)[0] == nil { - return fmt.Errorf("supposed to get a actual transaction, but get none") - } - - // check tx hash - actualTx := (*sysTxs)[0] - if expectedHash := signer.Hash(expectedTx); !bytes.Equal(signer.Hash(actualTx).Bytes(), expectedHash.Bytes()) { - return fmt.Errorf("expected tx hash %v, nonce %d, to %s, value %s, gas %d, gasPrice %s, data %s;"+ - "get tx hash %v, nonce %d, to %s, value %s, gas %d, gasPrice %s, data %s", - expectedHash.String(), - expectedTx.Nonce(), - expectedTx.To().String(), - expectedTx.Value().String(), - expectedTx.Gas(), - expectedTx.GasPrice().String(), - hex.EncodeToString(expectedTx.Data()), - actualTx.Hash().String(), - actualTx.Nonce(), - actualTx.To().String(), - actualTx.Value().String(), - actualTx.Gas(), - actualTx.GasPrice().String(), - hex.EncodeToString(actualTx.Data()), - ) - } - - // tx signature can be recovered and the sender should be equal to block `coinbase` - sender, err := signer.Sender(actualTx) - if err != nil { - return fmt.Errorf("recover system tx sender failed, err: %v", err) - } - if sender != header.Coinbase { - return fmt.Errorf("supposed to miner %s but got %s", header.Coinbase.Hex(), sender.Hex()) - } - - // reset tx and shift system tx list to next - expectedTx = actualTx - *sysTxs = (*sysTxs)[1:] - } - - // execute system tx and get the receipt - state.Prepare(expectedTx.Hash(), common.Hash{}, len(*commonTxs)) - gasUsed, err := applyMessage(msg, state, header, chain.Config(), chainContext) - if err != nil { - return err - } - *commonTxs = append(*commonTxs, expectedTx) - var root []byte - if chain.Config().IsByzantium(header.Number) { - state.Finalise(true) - } else { - root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)).Bytes() - } - *usedGas += gasUsed - receipt := types.NewReceipt(root, false, *usedGas) - receipt.TxHash = expectedTx.Hash() - receipt.GasUsed = gasUsed - - // set the receipt logs and create a bloom for filtering - receipt.Logs = state.GetLogs(expectedTx.Hash()) - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) - receipt.BlockHash = state.BlockHash() - receipt.BlockNumber = header.Number - receipt.TransactionIndex = uint(state.TxIndex()) - *receipts = append(*receipts, receipt) - state.SetNonce(msg.From(), nonce+1) - return nil -} - -// applyMessage -func applyMessage( - msg callmsg, - state *state.StateDB, - header *types.Header, - chainConfig *params.ChainConfig, - chainContext core.ChainContext, -) (uint64, error) { - // Create a new context to be used in the EVM environment - context := core.NewEVMBlockContext(header, chainContext, nil) - // Create a new environment which holds all relevant information - // about the transaction and calling mechanisms. - vmenv := vm.NewEVM(context, vm.TxContext{Origin: msg.From(), GasPrice: big.NewInt(0)}, state, chainConfig, vm.Config{}) - // Apply the transaction to the current state (included in the env) - ret, returnGas, err := vmenv.Call( - vm.AccountRef(msg.From()), - *msg.To(), - msg.Data(), - msg.Gas(), - msg.Value(), - ) - if err != nil { - log.Error("apply message failed", "msg", string(ret), "err", err) - } - return msg.Gas() - returnGas, err -} - func packBlock(state *state.StateDB, chain consensus.ChainHeaderReader, header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) *types.Block { - - var ( - block *types.Block - root common.Hash - ) - // perform root calculation and block reorganization at the same time which with a large number of memory copy. // and reset the header root after actions done. - wg := sync.WaitGroup{} - wg.Add(2) - go func() { - root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - wg.Done() - }() - go func() { - // the header uncle hash will be settle as EmptyUncleHash which as the same of `nilUncleHash` - block = types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) - wg.Done() - }() - wg.Wait() + root := state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + // the header uncle hash will be settle as EmptyUncleHash which as the same of `nilUncleHash` + block := types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) block.SetRoot(root) return block @@ -266,11 +116,6 @@ type systemTxContext struct { mining bool } -func (s *backend) executeTransaction(ctx *systemTxContext, contract common.Address, payload []byte) error { - msg := s.getSystemMessage(contract, payload, common.Big0) - return s.applyTransaction(ctx.chain, msg, ctx.state, ctx.header, ctx.chainCtx, ctx.txs, ctx.receipts, ctx.sysTxs, ctx.usedGas, ctx.mining) -} - func NewDefaultValSet(list []common.Address) hotstuff.ValidatorSet { return validator.NewSet(list, hotstuff.RoundRobin) } diff --git a/core/state_processor.go b/core/state_processor.go index 34fb19b9..a69cf221 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -18,6 +18,7 @@ package core import ( "fmt" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" @@ -70,24 +71,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg blockContext := NewEVMBlockContext(header, p.bc, nil) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) - // zion hotstuff consensus engine will add two tx for governance epoch change. - // separate the system tx and common tx before consensus `finalize` and assemble the - // tx and receipts again after `finalize` finished. - engine, isHotstuff := p.engine.(consensus.HotStuff) - txNum := len(block.Transactions()) - systemTxs := make([]*types.Transaction, 0, 2) - systemTxIds := make(map[string]int) - commonTxs := make([]*types.Transaction, 0, txNum) + // Sort out system transactions here to be handled after common transactions + commonTransactions, systemTransactions, asSystemMessage, err := p.engine.BlockTransactions(block, statedb) + if err != nil { + return nil, nil, 0, err + } // Iterate over and process the individual transactions - for i, tx := range block.Transactions() { - if isHotstuff { - if id, isSystemTx := engine.IsSystemTransaction(tx, block.Header()); isSystemTx { - systemTxs = append(systemTxs, tx) - systemTxIds[id] += 1 - continue - } - } + for i, tx := range commonTransactions { msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) if err != nil { return nil, nil, 0, err @@ -97,25 +88,21 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } - commonTxs = append(commonTxs, tx) receipts = append(receipts, receipt) } - // the number of system transaction in range of [1, 2] except genesis block. - // each system transaction can only be executed once in a single block. - if isHotstuff && engine.HasSystemTxHook() { - if length := len(systemTxs); (block.NumberU64() > 0 && length < 1) || length > 2 { - return nil, nil, 0, fmt.Errorf("system txs list length %d invalid", length) - } - for id, cnt := range systemTxIds { - if cnt > 1 { - return nil, nil, 0, fmt.Errorf("system tx %s dumplicated %d ", id, cnt) - } + for i, tx := range systemTransactions { + msg := asSystemMessage(tx, header.BaseFee) + statedb.Prepare(tx.Hash(), block.Hash(), len(commonTransactions) + i) + receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, header, tx, usedGas, vmenv) + if err != nil { + return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } + receipts = append(receipts, receipt) } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - if err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), &receipts, &systemTxs, usedGas); err != nil { + if err := p.engine.Finalize(p.bc, header, statedb, block.Uncles()); err != nil { return receipts, allLogs, *usedGas, err } @@ -185,3 +172,15 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv) } + +// ApplyTransaction attempts to apply a transaction to the given state database +// and uses the input parameters for its environment. It returns the receipt +// for the transaction, gas used and an error if the transaction failed, +// indicating the block was invalid. +func ApplyTransactionWithCustomMessageProvider(asMessage func(*types.Transaction, *big.Int) types.Message , config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { + msg := asMessage(tx, header.BaseFee) + // Create a new context to be used in the EVM environment + blockContext := NewEVMBlockContext(header, bc, author) + vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) + return applyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv) +} From 0307617556ba74be06f4613fd1b8c2cb3db849e8 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Fri, 25 Aug 2023 21:18:54 +0800 Subject: [PATCH 02/12] Small error fix --- consensus/clique/clique.go | 1 + consensus/ethash/consensus.go | 1 + consensus/hotstuff/backend/economic.go | 2 +- consensus/hotstuff/backend/engine.go | 3 +- consensus/hotstuff/backend/utils.go | 42 -------------------------- 5 files changed, 5 insertions(+), 44 deletions(-) diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index eddfc8dd..77450a71 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -576,6 +576,7 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade } // Filter out system transactions from common transactions +// returns common transactions, system transactions and system transaction message provider func (c *Clique) BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, func(*types.Transaction, *big.Int) types.Message, error) { return block.Transactions(), nil, nil, nil diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index e2e9832c..daa450b9 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -594,6 +594,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types. } // Filter out system transactions from common transactions +// returns common transactions, system transactions and system transaction message provider func (ethash *Ethash) BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, func(*types.Transaction, *big.Int) types.Message, error) { return block.Transactions(), nil, nil, nil diff --git a/consensus/hotstuff/backend/economic.go b/consensus/hotstuff/backend/economic.go index e49b7857..1539fdec 100644 --- a/consensus/hotstuff/backend/economic.go +++ b/consensus/hotstuff/backend/economic.go @@ -54,7 +54,7 @@ func (s *backend) reward(state *state.StateDB, height *big.Int) error { // prepare for slashing... // todo(fuk): slash for governance -func (s *backend) slash(ctx *systemTxContext) error { +func (s *backend) slash() error { return nil } diff --git a/consensus/hotstuff/backend/engine.go b/consensus/hotstuff/backend/engine.go index 8db4b97a..acebcb01 100644 --- a/consensus/hotstuff/backend/engine.go +++ b/consensus/hotstuff/backend/engine.go @@ -114,6 +114,7 @@ func (s *backend) Prepare(chain consensus.ChainHeaderReader, header *types.Heade } // Filter out system transactions from common transactions +// returns common transactions, system transactions and system transaction message provider func (s *backend) BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, func(*types.Transaction, *big.Int) types.Message, error) { systemTransactions, err := s.blockEndSystemTransactions(state, block.NumberU64()) @@ -130,7 +131,7 @@ func (s *backend) BlockTransactions(block *types.Block, state *state.StateDB) (t for i, tx := range systemTransactions { includedTx := allTransactions[commonTransactionCount + i] if includedTx.Hash() != tx.Hash() { - return nil, nil, nil, fmt.Errorf("unexpected system tx hash detected", "index", commonTransactionCount + i, "hash", includedTx.Hash(), "expected", tx.Hash()) + return nil, nil, nil, fmt.Errorf("unexpected system tx hash detected, tx index %v, hash %s, expected: %s", commonTransactionCount + i, includedTx.Hash(), tx.Hash()) } from, err := signer.Sender(includedTx) if err != nil { diff --git a/consensus/hotstuff/backend/utils.go b/consensus/hotstuff/backend/utils.go index 16e9442c..04cdf13d 100644 --- a/consensus/hotstuff/backend/utils.go +++ b/consensus/hotstuff/backend/utils.go @@ -22,14 +22,12 @@ import ( "math" "math/big" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/hotstuff" "github.com/ethereum/go-ethereum/consensus/hotstuff/validator" "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/utils" - "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/trie" @@ -37,20 +35,6 @@ import ( // =========================== utility function ========================== -// callmsg implements core.Message to allow passing it as a transaction simulator. -type callmsg struct { - ethereum.CallMsg -} - -func (m callmsg) From() common.Address { return m.CallMsg.From } -func (m callmsg) Nonce() uint64 { return 0 } -func (m callmsg) CheckNonce() bool { return false } -func (m callmsg) To() *common.Address { return m.CallMsg.To } -func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } -func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } -func (m callmsg) Value() *big.Int { return m.CallMsg.Value } -func (m callmsg) Data() []byte { return m.CallMsg.Data } - // chain context type chainContext struct { Chain consensus.ChainHeaderReader @@ -71,20 +55,6 @@ const ( systemGasPrice = int64(0) // consensus txs do not need to participate in gas price bidding ) -// getSystemMessage assemble system calling fields -func (s *backend) getSystemMessage(toAddress common.Address, data []byte, value *big.Int) callmsg { - return callmsg{ - ethereum.CallMsg{ - From: utils.SystemTxSender, - Gas: systemGas, - GasPrice: big.NewInt(systemGasPrice), - Value: value, - To: &toAddress, - Data: data, - }, - } -} - // getSystemCaller use fixed systemCaller as contract caller, and tx hash is useless in contract call. func (s *backend) getSystemCaller(state *state.StateDB, height *big.Int) *native.ContractRef { caller := utils.SystemTxSender @@ -104,18 +74,6 @@ func packBlock(state *state.StateDB, chain consensus.ChainHeaderReader, return block } -type systemTxContext struct { - chain consensus.ChainHeaderReader - state *state.StateDB - header *types.Header - chainCtx core.ChainContext - txs *[]*types.Transaction - sysTxs *[]*types.Transaction - receipts *[]*types.Receipt - usedGas *uint64 - mining bool -} - func NewDefaultValSet(list []common.Address) hotstuff.ValidatorSet { return validator.NewSet(list, hotstuff.RoundRobin) } From 1954a7c64fa434a8ac9838a9fb23787381c515ce Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Sat, 26 Aug 2023 11:54:01 +0800 Subject: [PATCH 03/12] Refactor damn stuff --- consensus/hotstuff/backend/economic.go | 77 --------- consensus/hotstuff/backend/engine.go | 10 +- consensus/hotstuff/backend/governance.go | 54 +------ consensus/hotstuff/backend/utils.go | 17 -- .../cross_chain_manager/entrance_test.go | 3 +- contracts/native/economic/economic.go | 48 +++++- contracts/native/economic/economic_test.go | 5 +- .../native/governance/community/state.go | 153 ++++++++++++++++++ contracts/native/governance/entrance.go | 67 ++++++++ .../governance/node_manager/distribute.go | 62 +++---- .../governance/node_manager/external.go | 18 +-- .../native/governance/node_manager/hooks.go | 15 +- .../native/governance/node_manager/manager.go | 42 +++-- .../governance/node_manager/manager_test.go | 11 +- .../native/governance/node_manager/stake.go | 8 +- .../native/governance/node_manager/storage.go | 80 ++------- .../native/governance/node_manager/types.go | 41 ++--- .../proposal_manager/proposal_manager.go | 12 +- .../proposal_manager/proposal_manager_test.go | 12 +- .../governance/proposal_manager/storage.go | 11 +- .../side_chain_manager_test.go | 3 +- contracts/native/utils/params.go | 11 +- .../node_manager => utils}/safe_math.go | 14 +- 23 files changed, 429 insertions(+), 345 deletions(-) delete mode 100644 consensus/hotstuff/backend/economic.go create mode 100644 contracts/native/governance/community/state.go create mode 100644 contracts/native/governance/entrance.go rename contracts/native/{governance/node_manager => utils}/safe_math.go (94%) diff --git a/consensus/hotstuff/backend/economic.go b/consensus/hotstuff/backend/economic.go deleted file mode 100644 index 1539fdec..00000000 --- a/consensus/hotstuff/backend/economic.go +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2021 The Zion Authors - * This file is part of The Zion library. - * - * The Zion is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Zion is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with The Zion. If not, see . - */ - -package backend - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/contracts/native/economic" - "github.com/ethereum/go-ethereum/contracts/native/utils" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/log" -) - -// reward distribute native token to `governance contract` and `reward pool` -func (s *backend) reward(state *state.StateDB, height *big.Int) error { - // genesis block do not need to distribute reward - if height.Uint64() == 0 { - return nil - } - - // get reward info list from native contract of `economic` - list, err := s.getRewardList(state, height) - if err != nil { - return err - } - - // add balance to related addresses - var sRwd string - for _, v := range list { - state.AddBalance(v.Address, v.Amount) - sRwd += fmt.Sprintf("address: %s, amount %v;", v.Address.Hex(), v.Amount) - } - log.Debug("reward", "num", height, "list", sRwd) - - return nil -} - -// prepare for slashing... -// todo(fuk): slash for governance -func (s *backend) slash() error { - return nil -} - -func (s *backend) getRewardList(state *state.StateDB, height *big.Int) ([]*economic.RewardAmount, error) { - caller := s.signer.Address() - ref := s.getSystemCaller(state, height) - payload, err := new(economic.MethodRewardInput).Encode() - if err != nil { - return nil, fmt.Errorf("encode reward input failed: %v", err) - } - enc, _, err := ref.NativeCall(caller, utils.EconomicContractAddress, payload) - if err != nil { - return nil, fmt.Errorf("reward native call failed: %v", err) - } - output := new(economic.MethodRewardOutput) - if err := output.Decode(enc); err != nil { - return nil, fmt.Errorf("reward output decode failed: %v", err) - } - return output.List, nil -} diff --git a/consensus/hotstuff/backend/engine.go b/consensus/hotstuff/backend/engine.go index acebcb01..ee9e8fc9 100644 --- a/consensus/hotstuff/backend/engine.go +++ b/consensus/hotstuff/backend/engine.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/hotstuff" "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/contracts/native/governance" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" @@ -117,7 +118,7 @@ func (s *backend) Prepare(chain consensus.ChainHeaderReader, header *types.Heade // returns common transactions, system transactions and system transaction message provider func (s *backend) BlockTransactions(block *types.Block, state *state.StateDB) (types.Transactions, types.Transactions, func(*types.Transaction, *big.Int) types.Message, error) { - systemTransactions, err := s.blockEndSystemTransactions(state, block.NumberU64()) + systemTransactions, err := governance.AssembleSystemTransactions(state, block.NumberU64()) if err != nil { return nil, nil, nil, err } @@ -171,7 +172,7 @@ func (s *backend) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header receipts = make([]*types.Receipt, 0) } - systemTransantions, err := s.blockEndSystemTransactions(state, header.Number.Uint64()) + systemTransantions, err := governance.AssembleSystemTransactions(state, header.Number.Uint64()) if err != nil { return nil, nil, err } @@ -187,6 +188,11 @@ func (s *backend) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header if err != nil { return nil, nil, err } + signer := types.MakeSigner(s.chainConfig, header.Number) + tx, err = s.signer.SignTx(tx, signer) + if err != nil { + return nil, nil, err + } txs = append(txs, tx) receipts = append(receipts, receipt) } diff --git a/consensus/hotstuff/backend/governance.go b/consensus/hotstuff/backend/governance.go index 2697b4a6..287db378 100644 --- a/consensus/hotstuff/backend/governance.go +++ b/consensus/hotstuff/backend/governance.go @@ -21,9 +21,7 @@ package backend import ( "fmt" "sync/atomic" - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/hotstuff" nm "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" @@ -42,7 +40,7 @@ var ( // * governance epoch changed on chain, use the new validators for an new epoch start header. // * governance epoch not changed, only set the old epoch start height in header. func (s *backend) FillHeader(state *state.StateDB, header *types.Header) error { - epoch, err := s.getGovernanceInfo(state) + epoch, err := nm.GetCurrentEpochInfoFromDB(state) if err != nil { return err } @@ -74,7 +72,7 @@ func (s *backend) CheckPoint(height uint64) (uint64, bool) { log.Warn("CheckPoint", "get state failed", err) return 0, false } - epoch, err := s.getGovernanceInfo(state) + epoch, err := nm.GetCurrentEpochInfoFromDB(state) if err != nil { log.Warn("CheckPoint", "get current epoch info, height", height, "err", err) return 0, false @@ -113,54 +111,6 @@ func (s *backend) Validators(height uint64, mining bool) hotstuff.ValidatorSet { return vals } -func (s *backend) blockEndSystemTransactions(state *state.StateDB, height uint64) (types.Transactions, error) { - // Genesis block has no system transaction? - if height == 0 { - return nil, nil - } - - var txs types.Transactions - systemSenderNonce := state.GetNonce(utils.SystemTxSender) - // SystemTransaction: NodeManager.EndBlock - { - payload, err := new(nm.EndBlockParam).Encode() - if err != nil { - return nil, err - } - txs = append(txs, types.NewTransaction(systemSenderNonce, utils.NodeManagerContractAddress, common.Big0, systemGas, big.NewInt(systemGasPrice), payload)) - } - - // SystemTransaction: NodeManager.ChangeEpoch - { - epoch, err := s.getGovernanceInfo(state) - if err != nil { - return nil, err - } - - if epoch == nil || epoch.EndHeight == nil { - return nil, fmt.Errorf("unexpected epoch or epoch end height missing") - } - - if height + 1 == epoch.EndHeight.Uint64() { - payload, err := new(nm.ChangeEpochParam).Encode() - if err != nil { - return nil, err - } - txs = append(txs, types.NewTransaction(systemSenderNonce + 1, utils.NodeManagerContractAddress, common.Big0, systemGas, big.NewInt(systemGasPrice), payload)) - } - } - return txs, nil -} - -// getGovernanceInfo call governance contract method and retrieve related info. -func (s *backend) getGovernanceInfo(state *state.StateDB) (*nm.EpochInfo, error) { - epoch, err := nm.GetCurrentEpochInfoFromDB(state) - if err != nil { - return nil, err - } - return epoch, nil -} - // getValidatorsByHeader check if current header height is an new epoch start and retrieve the validators. func (s *backend) getValidatorsByHeader(header, parent *types.Header, chain consensus.ChainHeaderReader) ( bool, hotstuff.ValidatorSet, error) { diff --git a/consensus/hotstuff/backend/utils.go b/consensus/hotstuff/backend/utils.go index 04cdf13d..b371f291 100644 --- a/consensus/hotstuff/backend/utils.go +++ b/consensus/hotstuff/backend/utils.go @@ -19,15 +19,10 @@ package backend import ( - "math" - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/hotstuff" "github.com/ethereum/go-ethereum/consensus/hotstuff/validator" - "github.com/ethereum/go-ethereum/contracts/native" - "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie" @@ -50,18 +45,6 @@ func (c chainContext) GetHeader(hash common.Hash, number uint64) *types.Header { return c.Chain.GetHeader(hash, number) } -const ( - systemGas = math.MaxUint64 / 2 // system tx will be executed in evm, and gas calculating is needed. - systemGasPrice = int64(0) // consensus txs do not need to participate in gas price bidding -) - -// getSystemCaller use fixed systemCaller as contract caller, and tx hash is useless in contract call. -func (s *backend) getSystemCaller(state *state.StateDB, height *big.Int) *native.ContractRef { - caller := utils.SystemTxSender - hash := common.EmptyHash - return native.NewContractRef(state, caller, caller, height, hash, systemGas, nil) -} - func packBlock(state *state.StateDB, chain consensus.ChainHeaderReader, header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) *types.Block { // perform root calculation and block reorganization at the same time which with a large number of memory copy. diff --git a/contracts/native/cross_chain_manager/entrance_test.go b/contracts/native/cross_chain_manager/entrance_test.go index 58a65256..5d1498b1 100644 --- a/contracts/native/cross_chain_manager/entrance_test.go +++ b/contracts/native/cross_chain_manager/entrance_test.go @@ -31,6 +31,7 @@ import ( scom "github.com/ethereum/go-ethereum/contracts/native/cross_chain_manager/common" "github.com/ethereum/go-ethereum/contracts/native/go_abi/cross_chain_manager_abi" "github.com/ethereum/go-ethereum/contracts/native/go_abi/side_chain_manager_abi" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" "github.com/ethereum/go-ethereum/contracts/native/governance/side_chain_manager" "github.com/ethereum/go-ethereum/contracts/native/info_sync" @@ -58,7 +59,7 @@ func init() { InitCrossChainManager() info_sync.InitInfoSync() - node_manager.StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) + community.StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) node_manager.StoreGenesisEpoch(sdb, signers, signers) node_manager.StoreGenesisGlobalConfig(sdb) diff --git a/contracts/native/economic/economic.go b/contracts/native/economic/economic.go index 24de804a..3f87a46e 100644 --- a/contracts/native/economic/economic.go +++ b/contracts/native/economic/economic.go @@ -24,8 +24,8 @@ import ( "github.com/ethereum/go-ethereum/contracts/native" . "github.com/ethereum/go-ethereum/contracts/native/go_abi/economic_abi" - nm "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" "github.com/ethereum/go-ethereum/contracts/native/utils" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -70,17 +70,18 @@ func TotalSupply(s *native.NativeContract) ([]byte, error) { return utils.PackOutputs(ABI, MethodTotalSupply, supply) } -func Reward(s *native.NativeContract) ([]byte, error) { - - community, err := nm.GetCommunityInfoFromDB(s.StateDB()) +func getBlockRewardList(s *native.NativeContract) ([]*RewardAmount, error) { + return nil, nil + /* + community, err := community.GetCommunityInfoFromDB(s.StateDB()) if err != nil { return nil, fmt.Errorf("GetCommunityInfo failed, err: %v", err) } // allow empty address as reward pool poolAddr := community.CommunityAddress - rewardPerBlock := nm.NewDecFromBigInt(RewardPerBlock) - rewardFactor := nm.NewDecFromBigInt(community.CommunityRate) + rewardPerBlock := utils.NewDecFromBigInt(RewardPerBlock) + rewardFactor := utils.NewDecFromBigInt(community.CommunityRate) poolRwdAmt, err := rewardPerBlock.MulWithPercentDecimal(rewardFactor) if err != nil { return nil, fmt.Errorf("Calculate pool reward amount failed, err: %v ", err) @@ -99,7 +100,40 @@ func Reward(s *native.NativeContract) ([]byte, error) { Amount: stakingRwdAmt.BigInt(), } + return []*RewardAmount{poolRwd, stakingRwd}, nil + */ +} + +func Reward(s *native.NativeContract) ([]byte, error) { + list, err := getBlockRewardList(s) + if err != nil { + return nil, err + } output := new(MethodRewardOutput) - output.List = []*RewardAmount{poolRwd, stakingRwd} + output.List = list return output.Encode() } + +func GenerateBlockReward(s *native.NativeContract) error { + height := s.ContractRef().BlockHeight() + // genesis block do not need to distribute reward + if height.Uint64() == 0 { + return nil + } + + // get reward info list from native contract of `economic` + list, err := getBlockRewardList(s) + if err != nil { + return err + } + + // add balance to related addresses + var sRwd string + for _, v := range list { + s.StateDB().AddBalance(v.Address, v.Amount) + sRwd += fmt.Sprintf("address: %s, amount %v;", v.Address.Hex(), v.Amount) + } + log.Debug("reward", "num", height, "list", sRwd) + + return nil +} diff --git a/contracts/native/economic/economic_test.go b/contracts/native/economic/economic_test.go index 320e5c7b..103e0895 100644 --- a/contracts/native/economic/economic_test.go +++ b/contracts/native/economic/economic_test.go @@ -28,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" . "github.com/ethereum/go-ethereum/contracts/native/go_abi/economic_abi" - nm "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/params" @@ -37,7 +37,6 @@ import ( func TestMain(m *testing.M) { InitABI() - nm.InitNodeManager() InitEconomic() os.Exit(m.Run()) } @@ -120,7 +119,7 @@ func TestReward(t *testing.T) { payload, _ := new(MethodRewardInput).Encode() raw, err := native.TestNativeCall(t, this, name, payload, tc.height, func(state *state.StateDB) { - nm.StoreCommunityInfo(state, big.NewInt(int64(tc.rate)), tc.pool) + community.StoreCommunityInfo(state, big.NewInt(int64(tc.rate)), tc.pool) }) if tc.err == nil { assert.NoError(t, err) diff --git a/contracts/native/governance/community/state.go b/contracts/native/governance/community/state.go new file mode 100644 index 00000000..fd312528 --- /dev/null +++ b/contracts/native/governance/community/state.go @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2021 The Zion Authors + * This file is part of The Zion library. + * + * The Zion is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Zion is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The Zion. If not, see . + */ + + package community + + import ( + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" + + "github.com/ethereum/go-ethereum/contracts/native" + "github.com/ethereum/go-ethereum/contracts/native/utils" + "github.com/ethereum/go-ethereum/core/state" +) + +// storage key prefix +const ( + SKP_COMMUNITY_INFO = "st_community_info" +) + +var ( + PercentDecimal = new(big.Int).Exp(big.NewInt(10), big.NewInt(4), nil) +) + +type CommunityInfo struct { + CommunityRate *big.Int + CommunityAddress common.Address +} + +func StoreCommunityInfo(s *state.StateDB, communityRate *big.Int, communityAddress common.Address) (*CommunityInfo, error) { + cache := (*state.CacheDB)(s) + communityInfo := &CommunityInfo{ + CommunityRate: communityRate, + CommunityAddress: communityAddress, + } + if err := setGenesisCommunityInfo(cache, communityInfo); err != nil { + return nil, err + } + return communityInfo, nil +} + + func setGenesisCommunityInfo(s *state.CacheDB, communityInfo *CommunityInfo) error { + if communityInfo.CommunityRate.Cmp(PercentDecimal) > 0 { + return fmt.Errorf("setGenesisCommunityInfo, CommunityRate over size") + } + key := communityInfoKey() + store, err := rlp.EncodeToBytes(communityInfo) + if err != nil { + return fmt.Errorf("setCommunityInfo, serialize community info error: %v", err) + } + customSet(s, key, store) + return nil + } + + func SetCommunityInfo(s *native.NativeContract, communityInfo *CommunityInfo) error { + if communityInfo.CommunityRate.Cmp(PercentDecimal) > 0 { + return fmt.Errorf("setCommunityInfo, CommunityRate over size") + } + key := communityInfoKey() + store, err := rlp.EncodeToBytes(communityInfo) + if err != nil { + return fmt.Errorf("setCommunityInfo, serialize community info error: %v", err) + } + set(s, key, store) + return nil + } + + func GetCommunityInfoImpl(s *native.NativeContract) (*CommunityInfo, error) { + communityInfo := new(CommunityInfo) + key := communityInfoKey() + store, err := get(s, key) + if err != nil { + return nil, fmt.Errorf("GetCommunityInfoImpl, get store error: %v", err) + } + if err := rlp.DecodeBytes(store, communityInfo); err != nil { + return nil, fmt.Errorf("GetCommunityInfoImpl, deserialize community info error: %v", err) + } + return communityInfo, nil + } + + func GetCommunityInfoFromDB(s *state.StateDB) (*CommunityInfo, error) { + cache := (*state.CacheDB)(s) + communityInfo := new(CommunityInfo) + key := communityInfoKey() + store, err := customGet(cache, key) + if err != nil { + return nil, fmt.Errorf("GetCommunityInfoFromDB, get store error: %v", err) + } + if err := rlp.DecodeBytes(store, communityInfo); err != nil { + return nil, fmt.Errorf("GetCommunityInfoFromDB, deserialize community info error: %v", err) + } + return communityInfo, nil + } + + // ==================================================================== + // + // storage basic operations + // + // ==================================================================== + + func get(s *native.NativeContract, key []byte) ([]byte, error) { + return customGet(s.GetCacheDB(), key) + } + + func set(s *native.NativeContract, key, value []byte) { + customSet(s.GetCacheDB(), key, value) + } + + func del(s *native.NativeContract, key []byte) { + customDel(s.GetCacheDB(), key) + } + + func customGet(db *state.CacheDB, key []byte) ([]byte, error) { + value, err := db.Get(key) + if err != nil { + return nil, err + } else if value == nil || len(value) == 0 { + return nil, errors.New("EOF") + } else { + return value, nil + } + } + + func customSet(db *state.CacheDB, key, value []byte) { + db.Put(key, value) + } + + func customDel(db *state.CacheDB, key []byte) { + db.Delete(key) + } + + func communityInfoKey() []byte { + return utils.ConcatKey(utils.NodeManagerContractAddress, []byte(SKP_COMMUNITY_INFO)) + } + \ No newline at end of file diff --git a/contracts/native/governance/entrance.go b/contracts/native/governance/entrance.go new file mode 100644 index 00000000..38404b0b --- /dev/null +++ b/contracts/native/governance/entrance.go @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 The zion network Authors + * This file is part of The poly network library. + * + * The poly network is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The poly network is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License + * along with The poly network . If not, see . + */ +package governance + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + nm "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" + "github.com/ethereum/go-ethereum/contracts/native/utils" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" +) + +func AssembleSystemTransactions(state *state.StateDB, height uint64) (types.Transactions, error) { + // Genesis block has no system transaction? + if height == 0 { + return nil, nil + } + + var txs types.Transactions + systemSenderNonce := state.GetNonce(utils.SystemTxSender) + // SystemTransaction: NodeManager.EndBlock + { + payload, err := new(nm.EndBlockParam).Encode() + if err != nil { + return nil, err + } + txs = append(txs, types.NewTransaction(systemSenderNonce, utils.NodeManagerContractAddress, common.Big0, utils.SystemGas, big.NewInt(utils.SystemGasPrice), payload)) + } + + // SystemTransaction: NodeManager.ChangeEpoch + { + epoch, err := nm.GetCurrentEpochInfoFromDB(state) + if err != nil { + return nil, err + } + + if epoch == nil || epoch.EndHeight == nil { + return nil, fmt.Errorf("unexpected epoch or epoch end height missing") + } + + if height + 1 == epoch.EndHeight.Uint64() { + payload, err := new(nm.ChangeEpochParam).Encode() + if err != nil { + return nil, err + } + txs = append(txs, types.NewTransaction(systemSenderNonce + 1, utils.NodeManagerContractAddress, common.Big0, utils.SystemGas, big.NewInt(utils.SystemGasPrice), payload)) + } + } + return txs, nil +} \ No newline at end of file diff --git a/contracts/native/governance/node_manager/distribute.go b/contracts/native/governance/node_manager/distribute.go index b7696dce..0d7355c8 100644 --- a/contracts/native/governance/node_manager/distribute.go +++ b/contracts/native/governance/node_manager/distribute.go @@ -20,10 +20,12 @@ package node_manager import ( "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/contract" - "math/big" + "github.com/ethereum/go-ethereum/contracts/native/utils" ) const ( @@ -79,7 +81,7 @@ func IncreaseValidatorPeriod(s *native.NativeContract, validator *Validator) (ui // set accumulate rewards, incrementing period by 1 newValidatorAccumulatedRewards := &ValidatorAccumulatedRewards{ - Rewards: NewDecFromBigInt(new(big.Int)), + Rewards: utils.NewDecFromBigInt(new(big.Int)), Period: validatorAccumulatedRewards.Period + 1, } err = setValidatorAccumulatedRewards(s, validator.ConsensusAddress, newValidatorAccumulatedRewards) @@ -90,57 +92,57 @@ func IncreaseValidatorPeriod(s *native.NativeContract, validator *Validator) (ui return validatorAccumulatedRewards.Period, nil } -func withdrawStakeRewards(s *native.NativeContract, validator *Validator, stakeInfo *StakeInfo) (Dec, error) { +func withdrawStakeRewards(s *native.NativeContract, validator *Validator, stakeInfo *StakeInfo) (utils.Dec, error) { // end current period and calculate rewards endingPeriod, err := IncreaseValidatorPeriod(s, validator) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, IncreaseValidatorPeriod error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, IncreaseValidatorPeriod error: %v", err) } rewards, err := CalculateStakeRewards(s, stakeInfo.StakeAddress, validator.ConsensusAddress, endingPeriod) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, CalculateStakeRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, CalculateStakeRewards error: %v", err) } err = contract.NativeTransfer(s.StateDB(), this, stakeInfo.StakeAddress, rewards.BigInt()) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, nativeTransfer error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, nativeTransfer error: %v", err) } // update the outstanding rewards outstanding, err := getOutstandingRewards(s) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, getOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, getOutstandingRewards error: %v", err) } validatorOutstanding, err := getValidatorOutstandingRewards(s, validator.ConsensusAddress) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, getValidatorOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, getValidatorOutstandingRewards error: %v", err) } newOutstandingRewards, err := outstanding.Rewards.Sub(rewards) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, outstanding.Rewards.Sub error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, outstanding.Rewards.Sub error: %v", err) } err = setOutstandingRewards(s, &OutstandingRewards{Rewards: newOutstandingRewards}) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, setOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, setOutstandingRewards error: %v", err) } newValidatorOutstandingRewards, err := validatorOutstanding.Rewards.Sub(rewards) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, validatorOutstanding.Rewards.Sub error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, validatorOutstanding.Rewards.Sub error: %v", err) } err = setValidatorOutstandingRewards(s, validator.ConsensusAddress, &ValidatorOutstandingRewards{Rewards: newValidatorOutstandingRewards}) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, setValidatorOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, setValidatorOutstandingRewards error: %v", err) } // decrement reference count of starting period startingInfo, err := getStakeStartingInfo(s, stakeInfo.StakeAddress, validator.ConsensusAddress) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, getStakeStartingInfo error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, getStakeStartingInfo error: %v", err) } startPeriod := startingInfo.StartPeriod err = decreaseReferenceCount(s, validator.ConsensusAddress, startPeriod) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawStakeRewards, decreaseReferenceCount error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawStakeRewards, decreaseReferenceCount error: %v", err) } // remove stake starting info @@ -148,11 +150,11 @@ func withdrawStakeRewards(s *native.NativeContract, validator *Validator, stakeI return rewards, nil } -func CalculateStakeRewards(s *native.NativeContract, stakeAddress common.Address, consensusAddr common.Address, endPeriod uint64) (Dec, error) { +func CalculateStakeRewards(s *native.NativeContract, stakeAddress common.Address, consensusAddr common.Address, endPeriod uint64) (utils.Dec, error) { // fetch starting info for delegation startingInfo, err := getStakeStartingInfo(s, stakeAddress, consensusAddr) if err != nil { - return Dec{nil}, fmt.Errorf("CalculateStakeRewards, getStakeStartingInfo error: %v", err) + return utils.Dec{nil}, fmt.Errorf("CalculateStakeRewards, getStakeStartingInfo error: %v", err) } startPeriod := startingInfo.StartPeriod @@ -166,19 +168,19 @@ func CalculateStakeRewards(s *native.NativeContract, stakeAddress common.Address // return staking * (ending - starting) starting, err := getValidatorSnapshotRewards(s, consensusAddr, startPeriod) if err != nil { - return Dec{nil}, fmt.Errorf("CalculateStakeRewards, getValidatorSnapshotRewards start error: %v", err) + return utils.Dec{nil}, fmt.Errorf("CalculateStakeRewards, getValidatorSnapshotRewards start error: %v", err) } ending, err := getValidatorSnapshotRewards(s, consensusAddr, endPeriod) if err != nil { - return Dec{nil}, fmt.Errorf("CalculateStakeRewards, getValidatorSnapshotRewards end error: %v", err) + return utils.Dec{nil}, fmt.Errorf("CalculateStakeRewards, getValidatorSnapshotRewards end error: %v", err) } difference, err := ending.AccumulatedRewardsRatio.Sub(starting.AccumulatedRewardsRatio) if err != nil { - return Dec{nil}, fmt.Errorf("CalculateStakeRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("CalculateStakeRewards error: %v", err) } rewards, err := difference.MulWithTokenDecimal(stake) if err != nil { - return Dec{nil}, fmt.Errorf("CalculateStakeRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("CalculateStakeRewards error: %v", err) } return rewards, nil } @@ -206,46 +208,46 @@ func initializeStake(s *native.NativeContract, stakeInfo *StakeInfo, consensusAd return nil } -func withdrawCommission(s *native.NativeContract, stakeAddress common.Address, consensusAddr common.Address) (Dec, error) { +func withdrawCommission(s *native.NativeContract, stakeAddress common.Address, consensusAddr common.Address) (utils.Dec, error) { accumulatedCommission, err := getAccumulatedCommission(s, consensusAddr) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, getAccumulatedCommission error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, getAccumulatedCommission error: %v", err) } // update the outstanding rewards outstanding, err := getOutstandingRewards(s) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, getOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, getOutstandingRewards error: %v", err) } validatorOutstanding, err := getValidatorOutstandingRewards(s, consensusAddr) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, getValidatorOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, getValidatorOutstandingRewards error: %v", err) } newOutstandingRewards, err := outstanding.Rewards.Sub(accumulatedCommission.Amount) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, outstanding.Rewards.Sub error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, outstanding.Rewards.Sub error: %v", err) } err = setOutstandingRewards(s, &OutstandingRewards{Rewards: newOutstandingRewards}) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, setOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, setOutstandingRewards error: %v", err) } newValidatorOutstandingRewards, err := validatorOutstanding.Rewards.Sub(accumulatedCommission.Amount) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, validatorOutstanding.Rewards.Sub error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, validatorOutstanding.Rewards.Sub error: %v", err) } err = setValidatorOutstandingRewards(s, consensusAddr, &ValidatorOutstandingRewards{Rewards: newValidatorOutstandingRewards}) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, setValidatorOutstandingRewards error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, setValidatorOutstandingRewards error: %v", err) } err = contract.NativeTransfer(s.StateDB(), this, stakeAddress, accumulatedCommission.Amount.BigInt()) if err != nil { - return Dec{nil}, fmt.Errorf("withdrawCommission, nativeTransfer commission error: %v", err) + return utils.Dec{nil}, fmt.Errorf("withdrawCommission, nativeTransfer commission error: %v", err) } return accumulatedCommission.Amount, nil } -func allocateRewardsToValidator(s *native.NativeContract, validator *Validator, rewards Dec) error { +func allocateRewardsToValidator(s *native.NativeContract, validator *Validator, rewards utils.Dec) error { commission, err := validator.Commission.Rate.MulWithPercentDecimal(rewards) if err != nil { return fmt.Errorf("allocateRewardsToValidator, validator.Commission.Rate.Mul error: %v", err) diff --git a/contracts/native/governance/node_manager/external.go b/contracts/native/governance/node_manager/external.go index 19a6a0f5..5af05bbe 100644 --- a/contracts/native/governance/node_manager/external.go +++ b/contracts/native/governance/node_manager/external.go @@ -22,6 +22,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" + "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/params" @@ -40,7 +42,7 @@ var ( MaxDescLength int = 2000 MaxValidatorNum int = 300 MaxUnlockingNum int = 100 - MaxStakeRate Dec = NewDecFromBigInt(new(big.Int).SetUint64(6)) // user stake can not more than 5 times of self stake + MaxStakeRate utils.Dec = utils.NewDecFromBigInt(new(big.Int).SetUint64(6)) // user stake can not more than 5 times of self stake MinBlockPerEpoch = new(big.Int).SetUint64(10000) ) @@ -57,7 +59,7 @@ func SetupGenesis(db *state.StateDB, genesis *core.Genesis) error { peers = append(peers, v.Validator) signers = append(signers, v.Signer) } - if _, err := StoreCommunityInfo(db, genesis.CommunityRate, genesis.CommunityAddress); err != nil { + if _, err := community.StoreCommunityInfo(db, genesis.CommunityRate, genesis.CommunityAddress); err != nil { return err } if _, err := StoreGenesisEpoch(db, peers, signers); err != nil { @@ -70,18 +72,6 @@ func SetupGenesis(db *state.StateDB, genesis *core.Genesis) error { return nil } -func StoreCommunityInfo(s *state.StateDB, communityRate *big.Int, communityAddress common.Address) (*CommunityInfo, error) { - cache := (*state.CacheDB)(s) - communityInfo := &CommunityInfo{ - CommunityRate: communityRate, - CommunityAddress: communityAddress, - } - if err := setGenesisCommunityInfo(cache, communityInfo); err != nil { - return nil, err - } - return communityInfo, nil -} - func StoreGenesisEpoch(s *state.StateDB, peers []common.Address, signers []common.Address) (*EpochInfo, error) { cache := (*state.CacheDB)(s) epoch := &EpochInfo{ diff --git a/contracts/native/governance/node_manager/hooks.go b/contracts/native/governance/node_manager/hooks.go index d6efe88d..ef98e1a8 100644 --- a/contracts/native/governance/node_manager/hooks.go +++ b/contracts/native/governance/node_manager/hooks.go @@ -20,33 +20,36 @@ package node_manager import ( "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/contract" - "math/big" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" + "github.com/ethereum/go-ethereum/contracts/native/utils" ) func AfterValidatorCreated(s *native.NativeContract, validator *Validator) error { // set initial historical rewards (period 0) with reference count of 1 - err := setValidatorSnapshotRewards(s, validator.ConsensusAddress, 0, &ValidatorSnapshotRewards{NewDecFromBigInt(new(big.Int)), 1}) + err := setValidatorSnapshotRewards(s, validator.ConsensusAddress, 0, &ValidatorSnapshotRewards{utils.NewDecFromBigInt(new(big.Int)), 1}) if err != nil { return fmt.Errorf("AfterValidatorCreated, setValidatorSnapshotRewards error: %v", err) } // set accumulate rewards (starting at period 1) - err = setValidatorAccumulatedRewards(s, validator.ConsensusAddress, &ValidatorAccumulatedRewards{NewDecFromBigInt(new(big.Int)), 1}) + err = setValidatorAccumulatedRewards(s, validator.ConsensusAddress, &ValidatorAccumulatedRewards{utils.NewDecFromBigInt(new(big.Int)), 1}) if err != nil { return fmt.Errorf("AfterValidatorCreated, setValidatorAccumulatedRewards error: %v", err) } // set accumulated commission - err = setAccumulatedCommission(s, validator.ConsensusAddress, &AccumulatedCommission{NewDecFromBigInt(new(big.Int))}) + err = setAccumulatedCommission(s, validator.ConsensusAddress, &AccumulatedCommission{utils.NewDecFromBigInt(new(big.Int))}) if err != nil { return fmt.Errorf("AfterValidatorCreated, setAccumulatedCommission error: %v", err) } // set outstanding rewards - err = setValidatorOutstandingRewards(s, validator.ConsensusAddress, &ValidatorOutstandingRewards{Rewards: NewDecFromBigInt(new(big.Int))}) + err = setValidatorOutstandingRewards(s, validator.ConsensusAddress, &ValidatorOutstandingRewards{Rewards: utils.NewDecFromBigInt(new(big.Int))}) if err != nil { return fmt.Errorf("AfterValidatorCreated, setValidatorOutstandingRewards error: %v", err) } @@ -59,7 +62,7 @@ func AfterValidatorRemoved(s *native.NativeContract, validator *Validator) error if err != nil { return fmt.Errorf("AfterValidatorRemoved, getValidatorOutstandingRewards error: %v", err) } - communityInfo, err := GetCommunityInfoImpl(s) + communityInfo, err := community.GetCommunityInfoImpl(s) if err != nil { return fmt.Errorf("AfterValidatorRemoved, GetCommunityInfoImpl error: %v", err) } diff --git a/contracts/native/governance/node_manager/manager.go b/contracts/native/governance/node_manager/manager.go index 045b9bb1..dfb9d739 100644 --- a/contracts/native/governance/node_manager/manager.go +++ b/contracts/native/governance/node_manager/manager.go @@ -26,7 +26,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/contract" + "github.com/ethereum/go-ethereum/contracts/native/economic" . "github.com/ethereum/go-ethereum/contracts/native/go_abi/node_manager_abi" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/rlp" ) @@ -188,12 +190,12 @@ func CreateValidator(s *native.NativeContract) ([]byte, error) { ConsensusAddress: params.ConsensusAddress, SignerAddress: params.SignerAddress, ProposalAddress: params.ProposalAddress, - Commission: &Commission{Rate: NewDecFromBigInt(params.Commission), UpdateHeight: height}, + Commission: &Commission{Rate: utils.NewDecFromBigInt(params.Commission), UpdateHeight: height}, Status: Unlock, Jailed: false, UnlockHeight: new(big.Int), - TotalStake: NewDecFromBigInt(initStake), - SelfStake: NewDecFromBigInt(initStake), + TotalStake: utils.NewDecFromBigInt(initStake), + SelfStake: utils.NewDecFromBigInt(initStake), Desc: params.Desc, } err = setValidator(s, validator) @@ -221,7 +223,7 @@ func CreateValidator(s *native.NativeContract) ([]byte, error) { } // deposit native token - err = deposit(s, caller, NewDecFromBigInt(initStake), validator) + err = deposit(s, caller, utils.NewDecFromBigInt(initStake), validator) if err != nil { return nil, fmt.Errorf("CreateValidator, deposit error: %v", err) } @@ -331,7 +333,7 @@ func UpdateCommission(s *native.NativeContract) ([]byte, error) { return nil, fmt.Errorf("UpdateCommission, commission can not changed in one epoch twice") } - validator.Commission = &Commission{Rate: NewDecFromBigInt(params.Commission), UpdateHeight: height} + validator.Commission = &Commission{Rate: utils.NewDecFromBigInt(params.Commission), UpdateHeight: height} err = setValidator(s, validator) if err != nil { @@ -365,7 +367,7 @@ func Stake(s *native.NativeContract) ([]byte, error) { if value.Sign() <= 0 { return nil, fmt.Errorf("Stake, amount must be positive") } - amount := NewDecFromBigInt(value) + amount := utils.NewDecFromBigInt(value) // check to see if the pubkey has been registered validator, found, err := getValidator(s, params.ConsensusAddress) @@ -428,7 +430,7 @@ func UnStake(s *native.NativeContract) ([]byte, error) { if params.Amount.Sign() <= 0 { return nil, fmt.Errorf("UnStake, amount must be positive") } - amount := NewDecFromBigInt(params.Amount) + amount := utils.NewDecFromBigInt(params.Amount) // check to see if the pubkey has been registered validator, found, err := getValidator(s, params.ConsensusAddress) @@ -600,7 +602,7 @@ func WithdrawValidator(s *native.NativeContract) ([]byte, error) { if err != nil { return nil, fmt.Errorf("WithdrawValidator, validator.TotalStake.Sub error: %v", err) } - validator.SelfStake = NewDecFromBigInt(new(big.Int)) + validator.SelfStake = utils.NewDecFromBigInt(new(big.Int)) if validator.TotalStake.IsZero() { delValidator(s, params.ConsensusAddress) err = AfterValidatorRemoved(s, validator) @@ -795,7 +797,7 @@ func WithdrawCommission(s *native.NativeContract) ([]byte, error) { if err != nil { return nil, fmt.Errorf("WithdrawCommission, withdrawCommission error: %v", err) } - err = setAccumulatedCommission(s, params.ConsensusAddress, &AccumulatedCommission{NewDecFromBigInt(new(big.Int))}) + err = setAccumulatedCommission(s, params.ConsensusAddress, &AccumulatedCommission{utils.NewDecFromBigInt(new(big.Int))}) if err != nil { return nil, fmt.Errorf("WithdrawCommission, setAccumulatedCommission error: %v", err) } @@ -813,8 +815,12 @@ func EndBlock(s *native.NativeContract) ([]byte, error) { return nil, fmt.Errorf("SystemTx authority failed") } + if err := economic.GenerateBlockReward(s); err != nil { + return nil, err + } + // contract balance = totalpool + outstanding + reward - balance := NewDecFromBigInt(s.StateDB().GetBalance(this)) + balance := utils.NewDecFromBigInt(s.StateDB().GetBalance(this)) totalPool, err := getTotalPool(s) if err != nil { @@ -843,7 +849,7 @@ func EndBlock(s *native.NativeContract) ([]byte, error) { if err != nil { return nil, fmt.Errorf("EndBlock, newRewards.DivUint64 error: %v", err) } - allocateSum := NewDecFromBigInt(new(big.Int)) + allocateSum := utils.NewDecFromBigInt(new(big.Int)) for _, v := range epochInfo.Validators { validator, found, err := getValidator(s, v) if err != nil { @@ -888,7 +894,7 @@ func GetGlobalConfig(s *native.NativeContract) ([]byte, error) { } func GetCommunityInfo(s *native.NativeContract) ([]byte, error) { - communityInfo, err := GetCommunityInfoImpl(s) + communityInfo, err := community.GetCommunityInfoImpl(s) if err != nil { return nil, fmt.Errorf("GetCommunityInfo, GetCommunityInfoImpl error: %v", err) } @@ -1191,6 +1197,18 @@ func GetStakeRewards(s *native.NativeContract) ([]byte, error) { return utils.PackOutputs(ABI, MethodGetStakeRewards, enc) } +func decodeCommunityInfo(payload []byte) (*community.CommunityInfo, error) { + m := new(community.CommunityInfo) + var data struct { + CommunityInfo []byte + } + if err := utils.UnpackOutputs(ABI, MethodGetCommunityInfo, &data, payload); err != nil { + return nil, err + } + err := rlp.DecodeBytes(data.CommunityInfo, m) + return m, err +} + // GetSpecMethodID for consensus use func GetSpecMethodID() map[string]bool { return map[string]bool{"fe6f86f8": true, "083c6323": true} diff --git a/contracts/native/governance/node_manager/manager_test.go b/contracts/native/governance/node_manager/manager_test.go index f13b840d..d96b7c9d 100644 --- a/contracts/native/governance/node_manager/manager_test.go +++ b/contracts/native/governance/node_manager/manager_test.go @@ -21,10 +21,12 @@ package node_manager import ( "crypto/ecdsa" "fmt" - "github.com/ethereum/go-ethereum/contracts/native/contract" "math/big" "testing" + "github.com/ethereum/go-ethereum/contracts/native/contract" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" . "github.com/ethereum/go-ethereum/contracts/native/go_abi/node_manager_abi" @@ -49,7 +51,7 @@ func Init() { InitNodeManager() sdb = native.NewTestStateDB() testGenesisPeers, _ = native.GenerateTestPeers(testGenesisNum) - StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) + community.StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) StoreGenesisEpoch(sdb, testGenesisPeers, testGenesisPeers) StoreGenesisGlobalConfig(sdb) } @@ -74,7 +76,7 @@ func TestCheckGenesis(t *testing.T) { assert.Equal(t, globalConfig.VoterValidatorNum, GenesisVoterValidatorNum) assert.Equal(t, globalConfig.ConsensusValidatorNum, GenesisConsensusValidatorNum) - communityInfo, err := GetCommunityInfoImpl(contract) + communityInfo, err := community.GetCommunityInfoImpl(contract) assert.Nil(t, err) assert.Equal(t, communityInfo.CommunityRate, big.NewInt(2000)) assert.Equal(t, communityInfo.CommunityAddress, common.EmptyAddress) @@ -104,8 +106,7 @@ func TestCheckGenesis(t *testing.T) { assert.Nil(t, err) ret, _, err = contractRef.NativeCall(common.EmptyAddress, utils.NodeManagerContractAddress, input) assert.Nil(t, err) - communityInfo2 := new(CommunityInfo) - err = communityInfo2.Decode(ret) + communityInfo2, err := decodeCommunityInfo(ret) assert.Nil(t, err) assert.Equal(t, communityInfo2.CommunityRate, big.NewInt(2000)) assert.Equal(t, communityInfo2.CommunityAddress, common.EmptyAddress) diff --git a/contracts/native/governance/node_manager/stake.go b/contracts/native/governance/node_manager/stake.go index 1586b402..00d58820 100644 --- a/contracts/native/governance/node_manager/stake.go +++ b/contracts/native/governance/node_manager/stake.go @@ -20,13 +20,15 @@ package node_manager import ( "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/contract" - "math/big" + "github.com/ethereum/go-ethereum/contracts/native/utils" ) -func deposit(s *native.NativeContract, from common.Address, amount Dec, validator *Validator) error { +func deposit(s *native.NativeContract, from common.Address, amount utils.Dec, validator *Validator) error { // get deposit info stakeInfo, found, err := getStakeInfo(s, from, validator.ConsensusAddress) if err != nil { @@ -70,7 +72,7 @@ func deposit(s *native.NativeContract, from common.Address, amount Dec, validato return nil } -func unStake(s *native.NativeContract, from common.Address, amount Dec, validator *Validator) error { +func unStake(s *native.NativeContract, from common.Address, amount utils.Dec, validator *Validator) error { height := s.ContractRef().BlockHeight() globalConfig, err := GetGlobalConfigImpl(s) if err != nil { diff --git a/contracts/native/governance/node_manager/storage.go b/contracts/native/governance/node_manager/storage.go index 60ac2ade..bffea74f 100644 --- a/contracts/native/governance/node_manager/storage.go +++ b/contracts/native/governance/node_manager/storage.go @@ -55,7 +55,6 @@ const ( SKP_STAKE_STARTING_INFO = "st_stake_starting_info" SKP_SIGN = "st_sign" SKP_SIGNER = "st_signer" - SKP_COMMUNITY_INFO = "st_community_info" ) func setAccumulatedCommission(s *native.NativeContract, consensusAddr common.Address, accumulatedCommission *AccumulatedCommission) error { @@ -154,7 +153,7 @@ func setOutstandingRewards(s *native.NativeContract, outstandingRewards *Outstan func getOutstandingRewards(s *native.NativeContract) (*OutstandingRewards, error) { outstandingRewards := &OutstandingRewards{ - Rewards: NewDecFromBigInt(new(big.Int)), + Rewards: utils.NewDecFromBigInt(new(big.Int)), } key := outstandingRewardsKey() store, err := get(s, key) @@ -441,7 +440,7 @@ func getAllValidators(s *native.NativeContract) (*AllValidators, error) { return allValidators, nil } -func depositTotalPool(s *native.NativeContract, amount Dec) error { +func depositTotalPool(s *native.NativeContract, amount utils.Dec) error { totalPool, err := getTotalPool(s) if err != nil { return fmt.Errorf("depositTotalPool, get total pool error: %v", err) @@ -457,7 +456,7 @@ func depositTotalPool(s *native.NativeContract, amount Dec) error { return nil } -func withdrawTotalPool(s *native.NativeContract, amount Dec) error { +func withdrawTotalPool(s *native.NativeContract, amount utils.Dec) error { totalPool, err := getTotalPool(s) if err != nil { return fmt.Errorf("withdrawTotalPool, get total pool error: %v", err) @@ -484,7 +483,7 @@ func setTotalPool(s *native.NativeContract, totalPool *TotalPool) error { } func getTotalPool(s *native.NativeContract) (*TotalPool, error) { - totalPool := &TotalPool{NewDecFromBigInt(new(big.Int))} + totalPool := &TotalPool{utils.NewDecFromBigInt(new(big.Int))} key := totalPoolKey() store, err := get(s, key) if err == ErrEof { @@ -518,7 +517,7 @@ func getStakeInfo(s *native.NativeContract, stakeAddress common.Address, consens stakeInfo := &StakeInfo{ StakeAddress: stakeAddress, ConsensusAddr: consensusAddr, - Amount: NewDecFromBigInt(new(big.Int)), + Amount: utils.NewDecFromBigInt(new(big.Int)), } key := stakeInfoKey(stakeAddress, consensusAddr) store, err := get(s, key) @@ -550,14 +549,14 @@ func addUnlockingInfo(s *native.NativeContract, stakeAddress common.Address, unl return nil } -func filterExpiredUnlockingInfo(s *native.NativeContract, stakeAddress common.Address) (Dec, error) { +func filterExpiredUnlockingInfo(s *native.NativeContract, stakeAddress common.Address) (utils.Dec, error) { height := s.ContractRef().BlockHeight() unlockingInfo, err := getUnlockingInfo(s, stakeAddress) if err != nil { - return Dec{nil}, fmt.Errorf("filterExpiredUnlockingInfo, GetUnlockingInfo error: %v", err) + return utils.Dec{nil}, fmt.Errorf("filterExpiredUnlockingInfo, GetUnlockingInfo error: %v", err) } j := 0 - expiredSum := NewDecFromBigInt(new(big.Int)) + expiredSum := utils.NewDecFromBigInt(new(big.Int)) for _, unlockingStake := range unlockingInfo.UnlockingStake { if unlockingStake.CompleteHeight.Cmp(height) == 1 { unlockingInfo.UnlockingStake[j] = unlockingStake @@ -565,7 +564,7 @@ func filterExpiredUnlockingInfo(s *native.NativeContract, stakeAddress common.Ad } else { expiredSum, err = expiredSum.Add(unlockingStake.Amount) if err != nil { - return Dec{nil}, fmt.Errorf("filterExpiredUnlockingInfo, expiredSum.Add error: %v", err) + return utils.Dec{nil}, fmt.Errorf("filterExpiredUnlockingInfo, expiredSum.Add error: %v", err) } } } @@ -575,7 +574,7 @@ func filterExpiredUnlockingInfo(s *native.NativeContract, stakeAddress common.Ad } else { err = setUnlockingInfo(s, unlockingInfo) if err != nil { - return Dec{nil}, fmt.Errorf("filterExpiredUnlockingInfo, setUnlockingInfo error: %v", err) + return utils.Dec{nil}, fmt.Errorf("filterExpiredUnlockingInfo, setUnlockingInfo error: %v", err) } } return expiredSum, nil @@ -725,59 +724,6 @@ func GetEpochInfoFromDB(s *state.StateDB, ID *big.Int) (*EpochInfo, error) { return epochInfo, nil } -func setGenesisCommunityInfo(s *state.CacheDB, communityInfo *CommunityInfo) error { - if communityInfo.CommunityRate.Cmp(PercentDecimal) > 0 { - return fmt.Errorf("setGenesisCommunityInfo, CommunityRate over size") - } - key := communityInfoKey() - store, err := rlp.EncodeToBytes(communityInfo) - if err != nil { - return fmt.Errorf("setCommunityInfo, serialize community info error: %v", err) - } - customSet(s, key, store) - return nil -} - -func SetCommunityInfo(s *native.NativeContract, communityInfo *CommunityInfo) error { - if communityInfo.CommunityRate.Cmp(PercentDecimal) > 0 { - return fmt.Errorf("setCommunityInfo, CommunityRate over size") - } - key := communityInfoKey() - store, err := rlp.EncodeToBytes(communityInfo) - if err != nil { - return fmt.Errorf("setCommunityInfo, serialize community info error: %v", err) - } - set(s, key, store) - return nil -} - -func GetCommunityInfoImpl(s *native.NativeContract) (*CommunityInfo, error) { - communityInfo := new(CommunityInfo) - key := communityInfoKey() - store, err := get(s, key) - if err != nil { - return nil, fmt.Errorf("GetCommunityInfoImpl, get store error: %v", err) - } - if err := rlp.DecodeBytes(store, communityInfo); err != nil { - return nil, fmt.Errorf("GetCommunityInfoImpl, deserialize community info error: %v", err) - } - return communityInfo, nil -} - -func GetCommunityInfoFromDB(s *state.StateDB) (*CommunityInfo, error) { - cache := (*state.CacheDB)(s) - communityInfo := new(CommunityInfo) - key := communityInfoKey() - store, err := customGet(cache, key) - if err != nil { - return nil, fmt.Errorf("GetCommunityInfoFromDB, get store error: %v", err) - } - if err := rlp.DecodeBytes(store, communityInfo); err != nil { - return nil, fmt.Errorf("GetCommunityInfoFromDB, deserialize community info error: %v", err) - } - return communityInfo, nil -} - // ==================================================================== // // `consensus sign` storage @@ -986,8 +932,4 @@ func signKey(hash common.Hash) []byte { func signerKey(hash common.Hash) []byte { return utils.ConcatKey(this, []byte(SKP_SIGNER), hash.Bytes()) -} - -func communityInfoKey() []byte { - return utils.ConcatKey(this, []byte(SKP_COMMUNITY_INFO)) -} +} \ No newline at end of file diff --git a/contracts/native/governance/node_manager/types.go b/contracts/native/governance/node_manager/types.go index 6865d53b..96e87f1c 100644 --- a/contracts/native/governance/node_manager/types.go +++ b/contracts/native/governance/node_manager/types.go @@ -60,8 +60,8 @@ type Validator struct { Status LockStatus Jailed bool UnlockHeight *big.Int - TotalStake Dec - SelfStake Dec + TotalStake utils.Dec + SelfStake utils.Dec Desc string } @@ -101,7 +101,7 @@ func (m Validator) IsRemoving(height *big.Int) bool { } type Commission struct { - Rate Dec + Rate utils.Dec UpdateHeight *big.Int } @@ -127,7 +127,7 @@ func (m *GlobalConfig) Decode(payload []byte) error { type StakeInfo struct { StakeAddress common.Address ConsensusAddr common.Address - Amount Dec + Amount utils.Dec } func (m *StakeInfo) Decode(payload []byte) error { @@ -159,7 +159,7 @@ type UnlockingStake struct { Height *big.Int CompleteHeight *big.Int ConsensusAddress common.Address - Amount Dec + Amount utils.Dec } type EpochInfo struct { @@ -218,7 +218,7 @@ func (m *EpochInfo) MemberList() []common.Address { } type AccumulatedCommission struct { - Amount Dec + Amount utils.Dec } func (m *AccumulatedCommission) Decode(payload []byte) error { @@ -232,7 +232,7 @@ func (m *AccumulatedCommission) Decode(payload []byte) error { } type ValidatorAccumulatedRewards struct { - Rewards Dec + Rewards utils.Dec Period uint64 } @@ -247,7 +247,7 @@ func (m *ValidatorAccumulatedRewards) Decode(payload []byte) error { } type ValidatorOutstandingRewards struct { - Rewards Dec + Rewards utils.Dec } func (m *ValidatorOutstandingRewards) Decode(payload []byte) error { @@ -261,7 +261,7 @@ func (m *ValidatorOutstandingRewards) Decode(payload []byte) error { } type OutstandingRewards struct { - Rewards Dec + Rewards utils.Dec } func (m *OutstandingRewards) Decode(payload []byte) error { @@ -275,7 +275,7 @@ func (m *OutstandingRewards) Decode(payload []byte) error { } type StakeRewards struct { - Rewards Dec + Rewards utils.Dec } func (m *StakeRewards) Decode(payload []byte) error { @@ -289,7 +289,7 @@ func (m *StakeRewards) Decode(payload []byte) error { } type ValidatorSnapshotRewards struct { - AccumulatedRewardsRatio Dec // ratio already mul decimal + AccumulatedRewardsRatio utils.Dec // ratio already mul decimal ReferenceCount uint64 } @@ -305,7 +305,7 @@ func (m *ValidatorSnapshotRewards) Decode(payload []byte) error { type StakeStartingInfo struct { StartPeriod uint64 - Stake Dec + Stake utils.Dec Height *big.Int } @@ -345,23 +345,8 @@ func (m *ConsensusSign) Hash() common.Hash { return v } -type CommunityInfo struct { - CommunityRate *big.Int - CommunityAddress common.Address -} - -func (m *CommunityInfo) Decode(payload []byte) error { - var data struct { - CommunityInfo []byte - } - if err := utils.UnpackOutputs(ABI, MethodGetCommunityInfo, &data, payload); err != nil { - return err - } - return rlp.DecodeBytes(data.CommunityInfo, m) -} - type TotalPool struct { - TotalPool Dec + TotalPool utils.Dec } func (m *TotalPool) Decode(payload []byte) error { diff --git a/contracts/native/governance/proposal_manager/proposal_manager.go b/contracts/native/governance/proposal_manager/proposal_manager.go index e657708b..a29ac3d7 100644 --- a/contracts/native/governance/proposal_manager/proposal_manager.go +++ b/contracts/native/governance/proposal_manager/proposal_manager.go @@ -21,14 +21,16 @@ package proposal_manager import ( "encoding/hex" "fmt" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/contract" . "github.com/ethereum/go-ethereum/contracts/native/go_abi/proposal_manager_abi" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/rlp" - "math/big" ) const ( @@ -271,7 +273,7 @@ func ProposeCommunity(s *native.NativeContract) ([]byte, error) { return nil, fmt.Errorf("ProposeCommunity, content is more than max length") } - info := new(node_manager.CommunityInfo) + info := new(community.CommunityInfo) err = rlp.DecodeBytes(params.Content, info) if err != nil { return nil, fmt.Errorf("ProposeCommunity, deserialize community info error: %v", err) @@ -366,7 +368,7 @@ func VoteProposal(s *native.NativeContract) ([]byte, error) { return nil, fmt.Errorf("Propose, utils.NativeTransfer error: %v", err) } - communityInfo, err := node_manager.GetCommunityInfoImpl(s) + communityInfo, err := community.GetCommunityInfoImpl(s) if err != nil { return nil, fmt.Errorf("VoteProposal, node_manager.GetCommunityInfoImpl error: %v", err) } @@ -440,7 +442,7 @@ func VoteProposal(s *native.NativeContract) ([]byte, error) { return nil, fmt.Errorf("VoteProposal, cleanConfigProposalList error: %v", err) } case UpdateCommunityInfo: - info := new(node_manager.CommunityInfo) + info := new(community.CommunityInfo) err := rlp.DecodeBytes(proposal.Content, info) if err != nil { return nil, fmt.Errorf("VoteProposal, deserialize community info error: %v", err) @@ -451,7 +453,7 @@ func VoteProposal(s *native.NativeContract) ([]byte, error) { if info.CommunityRate.Sign() > 0 { communityInfo.CommunityRate = info.CommunityRate } - err = node_manager.SetCommunityInfo(s, communityInfo) + err = community.SetCommunityInfo(s, communityInfo) if err != nil { return nil, fmt.Errorf("VoteProposal, node_manager.SetCommunityInfo error: %v", err) } diff --git a/contracts/native/governance/proposal_manager/proposal_manager_test.go b/contracts/native/governance/proposal_manager/proposal_manager_test.go index d6b5d7ac..61a1e9ea 100644 --- a/contracts/native/governance/proposal_manager/proposal_manager_test.go +++ b/contracts/native/governance/proposal_manager/proposal_manager_test.go @@ -20,15 +20,17 @@ package proposal_manager import ( "crypto/ecdsa" + "math/big" + "testing" + "github.com/ethereum/go-ethereum/contracts/native/contract" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "math/big" - "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/crypto" @@ -50,7 +52,7 @@ func init() { InitProposalManager() sdb = native.NewTestStateDB() testGenesisPeers, _ = native.GenerateTestPeers(testGenesisNum) - node_manager.StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) + community.StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) node_manager.StoreGenesisEpoch(sdb, testGenesisPeers, testGenesisPeers) node_manager.StoreGenesisGlobalConfig(sdb) } @@ -69,7 +71,7 @@ func TestProposalManager(t *testing.T) { assert.Equal(t, globalConfig.ConsensusValidatorNum, node_manager.GenesisConsensusValidatorNum) assert.Equal(t, globalConfig.MinProposalStake, node_manager.GenesisMinProposalStake) - communityInfo, err := node_manager.GetCommunityInfoImpl(c) + communityInfo, err := community.GetCommunityInfoImpl(c) assert.Nil(t, err) assert.Equal(t, communityInfo.CommunityRate, big.NewInt(2000)) assert.Equal(t, communityInfo.CommunityAddress, common.EmptyAddress) @@ -257,7 +259,7 @@ func TestProposalManager(t *testing.T) { globalConfig, err = node_manager.GetGlobalConfigImpl(c) assert.Nil(t, err) assert.Equal(t, globalConfig.VoterValidatorNum, uint64(2)) - communityInfo, err = node_manager.GetCommunityInfoImpl(c) + communityInfo, err = community.GetCommunityInfoImpl(c) assert.Nil(t, err) assert.Equal(t, communityInfo.CommunityRate, big.NewInt(1000)) assert.Equal(t, sdb.GetBalance(common.EmptyAddress), new(big.Int).Mul(big.NewInt(81000), params.ZNT1)) diff --git a/contracts/native/governance/proposal_manager/storage.go b/contracts/native/governance/proposal_manager/storage.go index 683502f6..8defeda8 100644 --- a/contracts/native/governance/proposal_manager/storage.go +++ b/contracts/native/governance/proposal_manager/storage.go @@ -21,13 +21,14 @@ package proposal_manager import ( "errors" "fmt" + "math/big" + "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/contract" - "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/rlp" - "math/big" ) var ErrEof = errors.New("EOF") @@ -108,7 +109,7 @@ func removeFromProposalList(s *native.NativeContract, ID *big.Int) error { } func removeExpiredFromProposalList(s *native.NativeContract) error { - communityInfo, err := node_manager.GetCommunityInfoImpl(s) + communityInfo, err := community.GetCommunityInfoImpl(s) if err != nil { return fmt.Errorf("removeExpiredFromProposalList, node_manager.GetCommunityInfoImpl error: %v", err) } @@ -183,7 +184,7 @@ func cleanConfigProposalList(s *native.NativeContract) error { } func removeExpiredFromConfigProposalList(s *native.NativeContract) error { - communityInfo, err := node_manager.GetCommunityInfoImpl(s) + communityInfo, err := community.GetCommunityInfoImpl(s) if err != nil { return fmt.Errorf("removeExpiredFromConfigProposalList, node_manager.GetCommunityInfoImpl error: %v", err) } @@ -258,7 +259,7 @@ func cleanCommunityProposalList(s *native.NativeContract) error { } func removeExpiredFromCommunityProposalList(s *native.NativeContract) error { - communityInfo, err := node_manager.GetCommunityInfoImpl(s) + communityInfo, err := community.GetCommunityInfoImpl(s) if err != nil { return fmt.Errorf("removeExpiredFromCommunityProposalList, node_manager.GetCommunityInfoImpl error: %v", err) } diff --git a/contracts/native/governance/side_chain_manager/side_chain_manager_test.go b/contracts/native/governance/side_chain_manager/side_chain_manager_test.go index 2d2aaca3..f0fbef2e 100644 --- a/contracts/native/governance/side_chain_manager/side_chain_manager_test.go +++ b/contracts/native/governance/side_chain_manager/side_chain_manager_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/contracts/native" "github.com/ethereum/go-ethereum/contracts/native/go_abi/side_chain_manager_abi" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/governance/node_manager" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/core/rawdb" @@ -49,7 +50,7 @@ func init() { node_manager.InitNodeManager() sdb = native.NewTestStateDB() signers, _ = native.GenerateTestPeers(2) - node_manager.StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) + community.StoreCommunityInfo(sdb, big.NewInt(2000), common.EmptyAddress) node_manager.StoreGenesisEpoch(sdb, signers, signers) node_manager.StoreGenesisGlobalConfig(sdb) } diff --git a/contracts/native/utils/params.go b/contracts/native/utils/params.go index 57c1ceb2..66b013d3 100644 --- a/contracts/native/utils/params.go +++ b/contracts/native/utils/params.go @@ -17,7 +17,11 @@ */ package utils -import "github.com/ethereum/go-ethereum/common" +import ( + "math" + + "github.com/ethereum/go-ethereum/common" +) var ( BYTE_FALSE = []byte{0} @@ -44,3 +48,8 @@ var ( RIPPLE_ROUTER = uint64(6) ) + +const ( + SystemGas = math.MaxUint64 / 2 // system tx will be executed in evm, and gas calculating is needed. + SystemGasPrice = int64(0) // consensus txs do not need to participate in gas price bidding +) diff --git a/contracts/native/governance/node_manager/safe_math.go b/contracts/native/utils/safe_math.go similarity index 94% rename from contracts/native/governance/node_manager/safe_math.go rename to contracts/native/utils/safe_math.go index 9d8e74ff..965259e5 100644 --- a/contracts/native/governance/node_manager/safe_math.go +++ b/contracts/native/utils/safe_math.go @@ -16,13 +16,23 @@ * along with The Zion. If not, see . */ -package node_manager +package utils import ( "errors" "math/big" ) +const ( + TokenPrecision = 18 + PercentPrecision = 4 +) + +var ( + TokenDecimal = new(big.Int).Exp(big.NewInt(10), big.NewInt(TokenPrecision), nil) + PercentDecimal = new(big.Int).Exp(big.NewInt(10), big.NewInt(PercentPrecision), nil) +) + type Dec struct { I *big.Int } @@ -149,4 +159,4 @@ func (t Dec) DivUint64(i uint64) (Dec, error) { div := new(big.Int).Div(t.I, new(big.Int).SetUint64(i)) return Dec{div}, nil -} +} \ No newline at end of file From 6796667da5336b58d72c26efd1a9fed8a0a54ee5 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Mon, 28 Aug 2023 10:22:01 +0800 Subject: [PATCH 04/12] Ensure system transactions will be not reverted --- consensus/hotstuff/backend/engine.go | 3 +++ core/state_processor.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/consensus/hotstuff/backend/engine.go b/consensus/hotstuff/backend/engine.go index ee9e8fc9..570be4e2 100644 --- a/consensus/hotstuff/backend/engine.go +++ b/consensus/hotstuff/backend/engine.go @@ -188,6 +188,9 @@ func (s *backend) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header if err != nil { return nil, nil, err } + if receipt.Status != types.ReceiptStatusSuccessful { + return nil, nil, fmt.Errorf("unexpected reverted system transactions tx %d [%s], status %v", len(txs), tx.Hash(), receipt.Status) + } signer := types.MakeSigner(s.chainConfig, header.Number) tx, err = s.signer.SignTx(tx, signer) if err != nil { diff --git a/core/state_processor.go b/core/state_processor.go index a69cf221..ce2f2cc5 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -98,6 +98,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } + if receipt.Status != types.ReceiptStatusSuccessful { + return nil, nil, 0, fmt.Errorf("unexpected reverted system transactions tx %d [%s], status %v", i, tx.Hash(), receipt.Status) + } receipts = append(receipts, receipt) } From 1242be9f11053445dd9b9daf26a4a58ed0144357 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Wed, 30 Aug 2023 10:16:55 +0800 Subject: [PATCH 05/12] Remove some quotes --- contracts/native/economic/economic.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/contracts/native/economic/economic.go b/contracts/native/economic/economic.go index 3f87a46e..1fc72299 100644 --- a/contracts/native/economic/economic.go +++ b/contracts/native/economic/economic.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/contracts/native" . "github.com/ethereum/go-ethereum/contracts/native/go_abi/economic_abi" + "github.com/ethereum/go-ethereum/contracts/native/governance/community" "github.com/ethereum/go-ethereum/contracts/native/utils" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -71,8 +72,6 @@ func TotalSupply(s *native.NativeContract) ([]byte, error) { } func getBlockRewardList(s *native.NativeContract) ([]*RewardAmount, error) { - return nil, nil - /* community, err := community.GetCommunityInfoFromDB(s.StateDB()) if err != nil { return nil, fmt.Errorf("GetCommunityInfo failed, err: %v", err) @@ -84,11 +83,11 @@ func getBlockRewardList(s *native.NativeContract) ([]*RewardAmount, error) { rewardFactor := utils.NewDecFromBigInt(community.CommunityRate) poolRwdAmt, err := rewardPerBlock.MulWithPercentDecimal(rewardFactor) if err != nil { - return nil, fmt.Errorf("Calculate pool reward amount failed, err: %v ", err) + return nil, fmt.Errorf("calculate pool reward amount failed, err: %v ", err) } stakingRwdAmt, err := rewardPerBlock.Sub(poolRwdAmt) if err != nil { - return nil, fmt.Errorf("Calculate staking reward amount, failed, err: %v ", err) + return nil, fmt.Errorf("calculate staking reward amount, failed, err: %v ", err) } poolRwd := &RewardAmount{ @@ -101,7 +100,6 @@ func getBlockRewardList(s *native.NativeContract) ([]*RewardAmount, error) { } return []*RewardAmount{poolRwd, stakingRwd}, nil - */ } func Reward(s *native.NativeContract) ([]byte, error) { From 6d2dbfbb4728bbd60298a3e445ca74881b034fe7 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Fri, 1 Sep 2023 20:14:05 +0800 Subject: [PATCH 06/12] Fix test units --- consensus/hotstuff/signer/signer_test.go | 42 ++----------------- .../cross_chain_manager/entrance_test.go | 1 - contracts/native/economic/economic_test.go | 8 ++-- .../signature_manager_test.go | 8 ++-- contracts/native/info_sync/entrance_test.go | 12 +++--- contracts/native/utils/event_emitter_test.go | 12 +++++- core/state_processor_test.go | 2 +- eth/api_test.go | 2 +- eth/catalyst/api_test.go | 2 +- eth/tracers/tracers_test.go | 4 +- ethclient/ethclient_test.go | 6 +-- miner/miner_test.go | 4 ++ signer/rules/rules_test.go | 2 +- 13 files changed, 40 insertions(+), 65 deletions(-) diff --git a/consensus/hotstuff/signer/signer_test.go b/consensus/hotstuff/signer/signer_test.go index ea4d026d..e72585e5 100644 --- a/consensus/hotstuff/signer/signer_test.go +++ b/consensus/hotstuff/signer/signer_test.go @@ -19,17 +19,14 @@ package signer import ( - "bytes" "crypto/ecdsa" "sort" "strings" "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/hotstuff" "github.com/ethereum/go-ethereum/consensus/hotstuff/validator" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/assert" ) @@ -38,11 +35,11 @@ import ( func TestSign(t *testing.T) { s := newTestSigner() data := []byte("Here is a string....") - sig, err := s.Sign(data) + hashData := crypto.Keccak256(data) + sig, err := s.SignHash(common.BytesToHash(hashData)) assert.NoError(t, err, "error mismatch: have %v, want nil", err) //Check signature recover - hashData := crypto.Keccak256(data) pubkey, _ := crypto.Ecrecover(hashData, sig) var signer common.Address copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) @@ -63,7 +60,7 @@ func TestCheckValidatorSignature(t *testing.T) { // CheckValidatorSignature should succeed signer := NewSigner(k) - addr, err := signer.CheckSignature(vset, data, sig) + addr, err := signer.CheckSignature(vset, common.BytesToHash(hashData), sig) assert.NoError(t, err, "error mismatch: have %v, want nil", err) val := vset.GetByIndex(uint64(i)) @@ -80,44 +77,13 @@ func TestCheckValidatorSignature(t *testing.T) { // CheckValidatorSignature should return ErrUnauthorizedAddress signer := NewSigner(key) - addr, err := signer.CheckSignature(vset, data, sig) + addr, err := signer.CheckSignature(vset, common.BytesToHash(hashData), sig) assert.Equal(t, err, ErrUnauthorizedAddress, "error mismatch: have %v, want %v", err, ErrUnauthorizedAddress) emptyAddr := common.Address{} assert.Equal(t, emptyAddr, common.Address{}, "address mismatch: have %v, want %v", addr, emptyAddr) } -// go test -v github.com/ethereum/go-ethereum/consensus/hotstuff/signer -run TestFillExtraAfterCommit -func TestFillExtraAfterCommit(t *testing.T) { - istRawData := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000000f89d801ef85494258af48e28e4a6846e931ddff8e1cdf8579821e5946a708455c8777630aac9d1e7702d13f7a865b27c948c09d936a1b408d6e0afaa537ba4e06c4504a0ae94ad3bf5ed640cc72f37bd21d64a65c3c756e9c88cb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080") - extra, _ := types.ExtractHotstuffExtraPayload(istRawData) - - expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.HotstuffExtraSeal-3)...) - expectedIstExtra := &types.HotstuffExtra{ - StartHeight: 0, - EndHeight: 30, - Validators: extra.Validators, - Seal: extra.Seal, - CommittedSeal: [][]byte{expectedCommittedSeal}, - Salt: extra.Salt, - } - h := &types.Header{ - Extra: istRawData, - } - - // normal case - assert.NoError(t, emptySigner.SealAfterCommit(h, [][]byte{expectedCommittedSeal})) - - // verify istanbul extra-data - istExtra, err := types.ExtractHotstuffExtra(h) - assert.NoError(t, err) - assert.Equal(t, expectedIstExtra, istExtra) - - // invalid seal - unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...) - assert.Equal(t, ErrInvalidCommittedSeals, emptySigner.SealAfterCommit(h, [][]byte{unexpectedCommittedSeal})) -} - var emptySigner = &SignerImpl{} type Keys []*ecdsa.PrivateKey diff --git a/contracts/native/cross_chain_manager/entrance_test.go b/contracts/native/cross_chain_manager/entrance_test.go index 5d1498b1..bc2e2684 100644 --- a/contracts/native/cross_chain_manager/entrance_test.go +++ b/contracts/native/cross_chain_manager/entrance_test.go @@ -64,7 +64,6 @@ func init() { node_manager.StoreGenesisGlobalConfig(sdb) param := new(side_chain_manager.RegisterSideChainParam) - param.BlocksToWait = 4 param.ChainID = 8 param.Name = "mychain" diff --git a/contracts/native/economic/economic_test.go b/contracts/native/economic/economic_test.go index 103e0895..b186c5a7 100644 --- a/contracts/native/economic/economic_test.go +++ b/contracts/native/economic/economic_test.go @@ -48,7 +48,7 @@ func TestName(t *testing.T) { payload, err := new(MethodContractNameInput).Encode() assert.NoError(t, err) - raw, err := native.TestNativeCall(t, this, name, payload) + raw, err := native.TestNativeCall(t, this, name, payload, common.Big0) assert.NoError(t, err) var got string assert.NoError(t, utils.UnpackOutputs(ABI, name, &got, raw)) @@ -78,7 +78,7 @@ func TestTotalSupply(t *testing.T) { var supply *big.Int payload, _ := new(MethodTotalSupplyInput).Encode() - raw, err := native.TestNativeCall(t, this, name, payload, tc.height) + raw, err := native.TestNativeCall(t, this, name, payload, common.Big0, tc.height) assert.NoError(t, err) if tc.testABI { @@ -118,7 +118,7 @@ func TestReward(t *testing.T) { got := new(MethodRewardOutput) payload, _ := new(MethodRewardInput).Encode() - raw, err := native.TestNativeCall(t, this, name, payload, tc.height, func(state *state.StateDB) { + raw, err := native.TestNativeCall(t, this, name, payload, common.Big0, tc.height, func(state *state.StateDB) { community.StoreCommunityInfo(state, big.NewInt(int64(tc.rate)), tc.pool) }) if tc.err == nil { @@ -146,7 +146,7 @@ func TestTransfer(t *testing.T) { state := native.NewTestStateDB() state.AddBalance(from, amount) - _, ctx := native.GenerateTestContext(t, state) + _, ctx := native.GenerateTestContext(t, common.Big0, to, state) if state.GetBalance(from).Cmp(amount) < 0 { t.Error("balance not enough") } diff --git a/contracts/native/governance/signature_manager/signature_manager_test.go b/contracts/native/governance/signature_manager/signature_manager_test.go index 35def3c1..7c16ff73 100644 --- a/contracts/native/governance/signature_manager/signature_manager_test.go +++ b/contracts/native/governance/signature_manager/signature_manager_test.go @@ -72,7 +72,7 @@ func TestAddSignature(t *testing.T) { payload := append(methodID, args...) supplyGas := gasTable[name] - _, err = native.TestNativeCall(t, this, name, payload, supplyGas) + _, err = native.TestNativeCall(t, this, name, payload, common.Big0, supplyGas) assert.NotNil(t, err) assert.Contains(t, err.Error(), "abi", "marshal") } @@ -83,7 +83,7 @@ func TestAddSignature(t *testing.T) { assert.NoError(t, err) supplyGas := gasTable[name] - 1 - _, err = native.TestNativeCall(t, this, name, payload, supplyGas) + _, err = native.TestNativeCall(t, this, name, payload, common.Big0, supplyGas) assert.NotNil(t, err) assert.Contains(t, err.Error(), "gas", "supply", "left") } @@ -98,7 +98,7 @@ func TestAddSignature(t *testing.T) { payload, err := utils.PackMethod(ABI, name, addr, big.NewInt(2), []byte{'a'}, []byte{'1'}) assert.NoError(t, err) - _, err = native.TestNativeCall(t, this, name, payload, sender, supplyGas) + _, err = native.TestNativeCall(t, this, name, payload, common.Big0, sender, supplyGas) assert.NotNil(t, err) assert.Contains(t, err.Error(), "checkWitness", "authentication") } @@ -118,7 +118,7 @@ func TestAddSignature(t *testing.T) { payload, err := utils.PackMethod(ABI, name, sender, chainID, subject, errSig) assert.NoError(t, err) - _, err = native.TestNativeCall(t, this, name, payload, sender, supplyGas, func(state *state.StateDB) { + _, err = native.TestNativeCall(t, this, name, payload, common.Big0, sender, supplyGas, func(state *state.StateDB) { nm.StoreGenesisEpoch(state, peers, peers) }) t.Error(err) diff --git a/contracts/native/info_sync/entrance_test.go b/contracts/native/info_sync/entrance_test.go index f025ba58..14324cdb 100644 --- a/contracts/native/info_sync/entrance_test.go +++ b/contracts/native/info_sync/entrance_test.go @@ -110,7 +110,7 @@ func TestNoAuthSyncRootInfo(t *testing.T) { caller := crypto.PubkeyToAddress(*pub) extra := uint64(21000000000000) - _, err = native.TestNativeCall(t, utils.InfoSyncContractAddress, "SyncRootInfo", input, caller, caller, extra, sdb) + _, err = native.TestNativeCall(t, utils.InfoSyncContractAddress, "SyncRootInfo", input, common.Big0, caller, caller, extra, sdb) assert.NotNil(t, err) } @@ -138,7 +138,7 @@ func TestNormalSyncRootInfo(t *testing.T) { input, err := param.Encode() assert.Nil(t, err) - ret, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "SyncRootInfo", input, caller, caller, extra, sdb) + ret, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "SyncRootInfo", input, common.Big0, caller, caller, extra, sdb) assert.Nil(t, err) result, err := utils.PackOutputs(ABI, MethodSyncRootInfo, true) assert.Nil(t, err) @@ -151,7 +151,7 @@ func TestNormalSyncRootInfo(t *testing.T) { input, err := q1.Encode() assert.Nil(t, err) extra := uint64(21000000000000) - ret1, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "GetInfo", input, extra, sdb) + ret1, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "GetInfo", input, common.Big0, extra, sdb) rootInfo := new(GetInfoOutput) err = rootInfo.Decode(ret1) assert.Nil(t, err) @@ -162,7 +162,7 @@ func TestNormalSyncRootInfo(t *testing.T) { } input, err = q2.Encode() assert.Nil(t, err) - ret2, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "GetInfo", input, extra, sdb) + ret2, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "GetInfo", input, common.Big0, extra, sdb) rootInfo = new(GetInfoOutput) err = rootInfo.Decode(ret2) assert.Nil(t, err) @@ -170,7 +170,7 @@ func TestNormalSyncRootInfo(t *testing.T) { q3 := &GetInfoHeightParam{CHAIN_ID} input, err = q3.Encode() assert.Nil(t, err) - ret3, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "GetInfoHeight", input, extra, sdb) + ret3, err := native.TestNativeCall(t, utils.InfoSyncContractAddress, "GetInfoHeight", input, common.Big0, extra, sdb) height := new(GetInfoHeightOutput) err = height.Decode(ret3) assert.Nil(t, err) @@ -186,6 +186,6 @@ func TestReplenish(t *testing.T) { extra := uint64(21000000000000) input, err := param.Encode() assert.Nil(t, err) - _, err = native.TestNativeCall(t, utils.InfoSyncContractAddress, "Replenish", input, extra, sdb) + _, err = native.TestNativeCall(t, utils.InfoSyncContractAddress, "Replenish", input, common.Big0, extra, sdb) assert.Nil(t, err) } diff --git a/contracts/native/utils/event_emitter_test.go b/contracts/native/utils/event_emitter_test.go index 0db6a6e1..b6f49aca 100644 --- a/contracts/native/utils/event_emitter_test.go +++ b/contracts/native/utils/event_emitter_test.go @@ -24,10 +24,18 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/contracts/native" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" "github.com/stretchr/testify/assert" ) +func NewTestStateDB() *state.StateDB { + memdb := rawdb.NewMemoryDatabase() + db := state.NewDatabase(memdb) + stateDB, _ := state.New(common.Hash{}, db, nil) + return stateDB +} + func TestEventEmitter(t *testing.T) { name := "propose" abijson := `[ @@ -39,7 +47,7 @@ func TestEventEmitter(t *testing.T) { contract := common.HexToAddress("0x05") blockNo := uint64(36) - stateDB := native.NewTestStateDB() + stateDB := NewTestStateDB() emmitter := NewEventEmitter(contract, blockNo, stateDB) proposer := common.HexToAddress("0x12") diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 5976ecc3..e9623b62 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -125,7 +125,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr Difficulty: parent.Difficulty(), UncleHash: parent.UncleHash(), }), - GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()), + GasLimit: parent.GasLimit(), Number: new(big.Int).Add(parent.Number(), common.Big1), Time: parent.Time() + 10, UncleHash: types.EmptyUncleHash, diff --git a/eth/api_test.go b/eth/api_test.go index e5eac7b7..39a1d584 100644 --- a/eth/api_test.go +++ b/eth/api_test.go @@ -177,7 +177,7 @@ func TestStorageRangeAt(t *testing.T) { } ) for _, entry := range storage { - state.SetState(addr, *entry.Key, entry.Value.Bytes()) + state.SetState(addr, *entry.Key, entry.Value) } // Check a few combinations of limit and start/end. diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index b8a6e43f..ecb1abc7 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -203,7 +203,7 @@ func TestEth2NewBlock(t *testing.T) { if err != nil || !success.Valid { t.Fatalf("Failed to insert forked block #%d: %v", i, err) } - lastBlock, err = insertBlockParamsToBlock(p) + lastBlock, err = insertBlockParamsToBlock(ethservice.APIBackend.ChainConfig(), lastBlock.Header(), p) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 9dc4c696..8b01edd7 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -179,7 +179,7 @@ func TestPrestateTracerCreate2(t *testing.T) { } evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer) + msg, err := tx.AsMessage(signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } @@ -254,7 +254,7 @@ func TestCallTracer(t *testing.T) { } evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) - msg, err := tx.AsMessage(signer) + msg, err := tx.AsMessage(signer, nil) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 713d0e97..56f287b6 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -652,7 +652,7 @@ func TestUnmarshalHeader(t *testing.T) { var ( blockNum uint64 = 1099 - epochID uint64 = 5 + epochID uint64 = 5 ) block, err := cli.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNum)) if err != nil { @@ -680,8 +680,7 @@ func TestUnmarshalHeader(t *testing.T) { // cache db slot contractAddr := utils.NodeManagerContractAddress - proofHash := node_manager.EpochProofHash(epochID) - cacheKey := utils.ConcatKey(contractAddr, []byte("st_proof"), proofHash.Bytes()) + cacheKey := utils.ConcatKey(contractAddr, []byte(node_manager.SKP_EPOCH_INFO), big.NewInt(int64(epochID)).Bytes()) slot := state.Key2Slot(cacheKey[common.AddressLength:]) t.Logf("slot hex before keccak: %s", slot.Hex()) @@ -699,5 +698,4 @@ func TestUnmarshalHeader(t *testing.T) { t.Fatal(err) } t.Logf("proof result: %s", string(enc)) - return } diff --git a/miner/miner_test.go b/miner/miner_test.go index da1e472d..fc724b88 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -54,6 +54,10 @@ func (m *mockBackend) TxPool() *core.TxPool { return m.txPool } +func (m *mockBackend) PeerCount() int { + return 0 +} + type testBlockChain struct { statedb *state.StateDB gasLimit uint64 diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go index 510c57e6..ec11e371 100644 --- a/signer/rules/rules_test.go +++ b/signer/rules/rules_test.go @@ -437,7 +437,7 @@ func dummyTx(value hexutil.Big) *core.SignTxRequest { To: to, Value: value, Nonce: n, - GasPrice: gasPrice, + GasPrice: &gasPrice, Gas: gas, }, Callinfo: []core.ValidationInfo{ From 826e9661b39a1f405fdf585a9be917e10fd4e566 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Tue, 12 Sep 2023 19:42:50 +0800 Subject: [PATCH 07/12] Fix miner unit tests --- core/genesis.go | 16 +++++++++------- core/tx_pool.go | 3 ++- miner/miner.go | 16 ++++++++++------ miner/worker.go | 10 ++++++---- miner/worker_test.go | 41 +++++++++++++---------------------------- 5 files changed, 40 insertions(+), 46 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index f692d6c8..112953de 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -299,6 +299,8 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { g.createNativeContract(statedb, v) } RegGenesis(statedb, g) + } else { + g.mintNativeToken(statedb) } root := statedb.IntermediateRoot(false) @@ -390,14 +392,14 @@ func (g *Genesis) mintNativeToken(statedb *state.StateDB) { if total.Cmp(params.GenesisSupply) != 0 { panic("alloc amount should be equal to genesis supply") } + } - for addr, account := range g.Alloc { - statedb.AddBalance(addr, account.Balance) - statedb.SetCode(addr, account.Code) - statedb.SetNonce(addr, account.Nonce) - for key, value := range account.Storage { - statedb.SetState(addr, key, value) - } + for addr, account := range g.Alloc { + statedb.AddBalance(addr, account.Balance) + statedb.SetCode(addr, account.Code) + statedb.SetNonce(addr, account.Nonce) + for key, value := range account.Storage { + statedb.SetState(addr, key, value) } } } diff --git a/core/tx_pool.go b/core/tx_pool.go index 41689ba1..e2d1db75 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -18,13 +18,14 @@ package core import ( "errors" - "github.com/ethereum/go-ethereum/consensus/misc" "math" "math/big" "sort" "sync" "time" + "github.com/ethereum/go-ethereum/consensus/misc" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/core/state" diff --git a/miner/miner.go b/miner/miner.go index 34ca2049..603f1ec7 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -78,12 +78,16 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even } // hotstuff: disable pre-sealing, and waiting for p2p server connections - protocol := hotstuff.HotstuffProtocol(chainConfig.HotStuff.Protocol) - switch protocol { - case hotstuff.HOTSTUFF_PROTOCOL_BASIC: - miner.worker = newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true) - miner.EnablePreseal() - default: + if chainConfig.HotStuff != nil { + protocol := hotstuff.HotstuffProtocol(chainConfig.HotStuff.Protocol) + switch protocol { + case hotstuff.HOTSTUFF_PROTOCOL_BASIC: + miner.worker = newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true) + miner.EnablePreseal() + default: + log.Crit("Unknown hotstuff protocal", "protocal", protocol) + } + } else { miner.worker = newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true) } diff --git a/miner/worker.go b/miner/worker.go index 8883847d..2577ac71 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -57,7 +57,7 @@ const ( // minRecommitInterval is the minimal time interval to recreate the mining block with // any newly arrived transactions. - minRecommitInterval = 20 * time.Second + minRecommitInterval = 3 * time.Second // maxRecommitInterval is the maximum time interval to recreate the mining block with // any newly arrived transactions. @@ -223,7 +223,10 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus go worker.resultLoop() go worker.taskLoop() - worker.startCh <- struct{}{} + // Submit first work to initialize pending state. + if init { + worker.startCh <- struct{}{} + } return worker } @@ -378,6 +381,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // If mining is running resubmit a new work cycle periodically to pull in // higher priced transactions. Disable this overhead for pending blocks. if w.IsRunning() && (w.chainConfig.HotStuff != nil && w.chainConfig.HotStuff.Protocol != "") { + timestamp = time.Now().Unix() log.Debug("Miner resubmit work", "timestamp", timestamp, "from", minRecommit) commit(commitInterruptResubmit) } @@ -864,10 +868,8 @@ func (w *worker) commitNewWork(interrupt *int32, timestamp int64) { w.mu.RLock() defer w.mu.RUnlock() - // just use current time as block timestamp tstart := time.Now() parent := w.chain.CurrentBlock() - timestamp = tstart.Unix() num := parent.Number() header := &types.Header{ diff --git a/miner/worker_test.go b/miner/worker_test.go index b267a74d..003987b2 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -89,6 +89,7 @@ func init() { To: &testUserAddress, Value: big.NewInt(1000), Gas: params.TxGas, + GasPrice: big.NewInt(params.InitialBaseFee), }) pendingTxs = append(pendingTxs, tx1) @@ -97,6 +98,7 @@ func init() { To: &testUserAddress, Value: big.NewInt(1000), Gas: params.TxGas, + GasPrice: big.NewInt(params.InitialBaseFee), }) newTxs = append(newTxs, tx2) @@ -244,12 +246,12 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) { // Start mining! w.Start() + time.Sleep(time.Second) for i := 0; i < 5; i++ { b.txPool.AddLocal(b.newRandomTx(true)) b.txPool.AddLocal(b.newRandomTx(false)) - //w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) - //w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) + w.newWorkCh <- &newWorkReq{timestamp: time.Now().Unix()} select { case ev := <-sub.Chan(): @@ -257,6 +259,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) { if _, err := chain.InsertChain([]*types.Block{block}); err != nil { t.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) } + time.Sleep(time.Second * 1) case <-time.After(3 * time.Second): // Worker needs 1s to include new changes. t.Fatalf("timeout") } @@ -283,7 +286,7 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens checkEqual := func(t *testing.T, task *task, index int) { // The first empty work without any txs included receiptLen, balance := 0, big.NewInt(0) - if index == 1 { + if index == 0 { // The second full work with 1 tx included receiptLen, balance = 1, big.NewInt(1000) } @@ -306,7 +309,7 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens time.Sleep(100 * time.Millisecond) } w.Start() // Start mining! - for i := 0; i < 2; i += 1 { + for i := 0; i < 1; i += 1 { select { case <-taskCh: case <-time.NewTimer(3 * time.Second).C: @@ -330,7 +333,7 @@ func TestStreamUncleBlock(t *testing.T) { // The first task is an empty task, the second // one has 1 pending tx, the third one has 1 tx // and 1 uncle. - if taskIndex == 2 { + if taskIndex == 1 { have := task.block.Header().UncleHash want := types.CalcUncleHash([]*types.Header{b.uncleBlock.Header()}) if have != want { @@ -349,16 +352,6 @@ func TestStreamUncleBlock(t *testing.T) { } w.Start() - for i := 0; i < 2; i += 1 { - select { - case <-taskCh: - case <-time.NewTimer(time.Second).C: - t.Error("new task timeout") - } - } - - //w.postSideBlock(core.ChainSideEvent{Block: b.uncleBlock}) - select { case <-taskCh: case <-time.NewTimer(time.Second).C: @@ -387,7 +380,7 @@ func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, en if task.block.NumberU64() == 1 { // The first task is an empty task, the second // one has 1 pending tx, the third one has 2 txs - if taskIndex == 2 { + { receiptLen, balance := 2, big.NewInt(2000) if len(task.receipts) != receiptLen { t.Errorf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen) @@ -407,16 +400,8 @@ func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, en time.Sleep(100 * time.Millisecond) } - w.Start() - // Ignore the first two works - for i := 0; i < 2; i += 1 { - select { - case <-taskCh: - case <-time.NewTimer(time.Second).C: - t.Error("new task timeout") - } - } b.txPool.AddLocals(newTxs) + w.Start() time.Sleep(time.Second) select { @@ -472,15 +457,15 @@ func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine co estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond case 3: - wantMinInterval, wantRecommitInterval = time.Second, time.Second + wantMinInterval, wantRecommitInterval = 3 * time.Second, 3* time.Second } // Check interval if minInterval != wantMinInterval { - t.Errorf("resubmit min interval mismatch: have %v, want %v ", minInterval, wantMinInterval) + t.Errorf("resubmit min interval mismatch: have %v, want %v , index %v", minInterval, wantMinInterval, index) } if recommitInterval != wantRecommitInterval { - t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) + t.Errorf("resubmit interval mismatch: have %v, want %v, index %v", recommitInterval, wantRecommitInterval, index) } result = append(result, float64(recommitInterval.Nanoseconds())) index += 1 From d5e8adb5cf0a39dfdd44f602c39cde7b39086b0e Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Wed, 13 Sep 2023 10:43:26 +0800 Subject: [PATCH 08/12] Ignore system tx base fee check --- core/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state_transition.go b/core/state_transition.go index 98e62f48..63c42f69 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -241,7 +241,7 @@ func (st *StateTransition) preCheck() error { } // This will panic if baseFee is nil, but basefee presence is verified // as part of header validation. - if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 { + if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 && st.msg.From() != utils.SystemTxSender { return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow, st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee) } From 99cbffefeef016e2de469558613106af1f7d7d13 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Wed, 13 Sep 2023 12:09:18 +0800 Subject: [PATCH 09/12] Fix most unit tests in native contracts --- .../cross_chain_manager/entrance_test.go | 36 ++--- contracts/native/economic/economic_test.go | 6 +- .../governance/node_manager/manager_test.go | 6 +- .../side_chain_manager_test.go | 36 ++--- .../signature_manager_test.go | 2 +- contracts/native/helper/internal.go | 142 ------------------ contracts/native/helper/internal_test.go | 48 ------ contracts/native/test.go | 2 +- 8 files changed, 46 insertions(+), 232 deletions(-) delete mode 100644 contracts/native/helper/internal.go delete mode 100644 contracts/native/helper/internal_test.go diff --git a/contracts/native/cross_chain_manager/entrance_test.go b/contracts/native/cross_chain_manager/entrance_test.go index bc2e2684..5246fcb3 100644 --- a/contracts/native/cross_chain_manager/entrance_test.go +++ b/contracts/native/cross_chain_manager/entrance_test.go @@ -66,29 +66,31 @@ func init() { param := new(side_chain_manager.RegisterSideChainParam) param.ChainID = 8 param.Name = "mychain" + param.Router = 1 param1 := new(side_chain_manager.RegisterSideChainParam) - param1.ChainID = 9 + param1.ChainID = 79 param1.Name = strings.Repeat("1", 100) param1.ExtraInfo = make([]byte, 1000000) param1.CCMCAddress = make([]byte, 1000) + param1.Router = 1 ccd := common.HexToAddress("0xdedace1809079e241234d546e44517f31b57ab8f") param2 := new(side_chain_manager.RegisterSideChainParam) param2.ChainID = 10 - param2.Router = 15 + param2.Router = 2 param2.Name = "chain10" param2.CCMCAddress = ccd.Bytes() param3 := new(side_chain_manager.RegisterSideChainParam) param3.ChainID = 11 - param3.Router = 15 + param3.Router = 2 param3.Name = strings.Repeat("1", 100) param3.ExtraInfo = make([]byte, 1000000) param3.CCMCAddress = ccd.Bytes() param4 := *param3 - param4.ChainID = 79 + param4.ChainID = 2 for _, param := range []*side_chain_manager.RegisterSideChainParam{param, param1, param2, param3, ¶m4} { input, err := utils.PackMethodWithStruct(side_chain_manager.ABI, side_chain_manager_abi.MethodRegisterSideChain, param) @@ -171,7 +173,7 @@ func TestImportOuterTransfer(t *testing.T) { param.Extra = event param1 := new(scom.EntranceParam) - param1.SourceChainID = 9 + param1.SourceChainID = 79 param1.Extra = event param2 := new(scom.EntranceParam) @@ -204,7 +206,7 @@ func TestImportOuterTransfer(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := common.Address{} contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodImportOuterTransfer]+extra, nil) tr.Start() @@ -214,7 +216,7 @@ func TestImportOuterTransfer(t *testing.T) { result, err := utils.PackOutputs(scom.ABI, cross_chain_manager_abi.MethodImportOuterTransfer, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } } @@ -223,7 +225,7 @@ func TestImportOuterTransfer(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := common.Address{} contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodImportOuterTransfer]+extra, nil) tr.Start() @@ -233,7 +235,7 @@ func TestImportOuterTransfer(t *testing.T) { result, err := utils.PackOutputs(scom.ABI, cross_chain_manager_abi.MethodImportOuterTransfer, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() } @@ -255,7 +257,7 @@ func TestReplenish(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := common.Address{} contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodReplenish]+extra, nil) tr.Start() @@ -265,7 +267,7 @@ func TestReplenish(t *testing.T) { result, err := utils.PackOutputs(scom.ABI, cross_chain_manager_abi.MethodReplenish, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() } @@ -283,7 +285,7 @@ func TestCheckDone(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := common.Address{} contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodCheckDone]+extra, nil) tr.Start() @@ -293,7 +295,7 @@ func TestCheckDone(t *testing.T) { result, err := utils.PackOutputs(scom.ABI, cross_chain_manager_abi.MethodCheckDone, false) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() } @@ -311,7 +313,7 @@ func TestWhiteChain(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := signers[0] contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodWhiteChain]+extra, nil) tr.Start() @@ -321,7 +323,7 @@ func TestWhiteChain(t *testing.T) { result, err := utils.PackOutputs(scom.ABI, cross_chain_manager_abi.MethodWhiteChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() } @@ -339,7 +341,7 @@ func TestBlackChain(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := signers[0] contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodBlackChain]+extra, nil) tr.Start() @@ -349,7 +351,7 @@ func TestBlackChain(t *testing.T) { result, err := utils.PackOutputs(scom.ABI, cross_chain_manager_abi.MethodBlackChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() } diff --git a/contracts/native/economic/economic_test.go b/contracts/native/economic/economic_test.go index b186c5a7..d8fbe3a3 100644 --- a/contracts/native/economic/economic_test.go +++ b/contracts/native/economic/economic_test.go @@ -48,7 +48,7 @@ func TestName(t *testing.T) { payload, err := new(MethodContractNameInput).Encode() assert.NoError(t, err) - raw, err := native.TestNativeCall(t, this, name, payload, common.Big0) + raw, err := native.TestNativeCall(t, this, name, payload, common.Big0, gasTable[MethodName]) assert.NoError(t, err) var got string assert.NoError(t, utils.UnpackOutputs(ABI, name, &got, raw)) @@ -78,7 +78,7 @@ func TestTotalSupply(t *testing.T) { var supply *big.Int payload, _ := new(MethodTotalSupplyInput).Encode() - raw, err := native.TestNativeCall(t, this, name, payload, common.Big0, tc.height) + raw, err := native.TestNativeCall(t, this, name, payload, common.Big0, tc.height, gasTable[MethodTotalSupply]) assert.NoError(t, err) if tc.testABI { @@ -120,7 +120,7 @@ func TestReward(t *testing.T) { payload, _ := new(MethodRewardInput).Encode() raw, err := native.TestNativeCall(t, this, name, payload, common.Big0, tc.height, func(state *state.StateDB) { community.StoreCommunityInfo(state, big.NewInt(int64(tc.rate)), tc.pool) - }) + }, gasTable[MethodReward]) if tc.err == nil { assert.NoError(t, err) assert.NoError(t, got.Decode(raw)) diff --git a/contracts/native/governance/node_manager/manager_test.go b/contracts/native/governance/node_manager/manager_test.go index d96b7c9d..26aa4101 100644 --- a/contracts/native/governance/node_manager/manager_test.go +++ b/contracts/native/governance/node_manager/manager_test.go @@ -453,7 +453,7 @@ func TestChangeEpoch(t *testing.T) { param := new(CreateValidatorParam) param.ConsensusAddress = consensusAddr param.SignerAddress = consensusAddr - param.ProposalAddress = caller + param.ProposalAddress = consensusAddr param.Commission = new(big.Int).SetUint64(2000) param.Desc = "test" validatorsKey = append(validatorsKey, &ValidatorKey{param.ConsensusAddress, caller}) @@ -537,7 +537,7 @@ func TestDistribute(t *testing.T) { param := new(CreateValidatorParam) param.ConsensusAddress = consensusAddr param.SignerAddress = consensusAddr - param.ProposalAddress = caller + param.ProposalAddress = consensusAddr param.Commission = new(big.Int).SetUint64(2000) param.Desc = "test" validatorsKey = append(validatorsKey, &ValidatorKey{param.ConsensusAddress, caller}) @@ -985,7 +985,7 @@ func TestPerformance(t *testing.T) { param := new(CreateValidatorParam) param.ConsensusAddress = consensusAddr param.SignerAddress = consensusAddr - param.ProposalAddress = caller + param.ProposalAddress = consensusAddr param.Commission = new(big.Int).SetUint64(2000) param.Desc = "test" validatorsKey = append(validatorsKey, &ValidatorKey{param.ConsensusAddress, caller}) diff --git a/contracts/native/governance/side_chain_manager/side_chain_manager_test.go b/contracts/native/governance/side_chain_manager/side_chain_manager_test.go index f0fbef2e..6081853f 100644 --- a/contracts/native/governance/side_chain_manager/side_chain_manager_test.go +++ b/contracts/native/governance/side_chain_manager/side_chain_manager_test.go @@ -71,7 +71,7 @@ func testRegisterSideChainManager(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) tr := native.NewTimer(side_chain_manager_abi.MethodRegisterSideChain) for _, input := range [][]byte{input, input1} { caller := signers[0] @@ -83,12 +83,14 @@ func testRegisterSideChainManager(t *testing.T) { result, err := utils.PackOutputs(ABI, side_chain_manager_abi.MethodRegisterSideChain) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) contract := native.NewNativeContract(sdb, contractRef) sideChain, err := GetSideChainApply(contract, 8) - assert.Equal(t, sideChain.Name, "mychain") assert.Nil(t, err) + assert.NotNil(t, sideChain) + t.Log(sideChain) + assert.Equal(t, sideChain.Name, "mychain") _, _, err = contractRef.NativeCall(common.Address{}, utils.SideChainManagerContractAddress, input) assert.NotNil(t, err) @@ -112,7 +114,7 @@ func testApproveRegisterSideChain(t *testing.T) { for _, input := range [][]byte{input, input1} { caller := signers[0] blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveRegisterSideChain]+extra, nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) @@ -122,7 +124,7 @@ func testApproveRegisterSideChain(t *testing.T) { result, err := utils.PackOutputs(ABI, side_chain_manager_abi.MethodApproveRegisterSideChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) caller = signers[1] contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveRegisterSideChain]+extra, nil) @@ -134,7 +136,7 @@ func testApproveRegisterSideChain(t *testing.T) { result, err = utils.PackOutputs(ABI, side_chain_manager_abi.MethodApproveRegisterSideChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() } @@ -160,7 +162,7 @@ func testUpdateSideChain(t *testing.T) { tr := native.NewTimer(side_chain_manager_abi.MethodUpdateSideChain) for _, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := signers[0] contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodUpdateSideChain]+extra, nil) tr.Start() @@ -171,7 +173,7 @@ func testUpdateSideChain(t *testing.T) { result, err := utils.PackOutputs(ABI, side_chain_manager_abi.MethodUpdateSideChain) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() @@ -193,7 +195,7 @@ func testApproveUpdateSideChain(t *testing.T) { tr1 := native.NewTimer(side_chain_manager_abi.MethodGetSideChain) for i, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := signers[0] contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveUpdateSideChain]+extra, nil) tr.Start() @@ -204,7 +206,7 @@ func testApproveUpdateSideChain(t *testing.T) { result, err := utils.PackOutputs(ABI, side_chain_manager_abi.MethodApproveUpdateSideChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) caller = signers[1] contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveUpdateSideChain]+extra, nil) @@ -216,7 +218,7 @@ func testApproveUpdateSideChain(t *testing.T) { result, err = utils.PackOutputs(ABI, side_chain_manager_abi.MethodApproveUpdateSideChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) contract := native.NewNativeContract(sdb, contractRef) sideChain, err := GetSideChainObject(contract, 8+uint64(i)) @@ -239,7 +241,7 @@ func testApproveUpdateSideChain(t *testing.T) { result, err = utils.PackOutputs(ABI, side_chain_manager_abi.MethodGetSideChain, sideChain) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() tr1.Dump() @@ -260,7 +262,7 @@ func testQuiteSideChain(t *testing.T) { tr := native.NewTimer(side_chain_manager_abi.MethodQuitSideChain) for _, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := signers[0] contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodQuitSideChain]+extra, nil) tr.Start() @@ -271,7 +273,7 @@ func testQuiteSideChain(t *testing.T) { result, err := utils.PackOutputs(ABI, side_chain_manager_abi.MethodQuitSideChain) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) } tr.Dump() } @@ -291,7 +293,7 @@ func TestApproveQuiteSideChain(t *testing.T) { tr := native.NewTimer(side_chain_manager_abi.MethodApproveQuitSideChain) for i, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(10) + extra := uint64(21000) caller := signers[0] contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveQuitSideChain]+extra, nil) tr.Start() @@ -302,7 +304,7 @@ func TestApproveQuiteSideChain(t *testing.T) { result, err := utils.PackOutputs(ABI, side_chain_manager_abi.MethodApproveUpdateSideChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) caller = signers[1] contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveQuitSideChain]+extra, nil) @@ -314,7 +316,7 @@ func TestApproveQuiteSideChain(t *testing.T) { result, err = utils.PackOutputs(ABI, side_chain_manager_abi.MethodApproveQuitSideChain, true) assert.Nil(t, err) assert.Equal(t, ret, result) - assert.Equal(t, leftOverGas, extra) + assert.Equal(t, leftOverGas, uint64(0)) contract := native.NewNativeContract(sdb, contractRef) sideChain, err := GetSideChainObject(contract, 8+uint64(i)) diff --git a/contracts/native/governance/signature_manager/signature_manager_test.go b/contracts/native/governance/signature_manager/signature_manager_test.go index 7c16ff73..bddd9082 100644 --- a/contracts/native/governance/signature_manager/signature_manager_test.go +++ b/contracts/native/governance/signature_manager/signature_manager_test.go @@ -121,6 +121,6 @@ func TestAddSignature(t *testing.T) { _, err = native.TestNativeCall(t, this, name, payload, common.Big0, sender, supplyGas, func(state *state.StateDB) { nm.StoreGenesisEpoch(state, peers, peers) }) - t.Error(err) + assert.Nil(t, err) } } diff --git a/contracts/native/helper/internal.go b/contracts/native/helper/internal.go deleted file mode 100644 index b92ff49b..00000000 --- a/contracts/native/helper/internal.go +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2021 The Zion Authors - * This file is part of The Zion library. - * - * The Zion is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Zion is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with The Zion. If not, see . - */ - -package helper - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/light" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" -) - -func VerifyTx(proof []byte, hdr *types.Header, contract common.Address, extra []byte, checkResult bool) ([]byte, error) { - ethProof := new(ethapi.AccountResult) - if err := json.Unmarshal(proof, ethProof); err != nil { - return nil, fmt.Errorf("VerifyFromEthProof, unmarshal proof failed, err:%v", err) - } - - proofResult, err := VerifyAccountResult(ethProof, hdr, contract) - if err != nil { - return nil, fmt.Errorf("VerifyFromEthProof, verifyMerkleProof failed, err:%v", err) - } - if proofResult == nil { - return nil, fmt.Errorf("VerifyFromEthProof, verifyMerkleProof failed, err:%s", "proof result is nil") - } - if checkResult && !CheckProofResult(proofResult, extra) { - return nil, fmt.Errorf("VerifyFromEthProof, failed to check result, stored %s, got %s", hexutil.Encode(proofResult), hexutil.Encode(extra)) - } - return proofResult, nil -} - -func VerifyAccountResult(proof *ethapi.AccountResult, header *types.Header, contractAddr common.Address) ([]byte, error) { - if err := VerifyAccountProof(proof, header, contractAddr); err != nil { - return nil, err - } - return VerifyStorageProof(proof) -} - -func VerifyAccountProof(proof *ethapi.AccountResult, header *types.Header, contractAddr common.Address) error { - nodeList := new(light.NodeList) - for _, s := range proof.AccountProof { - nodeList.Put(nil, common.FromHex(s)) - } - ns := nodeList.NodeSet() - - if proof.Address != contractAddr { - return fmt.Errorf("verifyMerkleProof, contract address is error, proof address: %s, side chain address: %s", proof.Address.Hex(), contractAddr.Hex()) - } - acctKey := crypto.Keccak256(proof.Address[:]) - - // 2. verify account proof - acctVal, err := trie.VerifyProof(header.Root, acctKey, ns) - if err != nil { - return fmt.Errorf("verifyMerkleProof, verify account proof error:%s\n", err) - } - - acct := &state.Account{ - Nonce: uint64(proof.Nonce), - Balance: proof.Balance.ToInt(), - Root: proof.StorageHash, - CodeHash: proof.CodeHash[:], - } - - acctrlp, err := rlp.EncodeToBytes(acct) - if err != nil { - return err - } - - if !bytes.Equal(acctrlp, acctVal) { - return fmt.Errorf("verifyMerkleProof, verify account proof failed, wanted:%v, get:%v", acctrlp, acctVal) - } - - return nil -} - -func VerifyStorageProof(proof *ethapi.AccountResult) ([]byte, error) { - nodeList := new(light.NodeList) - if len(proof.StorageProof) != 1 { - return nil, fmt.Errorf("verifyMerkleProof, invalid storage proof format") - } - sp := proof.StorageProof[0] - storageKey := crypto.Keccak256(common.HexToHash(Replace0x(sp.Key)).Bytes()) - - for _, prf := range sp.Proof { - nodeList.Put(nil, common.Hex2Bytes(Replace0x(prf))) - } - ns := nodeList.NodeSet() - - val, err := trie.VerifyProof(proof.StorageHash, storageKey[:], ns) - if err != nil { - return nil, fmt.Errorf("verifyMerkleProof, verify storage proof error:%s\n", err) - } - return val, nil -} - -func Replace0x(s string) string { - return strings.Replace(strings.ToLower(s), "0x", "", 1) -} - -func CheckProofResult(result, value []byte) bool { - var s_temp []byte - err := rlp.DecodeBytes(result, &s_temp) - if err != nil { - log.Errorf("checkProofResult, rlp.DecodeBytes error:%s\n", err) - return false - } - // - var s []byte - for i := len(s_temp); i < 32; i++ { - s = append(s, 0) - } - s = append(s, s_temp...) - hash := crypto.Keccak256(value) - - return bytes.Equal(s, hash) -} diff --git a/contracts/native/helper/internal_test.go b/contracts/native/helper/internal_test.go deleted file mode 100644 index dd6969df..00000000 --- a/contracts/native/helper/internal_test.go +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2021 The Zion Authors - * This file is part of The Zion library. - * - * The Zion is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Zion is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with The Zion. If not, see . - */ - -package helper - -import ( - "encoding/json" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/internal/ethapi" -) - -func TestVerifyAccountResult(t *testing.T) { - headerJson := `{"parentHash":"0xc4daea63055c5364fb42cb45c7f6eebf3277451c8d8ac984084e143b8c85c26d","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x8c09d936a1b408d6e0afaa537ba4e06c4504a0ae","stateRoot":"0x7f13d3173193b206527ff06ec2defb2cb79dd30fa09eba1c741a24aa71ad19f9","transactionsRoot":"0x41985aa48725b27456004e7596e64ccdaeb66ae38b5c42cdcc599072a123d566","receiptsRoot":"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x1","number":"0xa933b","gasLimit":"0x7a1200","gasUsed":"0x5208","timestamp":"0x618262de","extraData":"0x0000000000000000000000000000000000000000000000000000000000000000f90197c0b841d68c498ce9f44f82cfd0aedba61701516858d8db76d991e07daf080cf24835991ceae0eaa46220db3087ccea3692cbd4ab50019ad1369608e6d74747fc52e0a701f9014fb841fc08d7eb36cb49673b8526bf680f3ce2bddadcd11623d4e69a3c7c3ce98ff94861e6efcec0a34451404eac2ae63e599c747c41d351da80b818ac8b2fe29d004100b841be610bc5e49b1b1f5e4330dcce624f05f3c4f9fd58563edf2edda5370f093e6c62c6c4f42538dc34eead3ee848ee92d4ebad9f4116d02922369b15e250ed426e00b8419056e2c70f710717333afc7879860cbe84cd43426c07c2e60b62f273494d4dba6d7845250b15933681a9d0c0a59c37e8bb91d5804131d110065a2b1885e4e66600b841e2348610285a035b89dbbc0dfb4b88b62c90b085839eb57bfb1e60c83edb0a052462c22bc50549b02703d71ec8cb7a3c1ad015979d5e913f2a6507d8f94e940b00b8415706cd4cd259665ec1987d2bf42a776dd90681478c19ee6c03444fa131d4fcef0a4d3ae1f9649fec11db195cbf3759c54a225a51b914bfc7ea1d518eded83e400080","mixHash":"0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365","nonce":"0x0000000000000000","hash":"0xe71005f3dea6edde3adcb5c4d95413d37bdbcc8c1ae136747cd5905a18081ec1"}` - proofJson := `{"address":"0x7559968a6395d67d1b14a33e461a07837fc76534","accountProof":["0xf90211a0dc645c1bc408c7455f7148dd7d0bdadc4828a3d68cec2a894cee43b04a8c6371a0b2d9749426507e67698679359be1f6465f9bc6c37232c4fd8aa4f8d5e69e79dea042171732bfeae1d9d706633b40137c6ce0c4cdcc8f3c64869247e183b2d7b41ea0fa6777985694d2c92862eceb62c50994aec2a5b77b75d9d6e4e6fbe4a21fc92fa09c689b8ff30656dd6c04061996042f42e4e99475658803ed66f46e54dde8812da03d1a791ef6a1e74dde297afbc721c8cc9630852676c8925bcbd8d65aa3ea7f6aa009461bf87644c5065244d7ab3cfd56b9770621cde1d443e75d789de64b7d162aa0073b6b94eebfc830252ce6acadac4698b9cf60acf8ec1fecd15066c7e5684bc8a0ff85ebfa2dd7a4eb5895861f4756db8739c509ee4a8944294ea748cdc7f1a88ca08ba8c6a349cc7088884c2d5c7d5f7cc31e2d8e5774aa7c8d92085366ab9c5553a0ef4f0a8df0a0793735df3123c78f6cfb72907940efdacf35a7717ccd431b70f8a0f3570db8b65c9dbda26648386018d8d28947b34ede83c2318a36437a9c17571ca0b560872d03afb2de3dd5664298524b092846e2fc297af7682cd39cfb3a16e892a0e7f9d44e75ce1ead9eab9eb4b9d34e960f37a0da3f7abff8ada31f323eb8f465a06844be9ba9b1a11bcba38962212457dad2a234ad4267859fd088ae10a9cef6aea0d3701d759ded6f12cb8cc69c67daf9ebd6854de2065653d65aa17b034dbdce0080","0xf901f1a037121ae504f846cc7feec07fce5bb8a484f14a87ea89a34d7852f1b8f906220aa0c5724ef803e16fbaadcb01fb53d71047614f87456d0940f840323f5b00b51ba4a0384183443feade18a1c4c32985076d4a476f1d8df6fe3d6a5ceb122aeac47683a0f3011005e25a4f657a66279d3476644bbe9a0190f4573bf9dc0ac94ca3b0071ea02be843a7b9919b3c983adf75bc97b88725c010271687547e2a2621a2f8572076a0065494029df72cdb469b6fa0a4a0dfb71cf81d23252b50b402a34b3b769964cfa0f629bcfa2e70e49819c05c567f1b493b07757ae408ad4f3b07d7fca85def010aa0dc3cef685c9d54a52856ae48d38834fa5166f5efaa86ec105d3263efd52d7016a0dcfe9cecc57294fcb25c20000f3a4a376fd90ac2edced927d19b051e09468578a04db064a86a09a7838b3ce7b690c7277f752319f9072aee642d958e8a80ef416ea0d10d5c56904ba0769e94b473472d95daa28487f55211b30aafde658c2deec48da05190053527e9b10ebfa1855e7049c54ae1da76650e122d3197520caf1e0ec45aa0767ea183e6bedb588f3341b2be3a4e732a6b7470b10a4e9cfdedcee9d93b4b42a0f5a3e1ae905310644a810d05d416ae27ecf821bb50a582628fa43bb3afa30a43a034802e794acdc4514d37ddf08648170cbb0e4d545c0c999e11cb2e55734df85a8080","0xf8d18080a08dc3fbeb5b35dbef92d1378c7ba8f20d894d4df739df7492dcd74fb96790704280808080a007551a8a7efd604c4437ddab5c08750f6a79926321e8c74fc9c0a8913d5ec3c0a022784e544b94f8f5f1626286113721efbcf30556a4886c2b233f5fd3c77c2134a0d11d6371f79aea13fc89c3c389f167cb54f012f172d91efd491ec5c60b946048a0906553817ed69ff29645fd05ba32d7418b5217c5aabc6ae7e5b098e5a3de9d8180a087968c8af6e9b8931ea798f9584bbc75597ce8dfead3c1b7634cd9b4f26559b280808080","0xf8729f3d23679c94d1d1529982d63fab85ee7275fd777d7e61214c4f4723068921dbb850f84e808a043c33c1937564800000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"],"balance":"0x43c33c1937564800000","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","nonce":"0x0","storageHash":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","storageProof":[{"key":"0x439d23679c94d1d1529982d63fab85ee7275fd777d7e61214c4f4723068921db","value":"0x0","proof":[]}]}` - - header := new(types.Header) - if err := header.UnmarshalJSON([]byte(headerJson)); err != nil { - t.Fatal(err) - } - - var proof ethapi.AccountResult - if err := json.Unmarshal([]byte(proofJson), &proof); err != nil { - t.Fatal(err) - } - - user := common.HexToAddress("0x7559968a6395d67d1b14a33e461a07837fc76534") - if _, err := VerifyAccountResult(&proof, header, user); err != nil { - t.Fatal(err) - } -} diff --git a/contracts/native/test.go b/contracts/native/test.go index df2ea44f..bfc4decf 100644 --- a/contracts/native/test.go +++ b/contracts/native/test.go @@ -103,7 +103,7 @@ func GenerateTestContext(t *testing.T, value *big.Int, address common.Address, p } blockHeight := new(big.Int).SetInt64(int64(block)) - contractRef := NewContractRef(sdb, sender, caller, blockHeight, hash, supplyGas, nil) + contractRef := NewContractRef(sdb, sender, caller, blockHeight, hash, supplyGas + 21000, nil) contractRef.SetValue(value) contractRef.SetTo(address) ctx := NewNativeContract(sdb, contractRef) From 0b1a384379a0da5e82e44192956937095f6fa285 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Fri, 15 Sep 2023 15:28:58 +0800 Subject: [PATCH 10/12] Update header seal hash to include nonce and mix digest --- core/types/block.go | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index e51c4490..a91d94d9 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -114,25 +114,7 @@ func SealHash(header *Header) (hash common.Hash) { } hasher := sha3.NewLegacyKeccak256() - enc := []interface{}{ - header.ParentHash, - header.UncleHash, - header.Coinbase, - header.Root, - header.TxHash, - header.ReceiptHash, - header.Bloom, - header.Difficulty, - header.Number, - header.GasLimit, - header.GasUsed, - header.Time, - header.Extra, - } - if header.BaseFee != nil { - enc = append(enc, header.BaseFee) - } - rlp.Encode(hasher, enc) + rlp.Encode(hasher, header) hasher.Sum(hash[:0]) return hash } From 0f24c750b466df27db0abe5231850b6edce1a1e4 Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Fri, 15 Sep 2023 15:53:52 +0800 Subject: [PATCH 11/12] Remove duplicate intrinsic gas cost for native contract calls --- contracts/native/contract.go | 28 ++----------------- .../cross_chain_manager/entrance_test.go | 18 ++++-------- .../side_chain_manager_test.go | 26 +++++++---------- contracts/native/test.go | 2 +- 4 files changed, 20 insertions(+), 54 deletions(-) diff --git a/contracts/native/contract.go b/contracts/native/contract.go index 315fe9af..0143e415 100644 --- a/contracts/native/contract.go +++ b/contracts/native/contract.go @@ -38,14 +38,6 @@ var ( DebugSpentOpen bool = true ) -// the gasUsage for the native contract transaction calculated according to the following formula: -// * `gasUsage = gasRatio * gasTable[methodId]` -// the value in gas table for native tx is the max num for bench test in linux. -const ( - basicGas = uint64(21000) // minimum gas spent by transaction which failed before contract.handler, the default value is 21000 wei. - gasRatio = float64(1.0) // gasRatio is used to adjust the final value of gasUsage. -) - type NativeContract struct { ref *ContractRef db *state.StateDB @@ -81,8 +73,7 @@ func (s *NativeContract) Prepare(ab *abiPkg.ABI, gasTb map[string]uint64) { s.gasTable = make(map[string]uint64) for name, gas := range gasTb { id := utils.MethodID(s.ab, name) - final := uint64(float64(basicGas) + float64(gas)*gasRatio) - s.gasTable[id] = final + s.gasTable[id] = gas } } @@ -93,15 +84,6 @@ func (s *NativeContract) Register(name string, handler MethodHandler) { // Invoke return execute ret and cost gas func (s *NativeContract) Invoke() ([]byte, error) { - - // pre-cost for failed tx which failed before `handler` execution. - if gasLeft := s.ref.gasLeft; gasLeft < basicGas { - s.ref.gasLeft = 0 - return nil, fmt.Errorf("gasLeft not enough, need %d, got %d", basicGas, gasLeft) - } else { - s.ref.gasLeft -= basicGas - } - // check context if !s.ref.CheckContexts() { return nil, fmt.Errorf("context error") @@ -132,18 +114,14 @@ func (s *NativeContract) Invoke() ([]byte, error) { if !ok { return nil, fmt.Errorf("failed to find method: [%s]", methodID) } - if gasUsage < basicGas { - gasUsage = basicGas - } - // refund basic gas before tx get into `handler` - s.ref.gasLeft += basicGas + if gasLeft := s.ref.gasLeft; gasLeft < gasUsage { return nil, fmt.Errorf("gasLeft not enough, need %d, got %d", gasUsage, gasLeft) } + s.ref.gasLeft -= gasUsage // execute transaction and cost gas ret, err := handler(s) - s.ref.gasLeft -= gasUsage return ret, err } diff --git a/contracts/native/cross_chain_manager/entrance_test.go b/contracts/native/cross_chain_manager/entrance_test.go index 5246fcb3..5bca0fd6 100644 --- a/contracts/native/cross_chain_manager/entrance_test.go +++ b/contracts/native/cross_chain_manager/entrance_test.go @@ -206,9 +206,8 @@ func TestImportOuterTransfer(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(21000) caller := common.Address{} - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodImportOuterTransfer]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodImportOuterTransfer], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.CrossChainManagerContractAddress, input) tr.Stop() @@ -225,9 +224,8 @@ func TestImportOuterTransfer(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(21000) caller := common.Address{} - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodImportOuterTransfer]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodImportOuterTransfer], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.CrossChainManagerContractAddress, input) tr.Stop() @@ -257,9 +255,8 @@ func TestReplenish(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(21000) caller := common.Address{} - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodReplenish]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodReplenish], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.CrossChainManagerContractAddress, input) tr.Stop() @@ -285,9 +282,8 @@ func TestCheckDone(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(21000) caller := common.Address{} - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodCheckDone]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodCheckDone], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.CrossChainManagerContractAddress, input) tr.Stop() @@ -313,9 +309,8 @@ func TestWhiteChain(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(21000) caller := signers[0] - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodWhiteChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodWhiteChain], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.CrossChainManagerContractAddress, input) tr.Stop() @@ -341,9 +336,8 @@ func TestBlackChain(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(21000) caller := signers[0] - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodBlackChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[cross_chain_manager_abi.MethodBlackChain], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.CrossChainManagerContractAddress, input) tr.Stop() diff --git a/contracts/native/governance/side_chain_manager/side_chain_manager_test.go b/contracts/native/governance/side_chain_manager/side_chain_manager_test.go index 6081853f..bda2d649 100644 --- a/contracts/native/governance/side_chain_manager/side_chain_manager_test.go +++ b/contracts/native/governance/side_chain_manager/side_chain_manager_test.go @@ -71,12 +71,11 @@ func testRegisterSideChainManager(t *testing.T) { assert.Nil(t, err) blockNumber := big.NewInt(1) - extra := uint64(21000) tr := native.NewTimer(side_chain_manager_abi.MethodRegisterSideChain) for _, input := range [][]byte{input, input1} { caller := signers[0] tr.Start() - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodRegisterSideChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodRegisterSideChain], nil) ret, leftOverGas, err := contractRef.NativeCall(common.Address{}, utils.SideChainManagerContractAddress, input) tr.Stop() assert.Nil(t, err) @@ -114,8 +113,7 @@ func testApproveRegisterSideChain(t *testing.T) { for _, input := range [][]byte{input, input1} { caller := signers[0] blockNumber := big.NewInt(1) - extra := uint64(21000) - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveRegisterSideChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveRegisterSideChain], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr.Stop() @@ -127,7 +125,7 @@ func testApproveRegisterSideChain(t *testing.T) { assert.Equal(t, leftOverGas, uint64(0)) caller = signers[1] - contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveRegisterSideChain]+extra, nil) + contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveRegisterSideChain], nil) tr.Start() ret, leftOverGas, err = contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr.Stop() @@ -162,9 +160,8 @@ func testUpdateSideChain(t *testing.T) { tr := native.NewTimer(side_chain_manager_abi.MethodUpdateSideChain) for _, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(21000) caller := signers[0] - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodUpdateSideChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodUpdateSideChain], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(common.Address{}, utils.SideChainManagerContractAddress, input) tr.Stop() @@ -195,9 +192,8 @@ func testApproveUpdateSideChain(t *testing.T) { tr1 := native.NewTimer(side_chain_manager_abi.MethodGetSideChain) for i, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(21000) caller := signers[0] - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveUpdateSideChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveUpdateSideChain], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr.Stop() @@ -209,7 +205,7 @@ func testApproveUpdateSideChain(t *testing.T) { assert.Equal(t, leftOverGas, uint64(0)) caller = signers[1] - contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveUpdateSideChain]+extra, nil) + contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveUpdateSideChain], nil) tr.Start() ret, leftOverGas, err = contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr.Stop() @@ -233,7 +229,7 @@ func testApproveUpdateSideChain(t *testing.T) { input, err = utils.PackMethodWithStruct(ABI, side_chain_manager_abi.MethodGetSideChain, param) assert.Nil(t, err) - contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodGetSideChain]+extra, nil) + contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodGetSideChain], nil) tr1.Start() ret, leftOverGas, err = contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr1.Stop() @@ -262,9 +258,8 @@ func testQuiteSideChain(t *testing.T) { tr := native.NewTimer(side_chain_manager_abi.MethodQuitSideChain) for _, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(21000) caller := signers[0] - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodQuitSideChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodQuitSideChain], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr.Stop() @@ -293,9 +288,8 @@ func TestApproveQuiteSideChain(t *testing.T) { tr := native.NewTimer(side_chain_manager_abi.MethodApproveQuitSideChain) for i, input := range [][]byte{input, input1} { blockNumber := big.NewInt(1) - extra := uint64(21000) caller := signers[0] - contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveQuitSideChain]+extra, nil) + contractRef := native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveQuitSideChain], nil) tr.Start() ret, leftOverGas, err := contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr.Stop() @@ -307,7 +301,7 @@ func TestApproveQuiteSideChain(t *testing.T) { assert.Equal(t, leftOverGas, uint64(0)) caller = signers[1] - contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveQuitSideChain]+extra, nil) + contractRef = native.NewContractRef(sdb, caller, caller, blockNumber, common.Hash{}, gasTable[side_chain_manager_abi.MethodApproveQuitSideChain], nil) tr.Start() ret, leftOverGas, err = contractRef.NativeCall(caller, utils.SideChainManagerContractAddress, input) tr.Stop() diff --git a/contracts/native/test.go b/contracts/native/test.go index bfc4decf..df2ea44f 100644 --- a/contracts/native/test.go +++ b/contracts/native/test.go @@ -103,7 +103,7 @@ func GenerateTestContext(t *testing.T, value *big.Int, address common.Address, p } blockHeight := new(big.Int).SetInt64(int64(block)) - contractRef := NewContractRef(sdb, sender, caller, blockHeight, hash, supplyGas + 21000, nil) + contractRef := NewContractRef(sdb, sender, caller, blockHeight, hash, supplyGas, nil) contractRef.SetValue(value) contractRef.SetTo(address) ctx := NewNativeContract(sdb, contractRef) From 99bb7a07aaedecc9db820fb0246a3aa780a1fd7f Mon Sep 17 00:00:00 2001 From: Stefan Liu Date: Fri, 15 Sep 2023 16:05:42 +0800 Subject: [PATCH 12/12] Fix system tx hash issue --- consensus/hotstuff/backend/engine.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensus/hotstuff/backend/engine.go b/consensus/hotstuff/backend/engine.go index 570be4e2..b56c3f0a 100644 --- a/consensus/hotstuff/backend/engine.go +++ b/consensus/hotstuff/backend/engine.go @@ -131,8 +131,8 @@ func (s *backend) BlockTransactions(block *types.Block, state *state.StateDB) (t signer := types.MakeSigner(s.chainConfig, block.Number()) for i, tx := range systemTransactions { includedTx := allTransactions[commonTransactionCount + i] - if includedTx.Hash() != tx.Hash() { - return nil, nil, nil, fmt.Errorf("unexpected system tx hash detected, tx index %v, hash %s, expected: %s", commonTransactionCount + i, includedTx.Hash(), tx.Hash()) + if signer.Hash(includedTx) != signer.Hash(tx) { + return nil, nil, nil, fmt.Errorf("unexpected system tx hash detected, tx index %v, hash %s, expected: %s", commonTransactionCount + i, signer.Hash(includedTx), signer.Hash(tx)) } from, err := signer.Sender(includedTx) if err != nil {