Merge pull request #451 from nguyenbatam/version_1_3

New Version 1.3
This commit is contained in:
Tuna 2019-03-05 17:43:35 +07:00 committed by GitHub
commit 3c868707f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 751 additions and 234 deletions

270
cmd/tomoclean/main.go Normal file
View file

@ -0,0 +1,270 @@
package main
import (
"flag"
"fmt"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/hashicorp/golang-lru"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
"os"
"os/signal"
"runtime"
"sync"
"sync/atomic"
"time"
)
var (
dir = flag.String("dir", "", "dir to mainet chain data")
cacheSize = flag.Int("size", 1000000, "dir to mainet chain data")
)
type TrieRoot struct {
trie *trie.SecureTrie
number uint64
}
type StateNode struct {
node trie.Node
path []byte
}
type ResultProcessNode struct {
index int
number int
newNodes [17]*StateNode
keys [17]*[]byte
}
var sercureKey = []byte("secure-key-")
var nWorker = runtime.NumCPU() / 2
var cleanAddress = []common.Address{common.HexToAddress(common.BlockSigners)}
var cache *lru.Cache
var finish = int32(0)
var running = true
var stateRoots = make(chan TrieRoot)
func main() {
flag.Parse()
lddb, _ := ethdb.NewLDBDatabase(*dir, eth.DefaultConfig.DatabaseCache, utils.MakeDatabaseHandles())
head := core.GetHeadBlockHash(lddb)
currentHeader := core.GetHeader(lddb, head, core.GetBlockNumber(lddb, head))
tridb := trie.NewDatabase(lddb)
catchEventInterupt(lddb.LDB())
cache, _ = lru.New(*cacheSize)
go func() {
for i := uint64(1); i <= currentHeader.Number.Uint64(); i++ {
hash := core.GetCanonicalHash(lddb, i)
root := core.GetHeader(lddb, hash, i).Root
trieRoot, err := trie.NewSecure(root, tridb, 0)
if err != nil {
continue
}
if running {
stateRoots <- TrieRoot{trieRoot, i}
} else {
break
}
}
if running {
close(stateRoots)
}
}()
for trieRoot := range stateRoots {
atomic.StoreInt32(&finish, 1)
if running {
for _, address := range cleanAddress {
enc := trieRoot.trie.Get(address.Bytes())
var data state.Account
rlp.DecodeBytes(enc, &data)
fmt.Println(time.Now().Format(time.RFC3339), "Start clean state address ", address.Hex(), " at block ", trieRoot.number)
signerRoot, err := resolveHash(data.Root[:], lddb.LDB())
if err != nil {
fmt.Println(time.Now().Format(time.RFC3339), "Not found clean state address ", address.Hex(), " at block ", trieRoot.number)
continue
}
batch := new(leveldb.Batch)
count := 1
list := []*StateNode{{node: signerRoot}}
for len(list) > 0 {
newList, total := findNewNodes(list, lddb.LDB(), batch)
count = count + 17*len(newList)
list = removeNodesNil(newList, total)
}
fmt.Println(time.Now().Format(time.RFC3339), "Finish clean state address ", address.Hex(), " at block ", trieRoot.number, " keys ", count)
err = lddb.LDB().Write(batch, nil)
if err != nil {
fmt.Println(time.Now().Format(time.RFC3339), "Write batch leveldb error", err)
os.Exit(1)
}
}
} else {
break
}
atomic.StoreInt32(&finish, 0)
}
fmt.Println(time.Now(), "compact")
lddb.LDB().CompactRange(util.Range{})
lddb.Close()
fmt.Println(time.Now(), "end")
}
func removeNodesNil(list [][17]*StateNode, length int) []*StateNode {
results := make([]*StateNode, length)
index := 0
for _, nodes := range list {
for _, node := range nodes {
if node != nil {
results[index] = node
index++
}
}
}
return results
}
func catchEventInterupt(db *leveldb.DB) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
fmt.Println("catch event interrupt ", sig, running, finish)
running = false
if atomic.LoadInt32(&finish) == 0 {
close(stateRoots)
db.Close()
os.Exit(1)
}
}
}()
}
func resolveHash(n trie.HashNode, db *leveldb.DB) (trie.Node, error) {
if cache.Contains(common.BytesToHash(n)) {
return nil, &trie.MissingNodeError{}
}
enc, err := db.Get(n, nil)
if err != nil || enc == nil {
return nil, &trie.MissingNodeError{}
}
return trie.MustDecodeNode(n, enc, 0), nil
}
func getAllChilds(n StateNode, db *leveldb.DB) ([17]*StateNode, error) {
childs := [17]*StateNode{}
switch node := n.node.(type) {
case *trie.FullNode:
// Full Node, move to the first non-nil child.
for i := 0; i < len(node.Children); i++ {
child := node.Children[i]
if child != nil {
childNode := child
var err error = nil
if _, ok := child.(trie.HashNode); ok {
childNode, err = resolveHash(child.(trie.HashNode), db)
}
if err == nil {
childs[i] = &StateNode{node: childNode, path: append(n.path, byte(i))}
} else if err != nil {
_, ok := err.(*trie.MissingNodeError)
if !ok {
return childs, err
}
}
}
}
case *trie.ShortNode:
// Short Node, return the pointer singleton child
childNode := node.Val
var err error = nil
if _, ok := node.Val.(trie.HashNode); ok {
childNode, err = resolveHash(node.Val.(trie.HashNode), db)
}
if err == nil {
childs[0] = &StateNode{node: childNode, path: append(n.path, node.Key...)}
} else if err != nil {
_, ok := err.(*trie.MissingNodeError)
if !ok {
return childs, err
}
}
}
return childs, nil
}
func processNodes(node StateNode, db *leveldb.DB) ([17]*StateNode, [17]*[]byte, int) {
hash, _ := node.node.Cache()
commonHash := common.BytesToHash(hash)
newNodes := [17]*StateNode{}
keys := [17]*[]byte{}
number := 0
if !cache.Contains(commonHash) {
childNodes, err := getAllChilds(node, db)
if err != nil {
fmt.Println("Error when get all childs node : ", common.Bytes2Hex(node.path), err)
os.Exit(1)
}
for i, child := range childNodes {
if child != nil {
if _, ok := child.node.(trie.ValueNode); ok {
buf := append(sercureKey, child.path...)
keys[i] = &buf
} else {
hash, _ := child.node.Cache()
var bytes []byte = hash
keys[i] = &bytes
newNodes[i] = child
number++
}
}
}
cache.Add(commonHash, true)
}
return newNodes, keys, number
}
func findNewNodes(nodes []*StateNode, db *leveldb.DB, batchlvdb *leveldb.Batch) ([][17]*StateNode, int) {
length := len(nodes)
chunkSize := length / nWorker
if len(nodes)%nWorker != 0 {
chunkSize++
}
childNodes := make([][17]*StateNode, length)
results := make(chan ResultProcessNode)
wg := sync.WaitGroup{}
wg.Add(length)
for i := 0; i < nWorker; i++ {
from := i * chunkSize
to := from + chunkSize
if to > length {
to = length
}
go func(from int, to int) {
for j := from; j < to; j++ {
childs, keys, number := processNodes(*nodes[j], db)
go func(result ResultProcessNode) {
results <- result
}(ResultProcessNode{j, number, childs, keys})
}
}(from, to)
}
total := 0
go func() {
for result := range results {
childNodes[result.index] = result.newNodes
total = total + result.number
for _, key := range result.keys {
if key != nil {
batchlvdb.Delete(*key)
}
}
wg.Done()
}
}()
wg.Wait()
close(results)
return childNodes, total
}

View file

