Skip to content

Commit

Permalink
layer2 store and transfer (#1265)
Browse files Browse the repository at this point in the history
* add state tree

* add state tree

* add state tree

* update block header

* add state tree

* add state tree

* add state tree

* merge layer2 code

* merge layer2 code

* merge layer2 code

* fix state tree bug

* fix state tree bug

* for ontology

* for ontology

* for ontology

* for ontology

* update get proof interface

* block generate:

* update get proof interface

* get state proof safety

* get store proof safty

* merge code

* merge code

* add layer2 mode & add license

* update code after review

* go fmt

* go fmt

* go fmt

* go fmt

* fix bug

* fix test case

* fix test case

* move update state from execute block to submit block

Co-authored-by: tangaoyuan <[email protected]>
  • Loading branch information
blockchain-develop and tangaoyuan authored Jul 30, 2020
1 parent 415b6fc commit 666f7ee
Show file tree
Hide file tree
Showing 30 changed files with 1,099 additions and 39 deletions.
10 changes: 10 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ func setGenesis(ctx *cli.Context, cfg *config.OntologyConfig) error {
cfg.Genesis = config.PolarisConfig
}

if ctx.Bool(utils.GetFlagName(utils.EnableLayer2ModeFlag)) {
cfg.Genesis.ConsensusType = config.CONSENSUS_TYPE_SOLO
cfg.Genesis.SOLO.GenBlockTime = ctx.Uint(utils.GetFlagName(utils.Layer2ModeGenBlockTimeFlag))
if cfg.Genesis.SOLO.GenBlockTime <= 1 {
cfg.Genesis.SOLO.GenBlockTime = config.DEFAULT_GEN_BLOCK_TIME
}
return nil
}

if ctx.Bool(utils.GetFlagName(utils.EnableTestModeFlag)) {
cfg.Genesis.ConsensusType = config.CONSENSUS_TYPE_SOLO
cfg.Genesis.SOLO.GenBlockTime = ctx.Uint(utils.GetFlagName(utils.TestModeGenBlockTimeFlag))
Expand Down Expand Up @@ -135,6 +144,7 @@ func setCommonConfig(ctx *cli.Context, cfg *config.CommonConfig) {
cfg.EnableEventLog = !ctx.Bool(utils.GetFlagName(utils.DisableEventLogFlag))
cfg.GasLimit = ctx.Uint64(utils.GetFlagName(utils.GasLimitFlag))
cfg.GasPrice = ctx.Uint64(utils.GetFlagName(utils.GasPriceFlag))
cfg.MinOngLimit = ctx.Uint64(utils.GetFlagName(utils.MinOngLimitFlag))
cfg.DataDir = ctx.String(utils.GetFlagName(utils.DataDirFlag))
}

Expand Down
7 changes: 7 additions & 0 deletions cmd/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ var AppHelpFlagGroups = []flagGroup{
utils.WsPortFlag,
},
},
{
Name: "LAYER2 MODE",
Flags: []cli.Flag{
utils.EnableLayer2ModeFlag,
utils.Layer2ModeGenBlockTimeFlag,
},
},
{
Name: "TEST MODE",
Flags: []cli.Flag{
Expand Down
17 changes: 17 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@ var (
Value: config.DEFAULT_GAS_PRICE,
}

MinOngLimitFlag = cli.Uint64Flag{
Name: "minonglimit",
Usage: "Min withdraw and transfer Ong `<value>`.",
Value: config.DEFAULT_MIN_ONG_LIMIT,
}

EnableLayer2ModeFlag = cli.BoolFlag{
Name: "layer2mode",
Usage: "Single node for layer2. In layer2 mode, will start rpc, rest, web socket server, and set default gasprice to 0",
}

Layer2ModeGenBlockTimeFlag = cli.UintFlag{
Name: "layer2mode-gen-block-time",
Usage: "Block-out `<time>`(s) in layer2 mode.",
Value: config.DEFAULT_GEN_BLOCK_TIME,
}

//Test Mode setting
EnableTestModeFlag = cli.BoolFlag{
Name: "testmode",
Expand Down
2 changes: 2 additions & 0 deletions cmd/utils/ont.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ func NewInvokeTransaction(gasPrice, gasLimit uint64, invokeCode []byte) *types.M
GasPrice: gasPrice,
GasLimit: gasLimit,
TxType: types.InvokeNeo,
SystemId: constants.SYSTEM_ID,
Nonce: rand.Uint32(),
Payload: invokePayload,
Sigs: make([]types.Sig, 0, 0),
Expand Down Expand Up @@ -786,6 +787,7 @@ func NewDeployCodeTransaction(gasPrice, gasLimit uint64, code []byte, vmType pay
tx := &types.MutableTransaction{
Version: VERSION_TRANSACTION,
TxType: types.Deploy,
SystemId: constants.SYSTEM_ID,
Nonce: uint32(time.Now().Unix()),
Payload: deployPayload,
GasPrice: gasPrice,
Expand Down
2 changes: 2 additions & 0 deletions common/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const (
DEFAULT_CLI_RPC_PORT = uint(20000)
DEFUALT_CLI_RPC_ADDRESS = "127.0.0.1"
DEFAULT_GAS_LIMIT = 20000
DEFAULT_MIN_ONG_LIMIT = 100000000
DEFAULT_GAS_PRICE = 500
DEFAULT_WASM_GAS_FACTOR = uint64(10)
DEFAULT_WASM_MAX_STEPCOUNT = uint64(8000000)
Expand Down Expand Up @@ -591,6 +592,7 @@ type CommonConfig struct {
SystemFee map[string]int64
GasLimit uint64
GasPrice uint64
MinOngLimit uint64
DataDir string
WasmVerifyMethod VerifyMethod
}
Expand Down
2 changes: 2 additions & 0 deletions common/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,5 @@ const BLOCKHEIGHT_ONTFS_MAINNET = 8550000
const BLOCKHEIGHT_ONTFS_POLARIS = 12250000

const BLOCKHEIGHT_CC_POLARIS = 13130000

const SYSTEM_ID = 1
28 changes: 27 additions & 1 deletion consensus/solo/solo.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type SoloService struct {
genBlockInterval time.Duration
pid *actor.PID
sub *events.ActorSubscriber
counter int
genEmptyBlock int
}

func NewSoloService(bkAccount *account.Account, txpool *actor.PID) (*SoloService, error) {
Expand All @@ -59,6 +61,8 @@ func NewSoloService(bkAccount *account.Account, txpool *actor.PID) (*SoloService
poolActor: &actorTypes.TxPoolActor{Pool: txpool},
incrValidator: increment.NewIncrementValidator(20),
genBlockInterval: time.Duration(config.DefConfig.Genesis.SOLO.GenBlockTime) * time.Second,
counter: 0,
genEmptyBlock: 0,
}

props := actor.FromProducer(func() actor.Actor {
Expand Down Expand Up @@ -146,6 +150,9 @@ func (self *SoloService) genBlock() error {
if err != nil {
return fmt.Errorf("makeBlock error %s", err)
}
if block == nil {
return nil
}

result, err := ledger.DefLedger.ExecuteBlock(block)
if err != nil {
Expand Down Expand Up @@ -183,6 +190,11 @@ func (self *SoloService) makeBlock() (*types.Block, error) {
}
prevHash := ledger.DefLedger.GetCurrentBlockHash()
height := ledger.DefLedger.GetCurrentBlockHeight()
stateRoot, err := ledger.DefLedger.GetGlobalStateRoot(height)
if err != nil {
return nil, fmt.Errorf("GetGlobalStateRoot error:%s", err)
}
log.Debugf("global state root, height: %d, %v", height, stateRoot)

validHeight := height

Expand All @@ -198,7 +210,20 @@ func (self *SoloService) makeBlock() (*types.Block, error) {
log.Infof("current block height %v, increment validator block cache range: [%d, %d)", height, start, end)

txs := self.poolActor.GetTxnPool(true, validHeight)

//
if len(txs) == 0 && self.counter < 3600 && self.genEmptyBlock == 0 {
self.counter++
log.Infof("The number of tx is too small or timer is not out, counter: %d", self.counter)
return nil, nil
} else if len(txs) > 0 {
self.genEmptyBlock = 1
self.counter = 0
} else if self.genEmptyBlock > 0 {
self.genEmptyBlock--
self.counter = 0
} else {
self.counter = 0
}
transactions := make([]*types.Transaction, 0, len(txs))
for _, txEntry := range txs {
// TODO optimize to use height in txentry
Expand All @@ -219,6 +244,7 @@ func (self *SoloService) makeBlock() (*types.Block, error) {
PrevBlockHash: prevHash,
TransactionsRoot: txRoot,
BlockRoot: blockRoot,
StateRoot: stateRoot,
Timestamp: uint32(time.Now().Unix()),
Height: height + 1,
ConsensusData: common.GetNonce(),
Expand Down
8 changes: 8 additions & 0 deletions core/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ func (self *Ledger) GetStateMerkleRoot(height uint32) (result common.Uint256, er
return self.ldgStore.GetStateMerkleRoot(height)
}

func (self *Ledger) GetGlobalStateRoot(height uint32) (result common.Uint256, err error) {
return self.ldgStore.GetGlobalStateRoot(height)
}

func (self *Ledger) GetCrossStatesRoot(height uint32) (common.Uint256, error) {
return self.ldgStore.GetCrossStatesRoot(height)
}
Expand Down Expand Up @@ -200,6 +204,10 @@ func (self *Ledger) GetCrossStatesProof(height uint32, key []byte) ([]byte, erro
return self.ldgStore.GetCrossStatesProof(height, key)
}

func (self *Ledger) GetStoreProof(key []byte) ([]byte, []byte, uint32, error) {
return self.ldgStore.GetStoreProof(key)
}

func (self *Ledger) Close() error {
return self.ldgStore.Close()
}
Expand Down
1 change: 1 addition & 0 deletions core/store/common/data_entry_prefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (
SYS_BLOCK_MERKLE_TREE DataEntryPrefix = 0x13 // Block merkle tree root key prefix
SYS_STATE_MERKLE_TREE DataEntryPrefix = 0x20 // state merkle tree root key prefix
SYS_CROSS_CHAIN_MSG DataEntryPrefix = 0x22 // state merkle tree root key prefix
SYS_GLOBAL_STATE_TREE DataEntryPrefix = 0x24

EVENT_NOTIFY DataEntryPrefix = 0x14 //Event notify key prefix

Expand Down
70 changes: 69 additions & 1 deletion core/store/ledgerstore/ledger_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package ledgerstore
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"hash"
Expand Down Expand Up @@ -55,11 +56,15 @@ import (
sstate "github.com/ontio/ontology/smartcontract/states"
"github.com/ontio/ontology/smartcontract/storage"
types2 "github.com/ontio/ontology/vm/neovm/types"

"github.com/tendermint/iavl"
tmdb "github.com/tendermint/tm-db"
)

const (
SYSTEM_VERSION = byte(1) //Version of ledger store
HEADER_INDEX_BATCH_SIZE = uint32(2000) //Bath size of saving header index
defaultIAVLCacheSize = 10000
)

var (
Expand All @@ -68,6 +73,7 @@ var (
DBDirBlock = "block"
DBDirState = "states"
MerkleTreeStorePath = "merkle_tree.db"
StateTreeDb = "state_avl"
)

type PrexecuteParam struct {
Expand All @@ -90,6 +96,7 @@ type LedgerStoreImp struct {
vbftPeerInfoMap map[uint32]map[string]uint32 //key:block height,value:peerInfo
lock sync.RWMutex
stateHashCheckHeight uint32
stateTree *iavl.MutableTree

savingBlockSemaphore chan bool
closing bool
Expand Down Expand Up @@ -132,6 +139,16 @@ func NewLedgerStore(dataDir string, stateHashHeight uint32) (*LedgerStoreImp, er
}
ledgerStore.eventStore = eventState

stateDb, err := tmdb.NewGoLevelDB(StateTreeDb, dataDir)
if err != nil {
return nil, fmt.Errorf("NewGoLevelDB err %s", err)
}
stateTree, err := iavl.NewMutableTree(stateDb, defaultIAVLCacheSize)
if err != nil {
return nil, fmt.Errorf("NewMutableTree err %s", err)
}
ledgerStore.stateTree = stateTree

return ledgerStore, nil
}

Expand Down Expand Up @@ -309,6 +326,7 @@ func (this *LedgerStoreImp) recoverStore() error {
if err != nil {
return fmt.Errorf("stateStore.GetCurrentBlock error %s", err)
}
this.stateTree.LoadVersion(int64(stateHeight + 1))
for i := stateHeight; i < blockHeight; i++ {
blockHash, err := this.blockStore.GetBlockHash(i)
if err != nil {
Expand All @@ -324,6 +342,15 @@ func (this *LedgerStoreImp) recoverStore() error {
if err != nil {
return err
}
rootHash, version, err := this.stateTree.SaveVersion()
if err != nil {
return fmt.Errorf("stateTree.SaveVersion height:%d error %s", i, err)
}
log.Infof("state tree save version, root hash: %s, version: %d", hex.EncodeToString(rootHash), version)
result.StateRoot, err = common.Uint256ParseFromBytes(rootHash)
if err != nil {
return fmt.Errorf("common.Uint256ParseFromBytes height:%d error %s", i, err)
}
err = this.saveBlockToStateStore(block, result)
if err != nil {
return fmt.Errorf("save to state store height:%d error:%s", i, err)
Expand Down Expand Up @@ -583,6 +610,26 @@ func (this *LedgerStoreImp) GetStateMerkleRoot(height uint32) (common.Uint256, e
return this.stateStore.GetStateMerkleRoot(height)
}

func (this *LedgerStoreImp) GetGlobalStateRoot(height uint32) (common.Uint256, error) {
return this.stateStore.GetGlobalStateRoot(height)
}

func (this *LedgerStoreImp) GetStoreProof(key []byte) ([]byte, []byte, uint32, error) {
version := this.stateTree.Version() - 1
latestTree, err := this.stateTree.GetImmutable(version)
if err != nil {
return nil, nil, 0, err
}
value, proof, err := latestTree.GetWithProof(key)
if err != nil {
return nil, nil, 0, err
}
data := common.NewZeroCopySink(nil)
storeProof := types.StoreProof(*proof)
storeProof.Serialization(data)
return value, data.Bytes(), uint32(version), err
}

func (this *LedgerStoreImp) ExecuteBlock(block *types.Block) (result store.ExecuteResult, err error) {
this.getSavingBlockLock()
defer this.releaseSavingBlockLock()
Expand Down Expand Up @@ -768,7 +815,6 @@ func (this *LedgerStoreImp) executeBlock(block *types.Block) (result store.Execu
} else {
result.MerkleRoot = this.stateStore.GetStateMerkleRootWithNewHash(result.Hash)
}

return
}

Expand Down Expand Up @@ -820,6 +866,11 @@ func (this *LedgerStoreImp) saveBlockToStateStore(block *types.Block, result sto
return fmt.Errorf("AddBlockMerkleTreeRoot error %s", err)
}

err = this.stateStore.AddGlobalStateRoot(blockHeight, result.StateRoot)
if err != nil {
return fmt.Errorf("AddGlobalStateRoot error %s", err)
}

err = this.stateStore.SaveCurrentBlock(blockHeight, blockHash)
if err != nil {
return fmt.Errorf("SaveCurrentBlock error %s", err)
Expand Down Expand Up @@ -929,6 +980,16 @@ func (this *LedgerStoreImp) submitBlock(block *types.Block, crossChainMsg *types
if err != nil {
return fmt.Errorf("save to msg cross chain store height:%d error:%s", blockHeight, err)
}
this.updateStateToTree(result.WriteSet)
rootHash, version, err := this.stateTree.SaveVersion()
if err != nil {
return fmt.Errorf("stateTree.SaveVersion height:%d err %s", blockHeight, err)
}
log.Infof("state tree save version, root hash: %s, version: %d", hex.EncodeToString(rootHash), version)
result.StateRoot, err = common.Uint256ParseFromBytes(rootHash)
if err != nil {
return fmt.Errorf("common.Uint256ParseFromBytes height:%d err %s", blockHeight, err)
}
err = this.saveBlockToStateStore(block, result)
if err != nil {
return fmt.Errorf("save to state store height:%d error:%s", blockHeight, err)
Expand Down Expand Up @@ -1040,6 +1101,13 @@ func (this *LedgerStoreImp) saveHeaderIndexList() error {
return nil
}

func (this *LedgerStoreImp) updateStateToTree(writeSet *overlaydb.MemDB) {
writeSet.ForEach(func(key, val []byte) {
this.stateTree.Set(key, val)
log.Infof("update state to tree, key: %s", hex.EncodeToString(key))
})
}

//IsContainBlock return whether the block is in store
func (this *LedgerStoreImp) IsContainBlock(blockHash common.Uint256) (bool, error) {
return this.blockStore.ContainBlock(blockHash)
Expand Down
Loading

0 comments on commit 666f7ee

Please sign in to comment.