diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go
index b03c636d..77450a71 100644
--- a/consensus/clique/clique.go
+++ b/consensus/clique/clique.go
@@ -568,14 +568,20 @@ 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
+// 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
+}
+
// 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..bac9e2de 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.
@@ -165,12 +169,6 @@ type HotStuff interface {
// FillHeader fulfill the header with extra which contains epoch change info
FillHeader(state *state.StateDB, header *types.Header) error
-
- // IsSystemCall return method id and true if the tx is an system transaction
- IsSystemTransaction(tx *types.Transaction, header *types.Header) (string, bool)
-
- // HasSystemTxHook return true if systemTxHook is not nil
- HasSystemTxHook() bool
}
// Handler should be implemented is the consensus needs to handle and send peer's message
diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index 6b0d72c3..daa450b9 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -586,20 +586,26 @@ 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
+// 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
+}
+
// 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
deleted file mode 100644
index f6582a9d..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(ctx *systemTxContext) error {
- return s.executeTransaction(ctx, contractAddr, 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 3b4b7566..c9e6cd3b 100644
--- a/consensus/hotstuff/backend/engine.go
+++ b/consensus/hotstuff/backend/engine.go
@@ -24,11 +24,16 @@ 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/governance"
+ "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 +114,48 @@ 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
+// 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 := governance.AssembleSystemTransactions(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, tx index %v, hash %s, expected: %s", commonTransactionCount + i, includedTx.Hash(), 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 +172,32 @@ 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 := governance.AssembleSystemTransactions(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
+ }
+ 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 {
+ return nil, nil, err
+ }
+ txs = append(txs, tx)
+ receipts = append(receipts, receipt)
}
// Assemble and return the final block for sealing
@@ -145,42 +205,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 6d26e1ee..14c32dec 100644
--- a/consensus/hotstuff/backend/governance.go
+++ b/consensus/hotstuff/backend/governance.go
@@ -22,7 +22,6 @@ import (
"fmt"
"sync/atomic"
- "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"
@@ -41,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
}
@@ -73,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
@@ -112,76 +111,6 @@ func (s *backend) Validators(height uint64, mining bool) (hotstuff.ValidatorSet,
return vals, nil
}
-// 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
- }
-
- 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
- }
-}
-
-// 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
- }
-
- end := epoch.EndHeight.Uint64()
- height := header.Number.Uint64()
- if height != end-1 {
- return nil
- }
-
- payload, err := new(nm.ChangeEpochParam).Encode()
- if err != nil {
- return err
- }
- if err := s.executeTransaction(ctx, contractAddr, payload); err != nil {
- return err
- }
-
- log.Info("Execute governance EpochChange", "end", end, "current", height)
- return 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
-}
-
-// 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..b371f291 100644
--- a/consensus/hotstuff/backend/utils.go
+++ b/consensus/hotstuff/backend/utils.go
@@ -19,45 +19,17 @@
package backend
import (
- "bytes"
- "encoding/hex"
- "fmt"
- "math"
- "math/big"
- "sync"
-
- "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/core/vm"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)
// =========================== 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
@@ -73,204 +45,18 @@ 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
-)
-
-// 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
- hash := common.EmptyHash
- 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
}
-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 (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/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..1fc72299 100644
--- a/contracts/native/economic/economic.go
+++ b/contracts/native/economic/economic.go
@@ -24,8 +24,9 @@ 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/governance/community"
"github.com/ethereum/go-ethereum/contracts/native/utils"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
@@ -70,24 +71,23 @@ 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) {
+ 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)
+ 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{
@@ -99,7 +99,39 @@ 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..0ce0ff73
--- /dev/null
+++ b/contracts/native/governance/entrance.go
@@ -0,0 +1,78 @@
+/*
+ * 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"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/contracts/native/go_abi/node_manager_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/core"
+ "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
+ }
+ gas, err := core.IntrinsicGas(payload, nil, false, true, true)
+ if err != nil {
+ return nil, err
+ }
+ gas += nm.GasTable[node_manager_abi.MethodEndBlock]
+ txs = append(txs, types.NewTransaction(systemSenderNonce, utils.NodeManagerContractAddress, common.Big0, gas, common.Big0, 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
+ }
+ gas, err := core.IntrinsicGas(payload, nil, false, true, true)
+ if err != nil {
+ return nil, err
+ }
+ gas += nm.GasTable[node_manager_abi.MethodChangeEpoch]
+ txs = append(txs, types.NewTransaction(systemSenderNonce + 1, utils.NodeManagerContractAddress, common.Big0, gas, common.Big0, 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 7c501446..7bd7a741 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..bab206c1 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"
)
@@ -48,7 +50,7 @@ var (
// the real gas usage of `createValidator`,`changeEpoch`,`endBlock` are 1291500, 5087250 and 343875.
// in order to lower the total gas usage in an entire block, modify them to be 300000 and 200000, 150000.
var (
- gasTable = map[string]uint64{
+ GasTable = map[string]uint64{
MethodCreateValidator: 300000,
MethodUpdateValidator: 170625,
MethodUpdateCommission: 126000,
@@ -86,7 +88,7 @@ func InitNodeManager() {
}
func RegisterNodeManagerContract(s *native.NativeContract) {
- s.Prepare(ABI, gasTable)
+ s.Prepare(ABI, GasTable)
s.Register(MethodCreateValidator, CreateValidator)
s.Register(MethodUpdateValidator, UpdateValidator)
@@ -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..59be8461 100644
--- a/contracts/native/utils/params.go
+++ b/contracts/native/utils/params.go
@@ -17,7 +17,9 @@
*/
package utils
-import "github.com/ethereum/go-ethereum/common"
+import (
+ "github.com/ethereum/go-ethereum/common"
+)
var (
BYTE_FALSE = []byte{0}
@@ -43,4 +45,4 @@ var (
ETH_COMMON_ROUTER = uint64(2)
RIPPLE_ROUTER = uint64(6)
-)
+)
\ No newline at end of file
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
diff --git a/core/state_processor.go b/core/state_processor.go
index 34fb19b9..ce2f2cc5 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,24 @@ 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 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)
}
- for id, cnt := range systemTxIds {
- if cnt > 1 {
- return nil, nil, 0, fmt.Errorf("system tx %s dumplicated %d ", id, cnt)
- }
+ 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)
}
// 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 +175,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)
+}