@ -747,9 +747,9 @@ func setIPC(ctx *cli.Context, cfg *node.Config) {
} }
} }
// makeDatabaseHandles raises out the number of allowed file handles per process // MakeDatabaseHandles raises out the number of allowed file handles per process
// for tomo and returns half of the allowance to assign to the database. // for tomo and returns half of the allowance to assign to the database.
func makeDatabaseHandles() int { func MakeDatabaseHandles() int {
limit, err := fdlimit.Current() limit, err := fdlimit.Current()
if err != nil { if err != nil {
Fatalf("Failed to retrieve file descriptor allowance: %v", err) Fatalf("Failed to retrieve file descriptor allowance: %v", err)
@ -1066,7 +1066,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
} }
cfg.DatabaseHandles = makeDatabaseHandles() cfg.DatabaseHandles = MakeDatabaseHandles()
if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
@ -1212,7 +1212,7 @@ func SetupNetwork(ctx *cli.Context) {
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
var ( var (
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
handles = makeDatabaseHandles() handles = MakeDatabaseHandles()
) )
name := "chaindata" name := "chaindata"
if ctx.GlobalBool(LightModeFlag.Name) { if ctx.GlobalBool(LightModeFlag.Name) {

View file

@ -18,10 +18,13 @@ const (
LimitThresholdNonceInQueue = 10 LimitThresholdNonceInQueue = 10
DefaultMinGasPrice = 2500 DefaultMinGasPrice = 2500
MergeSignRange = 15 MergeSignRange = 15
RangeReturnSigner = 150
MinimunMinerBlockPerEpoch = 1
) )
var TIP2019Block = big.NewInt(1050000) var TIP2019Block = big.NewInt(1050000)
var IsTestnet = false var TIPSigning = big.NewInt(3000000)
var IsTestnet bool = false
var StoreRewardFolder string var StoreRewardFolder string
var RollbackHash Hash var RollbackHash Hash
var MinGasPrice int64 var MinGasPrice int64

View file

@ -228,6 +228,7 @@ type Posv struct {
BlockSigners *lru.Cache BlockSigners *lru.Cache
HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{})
HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error)
HookPenaltyTIPSigning func(chain consensus.ChainReader, header *types.Header, candidate []common.Address) ([]common.Address, error)
HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) HookValidator func(header *types.Header, signers []common.Address) ([]byte, error)
HookVerifyMNs func(header *types.Header, signers []common.Address) error HookVerifyMNs func(header *types.Header, signers []common.Address) error
} }
@ -397,9 +398,15 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.
} }
// If the block is a checkpoint block, verify the signer list // If the block is a checkpoint block, verify the signer list
if number%c.config.Epoch == 0 { if number%c.config.Epoch == 0 {
signers := snap.GetSigners()
penPenalties := []common.Address{} penPenalties := []common.Address{}
if c.HookPenalty != nil { if c.HookPenalty != nil || c.HookPenaltyTIPSigning != nil {
var err error = nil
if chain.Config().IsTIPSigning(header.Number) {
penPenalties, err = c.HookPenaltyTIPSigning(chain, header, signers)
} else {
penPenalties, err = c.HookPenalty(chain, number) penPenalties, err = c.HookPenalty(chain, number)
}
if err != nil { if err != nil {
return err return err
} }
@ -411,7 +418,6 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.
return errInvalidCheckpointPenalties return errInvalidCheckpointPenalties
} }
} }
signers := snap.GetSigners()
signers = common.RemoveItemFromArray(signers, penPenalties) signers = common.RemoveItemFromArray(signers, penPenalties)
for i := 1; i <= common.LimitPenaltyEpoch; i++ { for i := 1; i <= common.LimitPenaltyEpoch; i++ {
if number > uint64(i)*c.config.Epoch { if number > uint64(i)*c.config.Epoch {
@ -788,8 +794,14 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error
header.Extra = header.Extra[:extraVanity] header.Extra = header.Extra[:extraVanity]
masternodes := snap.GetSigners() masternodes := snap.GetSigners()
if number >= c.config.Epoch && number%c.config.Epoch == 0 { if number >= c.config.Epoch && number%c.config.Epoch == 0 {
if c.HookPenalty != nil { if c.HookPenalty != nil || c.HookPenaltyTIPSigning != nil {
penMasternodes, err := c.HookPenalty(chain, number) var penMasternodes []common.Address = nil
var err error = nil
if chain.Config().IsTIPSigning(header.Number) {
penMasternodes, err = c.HookPenaltyTIPSigning(chain, header, masternodes)
} else {
penMasternodes, err = c.HookPenalty(chain, number)
}
if err != nil { if err != nil {
return err return err
} }
@ -797,7 +809,7 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error
// penalize bad masternode(s) // penalize bad masternode(s)
masternodes = common.RemoveItemFromArray(masternodes, penMasternodes) masternodes = common.RemoveItemFromArray(masternodes, penMasternodes)
for _, address := range penMasternodes { for _, address := range penMasternodes {
log.Debug("Penalty status", "address", address, "block number", number) log.Debug("Penalty status", "address", address, "number", number)
} }
header.Penalties = common.ExtractAddressToBytes(penMasternodes) header.Penalties = common.ExtractAddressToBytes(penMasternodes)
} }
@ -1036,8 +1048,8 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea
return masternodes return masternodes
} }
func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) error { func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) []*types.Transaction {
var signTxs []*types.Transaction signTxs := []*types.Transaction{}
for _, tx := range txs { for _, tx := range txs {
if tx.IsSigningTransaction() { if tx.IsSigningTransaction() {
var b uint var b uint
@ -1063,7 +1075,19 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt
log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs)) log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs))
c.BlockSigners.Add(header.Hash(), signTxs) c.BlockSigners.Add(header.Hash(), signTxs)
return nil return signTxs
}
func (c *Posv) CacheSigner(hash common.Hash, txs []*types.Transaction) []*types.Transaction {
signTxs := []*types.Transaction{}
for _, tx := range txs {
if tx.IsSigningTransaction() {
signTxs = append(signTxs, tx)
}
}
log.Debug("Save tx signers to cache", "hash", hash.String(), "len(txs)", len(signTxs))
c.BlockSigners.Add(hash, signTxs)
return signTxs
} }
func (c *Posv) GetDb() ethdb.Database { func (c *Posv) GetDb() ethdb.Database {

View file

@ -320,46 +320,24 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, header *t
for i := prevCheckpoint + (rCheckpoint * 2) - 1; i >= startBlockNumber; i-- { for i := prevCheckpoint + (rCheckpoint * 2) - 1; i >= startBlockNumber; i-- {
header = chain.GetHeader(header.ParentHash, i) header = chain.GetHeader(header.ParentHash, i)
mapBlkHash[i] = header.Hash() mapBlkHash[i] = header.Hash()
if signData, ok := c.BlockSigners.Get(header.Hash()); ok { signData, ok := c.BlockSigners.Get(header.Hash())
if !ok {
log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i)
block := chain.GetBlock(header.Hash(), i)
txs := block.Transactions()
if !chain.Config().IsTIPSigning(header.Number) {
receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i)
signData = c.CacheData(header, txs, receipts)
} else {
signData = c.CacheSigner(header.Hash(), txs)
}
}
txs := signData.([]*types.Transaction) txs := signData.([]*types.Transaction)
for _, tx := range txs { for _, tx := range txs {
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
from := *tx.From() from := *tx.From()
data[blkHash] = append(data[blkHash], from) data[blkHash] = append(data[blkHash], from)
} }
} else {
log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i)
block := chain.GetBlock(header.Hash(), i)
txs := block.Transactions()
receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i)
var signTxs []*types.Transaction
for _, tx := range txs {
if tx.IsSigningTransaction() {
var b uint
for _, r := range receipts {
if r.TxHash == tx.Hash() {
if len(r.PostState) > 0 {
b = types.ReceiptStatusSuccessful
} else {
b = r.Status
}
break
}
}
if b == types.ReceiptStatusFailed {
continue
}
signTxs = append(signTxs, tx)
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
from := *tx.From()
data[blkHash] = append(data[blkHash], from)
}
}
c.BlockSigners.Add(header.Hash(), signTxs)
}
} }
header = chain.GetHeader(header.ParentHash, prevCheckpoint) header = chain.GetHeader(header.ParentHash, prevCheckpoint)
masternodes := posv.GetMasternodesFromCheckpointHeader(header) masternodes := posv.GetMasternodesFromCheckpointHeader(header)

View file

@ -507,7 +507,7 @@ func (bc *BlockChain) insert(block *types.Block) {
bc.currentBlock.Store(block) bc.currentBlock.Store(block)
// save cache BlockSigners // save cache BlockSigners
if bc.chainConfig.Posv != nil { if bc.chainConfig.Posv != nil && !bc.chainConfig.IsTIPSigning(block.Number()) {
engine := bc.Engine().(*posv.Posv) engine := bc.Engine().(*posv.Posv)
engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash()))
} }
@ -1019,6 +1019,11 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
if status == CanonStatTy { if status == CanonStatTy {
bc.insert(block) bc.insert(block)
} }
// save cache BlockSigners
if bc.chainConfig.Posv != nil && bc.chainConfig.IsTIPSigning(block.Number()) {
engine := bc.Engine().(*posv.Posv)
engine.CacheSigner(block.Header().Hash(), block.Transactions())
}
bc.futureBlocks.Remove(block.Hash()) bc.futureBlocks.Remove(block.Hash())
return status, nil return status, nil
} }

View file

@ -357,6 +357,14 @@ func (self *StateDB) deleteStateObject(stateObject *stateObject) {
self.setError(self.trie.TryDelete(addr[:])) self.setError(self.trie.TryDelete(addr[:]))
} }
// DeleteAddress removes the address from the state trie.
func (self *StateDB) DeleteAddress(addr common.Address) {
stateObject := self.getStateObject(addr)
if stateObject != nil && !stateObject.deleted {
self.deleteStateObject(stateObject)
}
}
// Retrieve a state object given my the address. Returns nil if not found. // Retrieve a state object given my the address. Returns nil if not found.
func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) { func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
// Prefer 'live' objects. // Prefer 'live' objects.

View file

@ -73,6 +73,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
if common.TIPSigning.Cmp(header.Number) == 0 {
statedb.DeleteAddress(common.HexToAddress(common.BlockSigners))
}
InitSignerInTransactions(p.config, header, block.Transactions()) InitSignerInTransactions(p.config, header, block.Transactions())
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i) statedb.Prepare(tx.Hash(), block.Hash(), i)
@ -101,6 +104,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
if common.TIPSigning.Cmp(header.Number) == 0 {
statedb.DeleteAddress(common.HexToAddress(common.BlockSigners))
}
if cBlock.stop { if cBlock.stop {
return nil, nil, 0, ErrStopPreparingBlock return nil, nil, 0, ErrStopPreparingBlock
} }
@ -132,6 +138,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
// for the transaction, gas used and an error if the transaction failed, // for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid. // indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) {
if tx.To() != nil && tx.To().String() == common.BlockSigners && config.IsTIPSigning(header.Number) {
return ApplySignTransaction(config, statedb, header, tx, usedGas)
}
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
@ -171,6 +180,41 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
return receipt, gas, err return receipt, gas, err
} }
func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, error) {
// Update the state with pending changes
var root []byte
if config.IsByzantium(header.Number) {
statedb.Finalise(true)
} else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
}
from, err := types.Sender(types.MakeSigner(config, header.Number), tx)
if err != nil {
return nil, 0, err
}
nonce := statedb.GetNonce(from)
if nonce < tx.Nonce() {
return nil, 0, ErrNonceTooHigh
} else if nonce > tx.Nonce() {
return nil, 0, ErrNonceTooLow
}
statedb.SetNonce(from, nonce+1)
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
// based on the eip phase, we're passing wether the root touch-delete accounts.
receipt := types.NewReceipt(root, false, *usedGas)
receipt.TxHash = tx.Hash()
receipt.GasUsed = 0
// if the transaction created a contract, store the creation address in the receipt.
// Set the receipt logs and create a bloom for filtering
log := &types.Log{}
log.Address = common.HexToAddress(common.BlockSigners)
log.BlockNumber = header.Number.Uint64()
statedb.AddLog(log)
receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
return receipt, 0, nil
}
func InitSignerInTransactions(config *params.ChainConfig, header *types.Header, txs types.Transactions) { func InitSignerInTransactions(config *params.ChainConfig, header *types.Header, txs types.Transactions) {
nWorker := runtime.NumCPU() nWorker := runtime.NumCPU()
signer := types.MakeSigner(config, header.Number) signer := types.MakeSigner(config, header.Number)

View file

@ -219,7 +219,7 @@ type TxPool struct {
wg sync.WaitGroup // for shutdown sync wg sync.WaitGroup // for shutdown sync
homestead bool homestead bool
IsMasterNode func(address common.Address) bool IsSigner func(address common.Address) bool
} }
// NewTxPool creates a new transaction pool to gather, sort and filter inbound // NewTxPool creates a new transaction pool to gather, sort and filter inbound
@ -592,7 +592,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Drop non-local transactions under our own minimal accepted gas price // Drop non-local transactions under our own minimal accepted gas price
local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
if !tx.IsSpecialTransaction() || (pool.IsMasterNode != nil && !pool.IsMasterNode(from)) { if !tx.IsSpecialTransaction() || (pool.IsSigner != nil && !pool.IsSigner(from)) {
return ErrUnderpriced return ErrUnderpriced
} }
} }
@ -661,7 +661,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
return false, err return false, err
} }
from, _ := types.Sender(pool.signer, tx) // already validated from, _ := types.Sender(pool.signer, tx) // already validated
if tx.IsSpecialTransaction() && pool.IsMasterNode != nil && pool.IsMasterNode(from) && pool.pendingState.GetNonce(from) == tx.Nonce() { if tx.IsSpecialTransaction() && pool.IsSigner != nil && pool.IsSigner(from) && pool.pendingState.GetNonce(from) == tx.Nonce() {
return pool.promoteSpecialTx(from, tx) return pool.promoteSpecialTx(from, tx)
} }
// If the transaction pool is full, discard underpriced transactions // If the transaction pool is full, discard underpriced transactions

View file

@ -20,6 +20,10 @@ package eth
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/rlp"
"math/big" "math/big"
"runtime" "runtime"
"sync" "sync"
@ -29,19 +33,16 @@ import (
"bytes" "bytes"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/consensus/posv" "github.com/ethereum/go-ethereum/consensus/posv"
"github.com/ethereum/go-ethereum/contracts" "github.com/ethereum/go-ethereum/contracts"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/state"
//"github.com/ethereum/go-ethereum/core/state" //"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
@ -51,7 +52,6 @@ import (
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -208,12 +208,13 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if eth.chainConfig.Posv != nil { if eth.chainConfig.Posv != nil {
c := eth.engine.(*posv.Posv) c := eth.engine.(*posv.Posv)
signHook := func(block *types.Block) error { signHook := func(block *types.Block) error {
ok, err := eth.ValidateMasternode() eb, err := eth.Etherbase()
if err != nil { if err != nil {
return fmt.Errorf("Can't verify masternode permission: %v", err) log.Error("Cannot get etherbase for append m2 header", "err", err)
return fmt.Errorf("etherbase missing: %v", err)
} }
ok := eth.txPool.IsSigner != nil && eth.txPool.IsSigner(eb)
if !ok { if !ok {
// silently return as this node doesn't have masternode permission to sign block
return nil return nil
} }
if block.NumberU64()%common.MergeSignRange == 0 || !eth.chainConfig.IsTIP2019(block.Number()) { if block.NumberU64()%common.MergeSignRange == 0 || !eth.chainConfig.IsTIP2019(block.Number()) {
@ -309,6 +310,113 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return []common.Address{}, nil return []common.Address{}, nil
} }
// Hook scans for bad masternodes and decide to penalty them
c.HookPenaltyTIPSigning = func(chain consensus.ChainReader, header *types.Header, candidates []common.Address) ([]common.Address, error) {
prevEpoc := header.Number.Uint64() - chain.Config().Posv.Epoch
combackEpoch := uint64(0)
comebackLength := uint64((common.LimitPenaltyEpoch + 1) * chain.Config().Posv.Epoch)
if header.Number.Uint64() > comebackLength {
combackEpoch = header.Number.Uint64() - comebackLength
}
if prevEpoc >= 0 {
start := time.Now()
listBlockHash := make([]common.Hash, chain.Config().Posv.Epoch)
// get list block hash & stats total created block
statMiners := make(map[common.Address]int)
listBlockHash[0] = header.ParentHash
parentnumber := header.Number.Uint64() - 1
parentHash := header.ParentHash
for i := uint64(1); i < chain.Config().Posv.Epoch; i++ {
parentHeader := chain.GetHeader(parentHash, parentnumber)
miner, _ := c.RecoverSigner(parentHeader)
value, exist := statMiners[miner]
if exist {
value = value + 1
} else {
value = 1
}
statMiners[miner] = value
parentHash = parentHeader.ParentHash
parentnumber--
listBlockHash[i] = parentHash
}
// add list not miner to penalties
prevHeader := chain.GetHeaderByNumber(prevEpoc)
preMasternodes := c.GetMasternodes(chain, prevHeader)
penalties := []common.Address{}
for miner, total := range statMiners {
if total < common.MinimunMinerBlockPerEpoch {
log.Debug("Find a node not enough requirement create block", "addr", miner.Hex(), "total", total)
penalties = append(penalties, miner)
}
}
for _, addr := range preMasternodes {
if _, exist := statMiners[addr]; !exist {
log.Debug("Find a node don't create block", "addr", addr.Hex())
penalties = append(penalties, addr)
}
}
// get list check penalties signing block & list master nodes wil comeback
penComebacks := []common.Address{}
if combackEpoch > 0 {
combackHeader := chain.GetHeaderByNumber(combackEpoch)
penalties := common.ExtractAddressFromBytes(combackHeader.Penalties)
for _, penaltie := range penalties {
for _, addr := range candidates {
if penaltie == addr {
penComebacks = append(penComebacks, penaltie)
}
}
}
}
// Loop for each block to check missing sign. with comeback nodes
mapBlockHash := map[common.Hash]bool{}
for i := common.RangeReturnSigner - 1; i >= 0; i-- {
if len(penComebacks) > 0 {
blockNumber := header.Number.Uint64() - uint64(i) - 1
bhash := listBlockHash[i]
if blockNumber%common.MergeSignRange == 0 {
mapBlockHash[bhash] = true
}
signData, ok := c.BlockSigners.Get(bhash)
if !ok {
block := chain.GetBlock(bhash, blockNumber)
txs := block.Transactions()
signData = c.CacheSigner(bhash, txs)
}
txs := signData.([]*types.Transaction)
// Check signer signed?
for _, tx := range txs {
blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])
from := *tx.From()
if mapBlockHash[blkHash] {
for j, addr := range penComebacks {
if from == addr {
// Remove it from dupSigners.
penComebacks = append(penComebacks[:j], penComebacks[j+1:]...)
break
}
}
}
}
} else {
break
}
}
log.Debug("Time Calculated HookPenaltyTIPSigning ", "block", header.Number, "hash", header.Hash().Hex(), "pen comeback nodes", len(penComebacks), "not enough miner", len(penalties), "time", common.PrettyDuration(time.Since(start)))
penalties = append(penalties, penComebacks...)
return penComebacks, nil
}
return []common.Address{}, nil
}
// Hook calculates reward for masternodes // Hook calculates reward for masternodes
c.HookReward = func(chain consensus.ChainReader, stateBlock *state.StateDB, header *types.Header) (error, map[string]interface{}) { c.HookReward = func(chain consensus.ChainReader, stateBlock *state.StateDB, header *types.Header) (error, map[string]interface{}) {
parentHeader := eth.blockchain.GetHeader(header.ParentHash, header.Number.Uint64()-1) parentHeader := eth.blockchain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
@ -382,7 +490,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return nil return nil
} }
eth.txPool.IsMasterNode = func(address common.Address) bool { eth.txPool.IsSigner = func(address common.Address) bool {
currentHeader := eth.blockchain.CurrentHeader() currentHeader := eth.blockchain.CurrentHeader()
header := currentHeader header := currentHeader
// Sometimes, the latest block hasn't been inserted to chain yet // Sometimes, the latest block hasn't been inserted to chain yet
@ -630,7 +738,9 @@ func (s *Ethereum) StartStaking(local bool) error {
return nil return nil
} }
func (s *Ethereum) StopStaking() { s.miner.Stop() } func (s *Ethereum) StopStaking() {
s.miner.Stop()
}
func (s *Ethereum) IsStaking() bool { return s.miner.Mining() } func (s *Ethereum) IsStaking() bool { return s.miner.Mining() }
func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) Miner() *miner.Miner { return s.miner }

View file

@ -1044,36 +1044,43 @@ func (s *PublicBlockChainAPI) rpcOutputBlockSigners(b *types.Block, ctx context.
var signers []common.Address var signers []common.Address
var filterSigners []common.Address var filterSigners []common.Address
if b.Number().Int64() > 0 { if b.Number().Int64() > 0 {
curBlockNumber := b.Number().Uint64() blockNumber := b.Number().Uint64()
prevBlockNumber := curBlockNumber + (common.MergeSignRange - (curBlockNumber % common.MergeSignRange)) signedBlockNumber := blockNumber + (common.MergeSignRange - (blockNumber % common.MergeSignRange))
latestBlockNumber := s.b.CurrentBlock().Number().Uint64() latestBlockNumber := s.b.CurrentBlock().Number()
if prevBlockNumber >= latestBlockNumber || !s.b.ChainConfig().IsTIP2019(b.Number()) { if signedBlockNumber >= latestBlockNumber.Uint64() || !s.b.ChainConfig().IsTIP2019(b.Number()) {
prevBlockNumber = curBlockNumber signedBlockNumber = blockNumber
} }
if engine, ok := s.b.GetEngine().(*posv.Posv); ok { if engine, ok := s.b.GetEngine().(*posv.Posv); ok {
prevBlock, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(prevBlockNumber)) // Get block epoc latest.
if err != nil { lastCheckpointNumber := signedBlockNumber - (signedBlockNumber % s.b.ChainConfig().Posv.Epoch)
log.Error("Fail to get previous block", "error", err) prevCheckpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(lastCheckpointNumber))
return []common.Address{}, err if prevCheckpointBlock != nil {
masternodes := engine.GetMasternodesFromCheckpointHeader(prevCheckpointBlock.Header(), blockNumber, s.b.ChainConfig().Posv.Epoch)
signedBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(signedBlockNumber))
if s.b.ChainConfig().IsTIPSigning(latestBlockNumber) {
signers, err = GetSignersFromBlocks(s.b, signedBlock.NumberU64(), signedBlock.Hash(), masternodes)
} else {
signers, err = contracts.GetSignersByExecutingEVM(common.HexToAddress(common.BlockSigners), client, signedBlock.Hash())
} }
addrBlockSigner := common.HexToAddress(common.BlockSigners)
signers, err = contracts.GetSignersByExecutingEVM(addrBlockSigner, client, prevBlock.Hash())
if err != nil { if err != nil {
log.Error("Fail to get signers from block signer SC.", "error", err) log.Error("Fail to get signers from block signer SC.", "error", err)
return []common.Address{}, err return nil, err
} }
validator, _ := engine.RecoverValidator(b.Header()) validator, _ := engine.RecoverValidator(b.Header())
creator, _ := engine.RecoverSigner(b.Header()) creator, _ := engine.RecoverSigner(b.Header())
signers = append(signers, validator) signers = append(signers, validator)
signers = append(signers, creator) signers = append(signers, creator)
countFinality := 0
for _, masternode := range masternodes { for _, masternode := range masternodes {
for _, signer := range signers { for _, signer := range signers {
if signer == masternode { if signer == masternode {
countFinality++
filterSigners = append(filterSigners, masternode) filterSigners = append(filterSigners, masternode)
break break
} }
} }
} }
}
} else { } else {
log.Error("Undefined POSV consensus engine") log.Error("Undefined POSV consensus engine")
} }
@ -1712,3 +1719,52 @@ func (s *PublicNetAPI) PeerCount() hexutil.Uint {
func (s *PublicNetAPI) Version() string { func (s *PublicNetAPI) Version() string {
return fmt.Sprintf("%d", s.networkVersion) return fmt.Sprintf("%d", s.networkVersion)
} }
func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash, masternodes []common.Address) ([]common.Address, error) {
var addrs []common.Address
mapMN := map[common.Address]bool{}
for _, node := range masternodes {
mapMN[node] = true
}
if engine, ok := b.GetEngine().(*posv.Posv); ok {
limitNumber := blockNumber - blockNumber%b.ChainConfig().Posv.Epoch + 2*b.ChainConfig().Posv.Epoch - 1
currentNumber := b.CurrentBlock().NumberU64()
if limitNumber > currentNumber {
limitNumber = currentNumber
}
for i := blockNumber + 1; i <= limitNumber; i++ {
header, err := b.HeaderByNumber(nil, rpc.BlockNumber(i))
if err != nil {
return addrs, err
}
signData, ok := engine.BlockSigners.Get(header.Hash())
var signTxs []*types.Transaction = nil
if !ok {
blockData, err := b.BlockByNumber(nil, rpc.BlockNumber(i))
if err != nil {
return addrs, err
}
signTxs = []*types.Transaction{}
for _, tx := range blockData.Transactions() {
if tx.IsSigningTransaction() {
signTxs = append(signTxs, tx)
}
}
} else {
signTxs = signData.([]*types.Transaction)
}
for _, signtx := range signTxs {
blkHash := common.BytesToHash(signtx.Data()[len(signtx.Data())-32:])
from := *signtx.From()
if blkHash == blockHash && mapMN[from] {
addrs = append(addrs, from)
delete(mapMN, from)
}
}
if len(mapMN) == 0 {
break
}
}
}
return addrs, nil
}

View file

@ -18,6 +18,7 @@ package miner
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
@ -583,6 +584,9 @@ func (self *worker) commitNewWork() {
if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 { if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 {
misc.ApplyDAOHardFork(work.state) misc.ApplyDAOHardFork(work.state)
} }
if common.TIPSigning.Cmp(header.Number) == 0 {
work.state.DeleteAddress(common.HexToAddress(common.BlockSigners))
}
// won't grasp txs at checkpoint // won't grasp txs at checkpoint
var ( var (
txs *types.TransactionsByPriceAndNonce txs *types.TransactionsByPriceAndNonce
@ -671,6 +675,17 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
log.Trace("Ignoring reply protected special transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block) log.Trace("Ignoring reply protected special transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block)
continue continue
} }
if tx.To().Hex() == common.BlockSigners {
if len(tx.Data()) < 68 {
log.Trace("Data special transaction invalid length", "hash", tx.Hash(), "data", len(tx.Data()))
continue
}
blkNumber := binary.BigEndian.Uint64(tx.Data()[8:40])
if blkNumber >= env.header.Number.Uint64() || blkNumber <= env.header.Number.Uint64()-env.config.Posv.Epoch*2 {
log.Trace("Data special transaction invalid number", "hash", tx.Hash(), "blkNumber", blkNumber, "miner", env.header.Number)
continue
}
}
// Start executing the transaction // Start executing the transaction
env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount)
nonce := env.state.GetNonce(from) nonce := env.state.GetNonce(from)

View file

@ -217,6 +217,10 @@ func (c *ChainConfig) IsTIP2019(num *big.Int) bool {
return isForked(common.TIP2019Block, num) return isForked(common.TIP2019Block, num)
} }
func (c *ChainConfig) IsTIPSigning(num *big.Int) bool {
return isForked(common.TIPSigning, num)
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
// //
// The returned GasTable's fields shouldn't, under any circumstances, be changed. // The returned GasTable's fields shouldn't, under any circumstances, be changed.

View file

@ -53,9 +53,9 @@ func returnHasherToPool(h *hasher) {
// hash collapses a node down into a hash node, also returning a copy of the // hash collapses a node down into a hash node, also returning a copy of the
// original node initialized with the computed hash to replace the original one. // original node initialized with the computed hash to replace the original one.
func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) { func (h *hasher) hash(n Node, db *Database, force bool) (Node, Node, error) {
// If we're not storing the node, just hashing, use available cached data // If we're not storing the node, just hashing, use available cached data
if hash, dirty := n.cache(); hash != nil { if hash, dirty := n.Cache(); hash != nil {
if db == nil { if db == nil {
return hash, n, nil return hash, n, nil
} }
@ -72,23 +72,23 @@ func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) {
// Trie not processed yet or needs storage, walk the children // Trie not processed yet or needs storage, walk the children
collapsed, cached, err := h.hashChildren(n, db) collapsed, cached, err := h.hashChildren(n, db)
if err != nil { if err != nil {
return hashNode{}, n, err return HashNode{}, n, err
} }
hashed, err := h.store(collapsed, db, force) hashed, err := h.store(collapsed, db, force)
if err != nil { if err != nil {
return hashNode{}, n, err return HashNode{}, n, err
} }
// Cache the hash of the node for later reuse and remove // Cache the hash of the node for later reuse and remove
// the dirty flag in commit mode. It's fine to assign these values directly // the dirty flag in commit mode. It's fine to assign these values directly
// without copying the node first because hashChildren copies it. // without copying the node first because hashChildren copies it.
cachedHash, _ := hashed.(hashNode) cachedHash, _ := hashed.(HashNode)
switch cn := cached.(type) { switch cn := cached.(type) {
case *shortNode: case *ShortNode:
cn.flags.hash = cachedHash cn.flags.hash = cachedHash
if db != nil { if db != nil {
cn.flags.dirty = false cn.flags.dirty = false
} }
case *fullNode: case *FullNode:
cn.flags.hash = cachedHash cn.flags.hash = cachedHash
if db != nil { if db != nil {
cn.flags.dirty = false cn.flags.dirty = false
@ -100,28 +100,28 @@ func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) {
// hashChildren replaces the children of a node with their hashes if the encoded // hashChildren replaces the children of a node with their hashes if the encoded
// size of the child is larger than a hash, returning the collapsed node as well // size of the child is larger than a hash, returning the collapsed node as well
// as a replacement for the original node with the child hashes cached in. // as a replacement for the original node with the child hashes cached in.
func (h *hasher) hashChildren(original node, db *Database) (node, node, error) { func (h *hasher) hashChildren(original Node, db *Database) (Node, Node, error) {
var err error var err error
switch n := original.(type) { switch n := original.(type) {
case *shortNode: case *ShortNode:
// Hash the short node's child, caching the newly hashed subtree // Hash the short Node's child, caching the newly hashed subtree
collapsed, cached := n.copy(), n.copy() collapsed, cached := n.copy(), n.copy()
collapsed.Key = hexToCompact(n.Key) collapsed.Key = hexToCompact(n.Key)
cached.Key = common.CopyBytes(n.Key) cached.Key = common.CopyBytes(n.Key)
if _, ok := n.Val.(valueNode); !ok { if _, ok := n.Val.(ValueNode); !ok {
collapsed.Val, cached.Val, err = h.hash(n.Val, db, false) collapsed.Val, cached.Val, err = h.hash(n.Val, db, false)
if err != nil { if err != nil {
return original, original, err return original, original, err
} }
} }
if collapsed.Val == nil { if collapsed.Val == nil {
collapsed.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings. collapsed.Val = ValueNode(nil) // Ensure that nil children are encoded as empty strings.
} }
return collapsed, cached, nil return collapsed, cached, nil
case *fullNode: case *FullNode:
// Hash the full node's children, caching the newly hashed subtrees // Hash the full node's children, caching the newly hashed subtrees
collapsed, cached := n.copy(), n.copy() collapsed, cached := n.copy(), n.copy()
@ -132,12 +132,12 @@ func (h *hasher) hashChildren(original node, db *Database) (node, node, error) {
return original, original, err return original, original, err
} }
} else { } else {
collapsed.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings. collapsed.Children[i] = ValueNode(nil) // Ensure that nil children are encoded as empty strings.
} }
} }
cached.Children[16] = n.Children[16] cached.Children[16] = n.Children[16]
if collapsed.Children[16] == nil { if collapsed.Children[16] == nil {
collapsed.Children[16] = valueNode(nil) collapsed.Children[16] = ValueNode(nil)
} }
return collapsed, cached, nil return collapsed, cached, nil
@ -150,9 +150,9 @@ func (h *hasher) hashChildren(original node, db *Database) (node, node, error) {
// store hashes the node n and if we have a storage layer specified, it writes // store hashes the node n and if we have a storage layer specified, it writes
// the key/value pair to it and tracks any node->child references as well as any // the key/value pair to it and tracks any node->child references as well as any
// node->external trie references. // node->external trie references.
func (h *hasher) store(n node, db *Database, force bool) (node, error) { func (h *hasher) store(n Node, db *Database, force bool) (Node, error) {
// Don't store hashes or empty nodes. // Don't store hashes or empty nodes.
if _, isHash := n.(hashNode); n == nil || isHash { if _, isHash := n.(HashNode); n == nil || isHash {
return n, nil return n, nil
} }
// Generate the RLP encoding of the node // Generate the RLP encoding of the node
@ -164,11 +164,11 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
return n, nil // Nodes smaller than 32 bytes are stored inside their parent return n, nil // Nodes smaller than 32 bytes are stored inside their parent
} }
// Larger nodes are replaced by their hash and stored in the database. // Larger nodes are replaced by their hash and stored in the database.
hash, _ := n.cache() hash, _ := n.Cache()
if hash == nil { if hash == nil {
h.sha.Reset() h.sha.Reset()
h.sha.Write(h.tmp.Bytes()) h.sha.Write(h.tmp.Bytes())
hash = hashNode(h.sha.Sum(nil)) hash = HashNode(h.sha.Sum(nil))
} }
if db != nil { if db != nil {
// We are pooling the trie nodes into an intermediate memory cache // We are pooling the trie nodes into an intermediate memory cache
@ -179,13 +179,13 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
// Track all direct parent->child node references // Track all direct parent->child node references
switch n := n.(type) { switch n := n.(type) {
case *shortNode: case *ShortNode:
if child, ok := n.Val.(hashNode); ok { if child, ok := n.Val.(HashNode); ok {
db.reference(common.BytesToHash(child), hash) db.reference(common.BytesToHash(child), hash)
} }
case *fullNode: case *FullNode:
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
if child, ok := n.Children[i].(hashNode); ok { if child, ok := n.Children[i].(HashNode); ok {
db.reference(common.BytesToHash(child), hash) db.reference(common.BytesToHash(child), hash)
} }
} }
@ -195,13 +195,13 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
// Track external references from account->storage trie // Track external references from account->storage trie
if h.onleaf != nil { if h.onleaf != nil {
switch n := n.(type) { switch n := n.(type) {
case *shortNode: case *ShortNode:
if child, ok := n.Val.(valueNode); ok { if child, ok := n.Val.(ValueNode); ok {
h.onleaf(child, hash) h.onleaf(child, hash)
} }
case *fullNode: case *FullNode:
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
if child, ok := n.Children[i].(valueNode); ok { if child, ok := n.Children[i].(ValueNode); ok {
h.onleaf(child, hash) h.onleaf(child, hash)
} }
} }

View file

@ -20,7 +20,6 @@ import (
"bytes" "bytes"
"container/heap" "container/heap"
"errors" "errors"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
@ -60,6 +59,7 @@ type NodeIterator interface {
// Next moves the iterator to the next node. If the parameter is false, any child // Next moves the iterator to the next node. If the parameter is false, any child
// nodes will be skipped. // nodes will be skipped.
Next(bool) bool Next(bool) bool
// Error returns the error status of the iterator. // Error returns the error status of the iterator.
Error() error Error() error
@ -86,7 +86,7 @@ type NodeIterator interface {
// trie, which can be resumed at a later invocation. // trie, which can be resumed at a later invocation.
type nodeIteratorState struct { type nodeIteratorState struct {
hash common.Hash // Hash of the node being iterated (nil if not standalone) hash common.Hash // Hash of the node being iterated (nil if not standalone)
node node // Trie node being iterated node Node // Trie node being iterated
parent common.Hash // Hash of the first full ancestor node (nil if current is the root) parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
index int // Child to be processed next index int // Child to be processed next
pathlen int // Length of the path to this node pathlen int // Length of the path to this node
@ -112,7 +112,7 @@ func (e seekError) Error() string {
return "seek error: " + e.err.Error() return "seek error: " + e.err.Error()
} }
func newNodeIterator(trie *Trie, start []byte) NodeIterator { func NewNodeIterator(trie *Trie, start []byte) NodeIterator {
if trie.Hash() == emptyState { if trie.Hash() == emptyState {
return new(nodeIterator) return new(nodeIterator)
} }
@ -141,7 +141,7 @@ func (it *nodeIterator) Leaf() bool {
func (it *nodeIterator) LeafBlob() []byte { func (it *nodeIterator) LeafBlob() []byte {
if len(it.stack) > 0 { if len(it.stack) > 0 {
if node, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { if node, ok := it.stack[len(it.stack)-1].node.(ValueNode); ok {
return []byte(node) return []byte(node)
} }
} }
@ -150,7 +150,7 @@ func (it *nodeIterator) LeafBlob() []byte {
func (it *nodeIterator) LeafKey() []byte { func (it *nodeIterator) LeafKey() []byte {
if len(it.stack) > 0 { if len(it.stack) > 0 {
if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { if _, ok := it.stack[len(it.stack)-1].node.(ValueNode); ok {
return hexToKeybytes(it.path) return hexToKeybytes(it.path)
} }
} }
@ -250,7 +250,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
} }
func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error { func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error {
if hash, ok := st.node.(hashNode); ok { if hash, ok := st.node.(HashNode); ok {
resolved, err := tr.resolveHash(hash, path) resolved, err := tr.resolveHash(hash, path)
if err != nil { if err != nil {
return err return err
@ -263,12 +263,12 @@ func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error {
func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Hash) (*nodeIteratorState, []byte, bool) { func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Hash) (*nodeIteratorState, []byte, bool) {
switch node := parent.node.(type) { switch node := parent.node.(type) {
case *fullNode: case *FullNode:
// Full node, move to the first non-nil child. // Full Node, move to the first non-nil child.
for i := parent.index + 1; i < len(node.Children); i++ { for i := parent.index + 1; i < len(node.Children); i++ {
child := node.Children[i] child := node.Children[i]
if child != nil { if child != nil {
hash, _ := child.cache() hash, _ := child.Cache()
state := &nodeIteratorState{ state := &nodeIteratorState{
hash: common.BytesToHash(hash), hash: common.BytesToHash(hash),
node: child, node: child,
@ -281,10 +281,10 @@ func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Has
return state, path, true return state, path, true
} }
} }
case *shortNode: case *ShortNode:
// Short node, return the pointer singleton child // Short node, return the pointer singleton child
if parent.index < 0 { if parent.index < 0 {
hash, _ := node.Val.cache() hash, _ := node.Val.Cache()
state := &nodeIteratorState{ state := &nodeIteratorState{
hash: common.BytesToHash(hash), hash: common.BytesToHash(hash),
node: node.Val, node: node.Val,

View file

@ -27,63 +27,63 @@ import (
var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "[17]"} var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "[17]"}
type node interface { type Node interface {
fstring(string) string fstring(string) string
cache() (hashNode, bool) Cache() (HashNode, bool)
canUnload(cachegen, cachelimit uint16) bool canUnload(cachegen, cachelimit uint16) bool
} }
type ( type (
fullNode struct { FullNode struct {
Children [17]node // Actual trie node data to encode/decode (needs custom encoder) Children [17]Node // Actual trie node data to encode/decode (needs custom encoder)
flags nodeFlag flags nodeFlag
} }
shortNode struct { ShortNode struct {
Key []byte Key []byte
Val node Val Node
flags nodeFlag flags nodeFlag
} }
hashNode []byte HashNode []byte
valueNode []byte ValueNode []byte
) )
// EncodeRLP encodes a full node into the consensus RLP format. // EncodeRLP encodes a full node into the consensus RLP format.
func (n *fullNode) EncodeRLP(w io.Writer) error { func (n *FullNode) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, n.Children) return rlp.Encode(w, n.Children)
} }
func (n *fullNode) copy() *fullNode { copy := *n; return &copy } func (n *FullNode) copy() *FullNode { copy := *n; return &copy }
func (n *shortNode) copy() *shortNode { copy := *n; return &copy } func (n *ShortNode) copy() *ShortNode { copy := *n; return &copy }
// nodeFlag contains caching-related metadata about a node. // nodeFlag contains caching-related metadata about a node.
type nodeFlag struct { type nodeFlag struct {
hash hashNode // cached hash of the node (may be nil) hash HashNode // cached hash of the node (may be nil)
gen uint16 // cache generation counter gen uint16 // cache generation counter
dirty bool // whether the node has changes that must be written to the database dirty bool // whether the node has changes that must be written to the database
} }
// canUnload tells whether a node can be unloaded. // canUnload tells whether a Node can be unloaded.
func (n *nodeFlag) canUnload(cachegen, cachelimit uint16) bool { func (n *nodeFlag) canUnload(cachegen, cachelimit uint16) bool {
return !n.dirty && cachegen-n.gen >= cachelimit return !n.dirty && cachegen-n.gen >= cachelimit
} }
func (n *fullNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } func (n *FullNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) }
func (n *shortNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } func (n *ShortNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) }
func (n hashNode) canUnload(uint16, uint16) bool { return false } func (n HashNode) canUnload(uint16, uint16) bool { return false }
func (n valueNode) canUnload(uint16, uint16) bool { return false } func (n ValueNode) canUnload(uint16, uint16) bool { return false }
func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } func (n *FullNode) Cache() (HashNode, bool) { return n.flags.hash, n.flags.dirty }
func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } func (n *ShortNode) Cache() (HashNode, bool) { return n.flags.hash, n.flags.dirty }
func (n hashNode) cache() (hashNode, bool) { return nil, true } func (n HashNode) Cache() (HashNode, bool) { return nil, true }
func (n valueNode) cache() (hashNode, bool) { return nil, true } func (n ValueNode) Cache() (HashNode, bool) { return nil, true }
// Pretty printing. // Pretty printing.
func (n *fullNode) String() string { return n.fstring("") } func (n *FullNode) String() string { return n.fstring("") }
func (n *shortNode) String() string { return n.fstring("") } func (n *ShortNode) String() string { return n.fstring("") }
func (n hashNode) String() string { return n.fstring("") } func (n HashNode) String() string { return n.fstring("") }
func (n valueNode) String() string { return n.fstring("") } func (n ValueNode) String() string { return n.fstring("") }
func (n *fullNode) fstring(ind string) string { func (n *FullNode) fstring(ind string) string {
resp := fmt.Sprintf("[\n%s ", ind) resp := fmt.Sprintf("[\n%s ", ind)
for i, node := range n.Children { for i, node := range n.Children {
if node == nil { if node == nil {
@ -94,17 +94,17 @@ func (n *fullNode) fstring(ind string) string {
} }
return resp + fmt.Sprintf("\n%s] ", ind) return resp + fmt.Sprintf("\n%s] ", ind)
} }
func (n *shortNode) fstring(ind string) string { func (n *ShortNode) fstring(ind string) string {
return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" ")) return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" "))
} }
func (n hashNode) fstring(ind string) string { func (n HashNode) fstring(ind string) string {
return fmt.Sprintf("<%x> ", []byte(n)) return fmt.Sprintf("<%x> ", []byte(n))
} }
func (n valueNode) fstring(ind string) string { func (n ValueNode) fstring(ind string) string {
return fmt.Sprintf("%x ", []byte(n)) return fmt.Sprintf("%x ", []byte(n))
} }
func mustDecodeNode(hash, buf []byte, cachegen uint16) node { func MustDecodeNode(hash, buf []byte, cachegen uint16) Node {
n, err := decodeNode(hash, buf, cachegen) n, err := decodeNode(hash, buf, cachegen)
if err != nil { if err != nil {
panic(fmt.Sprintf("node %x: %v", hash, err)) panic(fmt.Sprintf("node %x: %v", hash, err))
@ -113,7 +113,7 @@ func mustDecodeNode(hash, buf []byte, cachegen uint16) node {
} }
// decodeNode parses the RLP encoding of a trie node. // decodeNode parses the RLP encoding of a trie node.
func decodeNode(hash, buf []byte, cachegen uint16) (node, error) { func decodeNode(hash, buf []byte, cachegen uint16) (Node, error) {
if len(buf) == 0 { if len(buf) == 0 {
return nil, io.ErrUnexpectedEOF return nil, io.ErrUnexpectedEOF
} }
@ -133,7 +133,7 @@ func decodeNode(hash, buf []byte, cachegen uint16) (node, error) {
} }
} }
func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) { func decodeShort(hash, buf, elems []byte, cachegen uint16) (Node, error) {
kbuf, rest, err := rlp.SplitString(elems) kbuf, rest, err := rlp.SplitString(elems)
if err != nil { if err != nil {
return nil, err return nil, err
@ -146,17 +146,17 @@ func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid value node: %v", err) return nil, fmt.Errorf("invalid value node: %v", err)
} }
return &shortNode{key, append(valueNode{}, val...), flag}, nil return &ShortNode{key, append(ValueNode{}, val...), flag}, nil
} }
r, _, err := decodeRef(rest, cachegen) r, _, err := decodeRef(rest, cachegen)
if err != nil { if err != nil {
return nil, wrapError(err, "val") return nil, wrapError(err, "val")
} }
return &shortNode{key, r, flag}, nil return &ShortNode{key, r, flag}, nil
} }
func decodeFull(hash, buf, elems []byte, cachegen uint16) (*fullNode, error) { func decodeFull(hash, buf, elems []byte, cachegen uint16) (*FullNode, error) {
n := &fullNode{flags: nodeFlag{hash: hash, gen: cachegen}} n := &FullNode{flags: nodeFlag{hash: hash, gen: cachegen}}
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
cld, rest, err := decodeRef(elems, cachegen) cld, rest, err := decodeRef(elems, cachegen)
if err != nil { if err != nil {
@ -169,14 +169,14 @@ func decodeFull(hash, buf, elems []byte, cachegen uint16) (*fullNode, error) {
return n, err return n, err
} }
if len(val) > 0 { if len(val) > 0 {
n.Children[16] = append(valueNode{}, val...) n.Children[16] = append(ValueNode{}, val...)
} }
return n, nil return n, nil
} }
const hashLen = len(common.Hash{}) const hashLen = len(common.Hash{})
func decodeRef(buf []byte, cachegen uint16) (node, []byte, error) { func decodeRef(buf []byte, cachegen uint16) (Node, []byte, error) {
kind, val, rest, err := rlp.Split(buf) kind, val, rest, err := rlp.Split(buf)
if err != nil { if err != nil {
return nil, buf, err return nil, buf, err
@ -195,7 +195,7 @@ func decodeRef(buf []byte, cachegen uint16) (node, []byte, error) {
// empty node // empty node
return nil, rest, nil return nil, rest, nil
case kind == rlp.String && len(val) == 32: case kind == rlp.String && len(val) == 32:
return append(hashNode{}, val...), rest, nil return append(HashNode{}, val...), rest, nil
default: default:
return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val)) return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val))
} }

View file

@ -37,11 +37,11 @@ import (
func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
// Collect all nodes on the path to key. // Collect all nodes on the path to key.
key = keybytesToHex(key) key = keybytesToHex(key)
nodes := []node{} nodes := []Node{}
tn := t.root tn := t.root
for len(key) > 0 && tn != nil { for len(key) > 0 && tn != nil {
switch n := tn.(type) { switch n := tn.(type) {
case *shortNode: case *ShortNode:
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
// The trie doesn't contain the key. // The trie doesn't contain the key.
tn = nil tn = nil
@ -50,11 +50,11 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
key = key[len(n.Key):] key = key[len(n.Key):]
} }
nodes = append(nodes, n) nodes = append(nodes, n)
case *fullNode: case *FullNode:
tn = n.Children[key[0]] tn = n.Children[key[0]]
key = key[1:] key = key[1:]
nodes = append(nodes, n) nodes = append(nodes, n)
case hashNode: case HashNode:
var err error var err error
tn, err = t.resolveHash(n, nil) tn, err = t.resolveHash(n, nil)
if err != nil { if err != nil {
@ -71,7 +71,7 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
// if encoding doesn't work and we're not writing to any database. // if encoding doesn't work and we're not writing to any database.
n, _, _ = hasher.hashChildren(n, nil) n, _, _ = hasher.hashChildren(n, nil)
hn, _ := hasher.store(n, nil, false) hn, _ := hasher.store(n, nil, false)
if hash, ok := hn.(hashNode); ok || i == 0 { if hash, ok := hn.(HashNode); ok || i == 0 {
// If the node's database encoding is a hash (or is the // If the node's database encoding is a hash (or is the
// root node), it becomes a proof element. // root node), it becomes a proof element.
if fromLevel > 0 { if fromLevel > 0 {
@ -119,32 +119,32 @@ func VerifyProof(rootHash common.Hash, key []byte, proofDb DatabaseReader) (valu
case nil: case nil:
// The trie doesn't contain the key. // The trie doesn't contain the key.
return nil, nil, i return nil, nil, i
case hashNode: case HashNode:
key = keyrest key = keyrest
copy(wantHash[:], cld) copy(wantHash[:], cld)
case valueNode: case ValueNode:
return cld, nil, i + 1 return cld, nil, i + 1
} }
} }
} }
func get(tn node, key []byte) ([]byte, node) { func get(tn Node, key []byte) ([]byte, Node) {
for { for {
switch n := tn.(type) { switch n := tn.(type) {
case *shortNode: case *ShortNode:
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
return nil, nil return nil, nil
} }
tn = n.Val tn = n.Val
key = key[len(n.Key):] key = key[len(n.Key):]
case *fullNode: case *FullNode:
tn = n.Children[key[0]] tn = n.Children[key[0]]
key = key[1:] key = key[1:]
case hashNode: case HashNode:
return key, n return key, n
case nil: case nil:
return key, nil return key, nil
case valueNode: case ValueNode:
return nil, n return nil, n
default: default:
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))

View file

@ -248,21 +248,21 @@ func (s *TrieSync) schedule(req *request) {
// children retrieves all the missing children of a state trie entry for future // children retrieves all the missing children of a state trie entry for future
// retrieval scheduling. // retrieval scheduling.
func (s *TrieSync) children(req *request, object node) ([]*request, error) { func (s *TrieSync) children(req *request, object Node) ([]*request, error) {
// Gather all the children of the node, irrelevant whether known or not // Gather all the children of the node, irrelevant whether known or not
type child struct { type child struct {
node node node Node
depth int depth int
} }
children := []child{} children := []child{}
switch node := (object).(type) { switch node := (object).(type) {
case *shortNode: case *ShortNode:
children = []child{{ children = []child{{
node: node.Val, node: node.Val,
depth: req.depth + len(node.Key), depth: req.depth + len(node.Key),
}} }}
case *fullNode: case *FullNode:
for i := 0; i < 17; i++ { for i := 0; i < 17; i++ {
if node.Children[i] != nil { if node.Children[i] != nil {
children = append(children, child{ children = append(children, child{
@ -279,14 +279,14 @@ func (s *TrieSync) children(req *request, object node) ([]*request, error) {
for _, child := range children { for _, child := range children {
// Notify any external watcher of a new key/value node // Notify any external watcher of a new key/value node
if req.callback != nil { if req.callback != nil {
if node, ok := (child.node).(valueNode); ok { if node, ok := (child.node).(ValueNode); ok {
if err := req.callback(node, req.hash); err != nil { if err := req.callback(node, req.hash); err != nil {
return nil, err return nil, err
} }
} }
} }
// If the child references another node, resolve or schedule // If the child references another node, resolve or schedule
if node, ok := (child.node).(hashNode); ok { if node, ok := (child.node).(HashNode); ok {
// Try to resolve the node from the local database // Try to resolve the node from the local database
hash := common.BytesToHash(node) hash := common.BytesToHash(node)
if _, ok := s.membatch.batch[hash]; ok { if _, ok := s.membatch.batch[hash]; ok {

View file

@ -66,7 +66,7 @@ type LeafCallback func(leaf []byte, parent common.Hash) error
// Trie is not safe for concurrent use. // Trie is not safe for concurrent use.
type Trie struct { type Trie struct {
db *Database db *Database
root node root Node
originalRoot common.Hash originalRoot common.Hash
// Cache generation values. // Cache generation values.
@ -114,7 +114,7 @@ func New(root common.Hash, db *Database) (*Trie, error) {
// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at // NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at
// the key after the given start key. // the key after the given start key.
func (t *Trie) NodeIterator(start []byte) NodeIterator { func (t *Trie) NodeIterator(start []byte) NodeIterator {
return newNodeIterator(t, start) return NewNodeIterator(t, start)
} }
// Get returns the value for key stored in the trie. // Get returns the value for key stored in the trie.
@ -139,13 +139,13 @@ func (t *Trie) TryGet(key []byte) ([]byte, error) {
return value, err return value, err
} }
func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) { func (t *Trie) tryGet(origNode Node, key []byte, pos int) (value []byte, newnode Node, didResolve bool, err error) {
switch n := (origNode).(type) { switch n := (origNode).(type) {
case nil: case nil:
return nil, nil, false, nil return nil, nil, false, nil
case valueNode: case ValueNode:
return n, n, false, nil return n, n, false, nil
case *shortNode: case *ShortNode:
if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) { if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) {
// key not found in trie // key not found in trie
return nil, n, false, nil return nil, n, false, nil
@ -157,7 +157,7 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode
n.flags.gen = t.cachegen n.flags.gen = t.cachegen
} }
return value, n, didResolve, err return value, n, didResolve, err
case *fullNode: case *FullNode:
value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1) value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1)
if err == nil && didResolve { if err == nil && didResolve {
n = n.copy() n = n.copy()
@ -165,7 +165,7 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode
n.Children[key[pos]] = newnode n.Children[key[pos]] = newnode
} }
return value, n, didResolve, err return value, n, didResolve, err
case hashNode: case HashNode:
child, err := t.resolveHash(n, key[:pos]) child, err := t.resolveHash(n, key[:pos])
if err != nil { if err != nil {
return nil, n, true, err return nil, n, true, err
@ -200,7 +200,7 @@ func (t *Trie) Update(key, value []byte) {
func (t *Trie) TryUpdate(key, value []byte) error { func (t *Trie) TryUpdate(key, value []byte) error {
k := keybytesToHex(key) k := keybytesToHex(key)
if len(value) != 0 { if len(value) != 0 {
_, n, err := t.insert(t.root, nil, k, valueNode(value)) _, n, err := t.insert(t.root, nil, k, ValueNode(value))
if err != nil { if err != nil {
return err return err
} }
@ -215,15 +215,15 @@ func (t *Trie) TryUpdate(key, value []byte) error {
return nil return nil
} }
func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error) { func (t *Trie) insert(n Node, prefix, key []byte, value Node) (bool, Node, error) {
if len(key) == 0 { if len(key) == 0 {
if v, ok := n.(valueNode); ok { if v, ok := n.(ValueNode); ok {
return !bytes.Equal(v, value.(valueNode)), value, nil return !bytes.Equal(v, value.(ValueNode)), value, nil
} }
return true, value, nil return true, value, nil
} }
switch n := n.(type) { switch n := n.(type) {
case *shortNode: case *ShortNode:
matchlen := prefixLen(key, n.Key) matchlen := prefixLen(key, n.Key)
// If the whole key matches, keep this short node as is // If the whole key matches, keep this short node as is
// and only update the value. // and only update the value.
@ -232,10 +232,10 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
if !dirty || err != nil { if !dirty || err != nil {
return false, n, err return false, n, err
} }
return true, &shortNode{n.Key, nn, t.newFlag()}, nil return true, &ShortNode{n.Key, nn, t.newFlag()}, nil
} }
// Otherwise branch out at the index where they differ. // Otherwise branch out at the index where they differ.
branch := &fullNode{flags: t.newFlag()} branch := &FullNode{flags: t.newFlag()}
var err error var err error
_, branch.Children[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val) _, branch.Children[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val)
if err != nil { if err != nil {
@ -250,9 +250,9 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
return true, branch, nil return true, branch, nil
} }
// Otherwise, replace it with a short node leading up to the branch. // Otherwise, replace it with a short node leading up to the branch.
return true, &shortNode{key[:matchlen], branch, t.newFlag()}, nil return true, &ShortNode{key[:matchlen], branch, t.newFlag()}, nil
case *fullNode: case *FullNode:
dirty, nn, err := t.insert(n.Children[key[0]], append(prefix, key[0]), key[1:], value) dirty, nn, err := t.insert(n.Children[key[0]], append(prefix, key[0]), key[1:], value)
if !dirty || err != nil { if !dirty || err != nil {
return false, n, err return false, n, err
@ -263,9 +263,9 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
return true, n, nil return true, n, nil
case nil: case nil:
return true, &shortNode{key, value, t.newFlag()}, nil return true, &ShortNode{key, value, t.newFlag()}, nil
case hashNode: case HashNode:
// We've hit a part of the trie that isn't loaded yet. Load // We've hit a part of the trie that isn't loaded yet. Load
// the node and insert into it. This leaves all child nodes on // the node and insert into it. This leaves all child nodes on
// the path to the value in the trie. // the path to the value in the trie.
@ -306,9 +306,9 @@ func (t *Trie) TryDelete(key []byte) error {
// delete returns the new root of the trie with key deleted. // delete returns the new root of the trie with key deleted.
// It reduces the trie to minimal form by simplifying // It reduces the trie to minimal form by simplifying
// nodes on the way up after deleting recursively. // nodes on the way up after deleting recursively.
func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { func (t *Trie) delete(n Node, prefix, key []byte) (bool, Node, error) {
switch n := n.(type) { switch n := n.(type) {
case *shortNode: case *ShortNode:
matchlen := prefixLen(key, n.Key) matchlen := prefixLen(key, n.Key)
if matchlen < len(n.Key) { if matchlen < len(n.Key) {
return false, n, nil // don't replace n on mismatch return false, n, nil // don't replace n on mismatch
@ -325,19 +325,19 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
return false, n, err return false, n, err
} }
switch child := child.(type) { switch child := child.(type) {
case *shortNode: case *ShortNode:
// Deleting from the subtrie reduced it to another // Deleting from the subtrie reduced it to another
// short node. Merge the nodes to avoid creating a // short node. Merge the nodes to avoid creating a
// shortNode{..., shortNode{...}}. Use concat (which // shortNode{..., shortNode{...}}. Use concat (which
// always creates a new slice) instead of append to // always creates a new slice) instead of append to
// avoid modifying n.Key since it might be shared with // avoid modifying n.Key since it might be shared with
// other nodes. // other nodes.
return true, &shortNode{concat(n.Key, child.Key...), child.Val, t.newFlag()}, nil return true, &ShortNode{concat(n.Key, child.Key...), child.Val, t.newFlag()}, nil
default: default:
return true, &shortNode{n.Key, child, t.newFlag()}, nil return true, &ShortNode{n.Key, child, t.newFlag()}, nil
} }
case *fullNode: case *FullNode:
dirty, nn, err := t.delete(n.Children[key[0]], append(prefix, key[0]), key[1:]) dirty, nn, err := t.delete(n.Children[key[0]], append(prefix, key[0]), key[1:])
if !dirty || err != nil { if !dirty || err != nil {
return false, n, err return false, n, err
@ -378,25 +378,25 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
if cnode, ok := cnode.(*shortNode); ok { if cnode, ok := cnode.(*ShortNode); ok {
k := append([]byte{byte(pos)}, cnode.Key...) k := append([]byte{byte(pos)}, cnode.Key...)
return true, &shortNode{k, cnode.Val, t.newFlag()}, nil return true, &ShortNode{k, cnode.Val, t.newFlag()}, nil
} }
} }
// Otherwise, n is replaced by a one-nibble short node // Otherwise, n is replaced by a one-nibble short node
// containing the child. // containing the child.
return true, &shortNode{[]byte{byte(pos)}, n.Children[pos], t.newFlag()}, nil return true, &ShortNode{[]byte{byte(pos)}, n.Children[pos], t.newFlag()}, nil
} }
// n still contains at least two values and cannot be reduced. // n still contains at least two values and cannot be reduced.
return true, n, nil return true, n, nil
case valueNode: case ValueNode:
return true, nil, nil return true, nil, nil
case nil: case nil:
return false, nil, nil return false, nil, nil
case hashNode: case HashNode:
// We've hit a part of the trie that isn't loaded yet. Load // We've hit a part of the trie that isn't loaded yet. Load
// the node and delete from it. This leaves all child nodes on // the node and delete from it. This leaves all child nodes on
// the path to the value in the trie. // the path to the value in the trie.
@ -422,14 +422,14 @@ func concat(s1 []byte, s2 ...byte) []byte {
return r return r
} }
func (t *Trie) resolve(n node, prefix []byte) (node, error) { func (t *Trie) resolve(n Node, prefix []byte) (Node, error) {
if n, ok := n.(hashNode); ok { if n, ok := n.(HashNode); ok {
return t.resolveHash(n, prefix) return t.resolveHash(n, prefix)
} }
return n, nil return n, nil
} }
func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { func (t *Trie) resolveHash(n HashNode, prefix []byte) (Node, error) {
cacheMissCounter.Inc(1) cacheMissCounter.Inc(1)
hash := common.BytesToHash(n) hash := common.BytesToHash(n)
@ -438,7 +438,7 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
if err != nil || enc == nil { if err != nil || enc == nil {
return nil, &MissingNodeError{NodeHash: hash, Path: prefix} return nil, &MissingNodeError{NodeHash: hash, Path: prefix}
} }
return mustDecodeNode(n, enc, t.cachegen), nil return MustDecodeNode(n, enc, t.cachegen), nil
} }
// Root returns the root hash of the trie. // Root returns the root hash of the trie.
@ -450,7 +450,7 @@ func (t *Trie) Root() []byte { return t.Hash().Bytes() }
func (t *Trie) Hash() common.Hash { func (t *Trie) Hash() common.Hash {
hash, cached, _ := t.hashRoot(nil, nil) hash, cached, _ := t.hashRoot(nil, nil)
t.root = cached t.root = cached
return common.BytesToHash(hash.(hashNode)) return common.BytesToHash(hash.(HashNode))
} }
// Commit writes all nodes to the trie's memory database, tracking the internal // Commit writes all nodes to the trie's memory database, tracking the internal
@ -465,12 +465,12 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
} }
t.root = cached t.root = cached
t.cachegen++ t.cachegen++
return common.BytesToHash(hash.(hashNode)), nil return common.BytesToHash(hash.(HashNode)), nil
} }
func (t *Trie) hashRoot(db *Database, onleaf LeafCallback) (node, node, error) { func (t *Trie) hashRoot(db *Database, onleaf LeafCallback) (Node, Node, error) {
if t.root == nil { if t.root == nil {
return hashNode(emptyRoot.Bytes()), nil, nil return HashNode(emptyRoot.Bytes()), nil, nil
} }
h := newHasher(t.cachegen, t.cachelimit, onleaf) h := newHasher(t.cachegen, t.cachelimit, onleaf)
defer returnHasherToPool(h) defer returnHasherToPool(h)

View file

@ -469,14 +469,14 @@ func runRandTest(rt randTest) bool {
return true return true
} }
func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error { func checkCacheInvariant(n, parent Node, parentCachegen uint16, parentDirty bool, depth int) error {
var children []node var children []Node
var flag nodeFlag var flag nodeFlag
switch n := n.(type) { switch n := n.(type) {
case *shortNode: case *ShortNode:
flag = n.flags flag = n.flags
children = []node{n.Val} children = []Node{n.Val}
case *fullNode: case *FullNode:
flag = n.flags flag = n.flags
children = n.Children[:] children = n.Children[:]
default: default: