From aba37fc3c5bf1378aa05795f81519de626ebdfc7 Mon Sep 17 00:00:00 2001 From: wangkui0508 Date: Sat, 6 Jan 2024 15:37:04 +0800 Subject: [PATCH 1/6] add rwListMap --- ebp/engine.go | 98 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 18 deletions(-) diff --git a/ebp/engine.go b/ebp/engine.go index b34d864..2523fb7 100644 --- a/ebp/engine.go +++ b/ebp/engine.go @@ -37,6 +37,43 @@ type TxRange struct { end uint64 } +type rwList struct { + rList []uint64 + wList []uint64 +} + +func newRWList() rwList { + return rwList{ + rList: make([]uint64, 0, 32), + wList: make([]uint64, 0, 32), + } +} + +func (rwl *rwList) add(k uint64, isWrite bool) { + if isWrite { + rwl.rList = append(rwl.rList, k) + } else { + rwl.wList = append(rwl.wList, k) + } +} + +func (rwl rwList) conflictsWith(touchedSet map[uint64]struct{}) bool { + for _, l := range [2][]uint64{rwl.rList, rwl.wList} { + for _, k := range l { + if _, ok := touchedSet[k]; ok { + return true + } + } + } + return false +} + +func (rwl rwList) updateTouchedSet(touchedSet map[uint64]struct{}) { + for _, k := range rwl.wList { + touchedSet[k] = struct{}{} + } +} + type txEngine struct { // How many parallel execution round are performed for each block roundNum int //consensus parameter @@ -54,6 +91,9 @@ type txEngine struct { signer gethtypes.Signer currentBlock *types.BlockInfo + rwListMap map[common.Hash]rwList + checkRWInLoading bool + cumulativeGasUsed uint64 cumulativeFeeRefund *uint256.Int cumulativeGasFee *uint256.Int @@ -176,6 +216,10 @@ func NewEbpTxExec(exeRoundCount, runnerNumber, parallelNum, defaultTxListCap int } } +func (exec *txEngine) SetCheckRWInLoading(b bool) { + exec.checkRWInLoading = b +} + func (exec *txEngine) SetAotParam(aotDir string, aotReloadInterval int64) { exec.aotDir = aotDir exec.aotReloadInterval = aotReloadInterval @@ -450,6 +494,7 @@ func (exec *txEngine) Execute(currBlock *types.BlockInfo) { exec.cumulativeFeeRefund = uint256.NewInt(0) exec.cumulativeGasFee = uint256.NewInt(0) exec.currentBlock = currBlock + exec.rwListMap = make(map[common.Hash]rwList, 1024) startKey, endKey := exec.getStandbyQueueRange() if startKey == endKey { return @@ -467,6 +512,9 @@ func (exec *txEngine) Execute(currBlock *types.BlockInfo) { break } numTx := exec.executeOneRound(txRange, exec.currentBlock) + if numTx == 0 && exec.checkRWInLoading { + break + } for i := 0; i < numTx; i++ { if Runners[i] == nil { continue // the TX is not committable and needs re-execution @@ -504,24 +552,34 @@ func (exec *txEngine) setStandbyQueueRange(start, end uint64) { // Execute 'runnerNumber' transactions in parallel and commit the ones without any interdependency func (exec *txEngine) executeOneRound(txRange *TxRange, currBlock *types.BlockInfo) int { - txBundle := exec.loadStandbyTxs(txRange) + txBundle, ignoreList := exec.loadStandbyTxs(txRange) + if exec.checkRWInLoading && len(txBundle) == 0 { + return 0 + } kvCount := exec.runTxInParallel(txRange, txBundle, currBlock) - exec.checkTxDepsAndUptStandbyQ(txRange, txBundle, int(kvCount)) + exec.checkTxDepsAndUptStandbyQ(txRange, txBundle, ignoreList, int(kvCount)) return len(txBundle) } // Load at most 'exec.runnerNumber' transactions from standby queue -func (exec *txEngine) loadStandbyTxs(txRange *TxRange) (txBundle []types.TxToRun) { +func (exec *txEngine) loadStandbyTxs(txRange *TxRange) (txBundle, ignoreList []types.TxToRun) { + touchedSet := make(map[uint64]struct{}, 4096) ctx := exec.cleanCtx.WithRbtCopy() - end := txRange.end - if end > txRange.start+uint64(exec.runnerNumber) { // load at most exec.runnerNumber - end = txRange.start + uint64(exec.runnerNumber) - } - txBundle = make([]types.TxToRun, end-txRange.start) - for i := txRange.start; i < end; i++ { + txBundle = make([]types.TxToRun, 0, exec.runnerNumber) + ignoreList = make([]types.TxToRun, 0, exec.runnerNumber) + for i := txRange.start; i < txRange.end && len(txBundle) < exec.runnerNumber; i++ { k := types.GetStandbyTxKey(i) bz := ctx.Rbt.GetBaseStore().Get(k) - txBundle[i-txRange.start].FromBytes(bz) + var txToRun types.TxToRun + txToRun.FromBytes(bz) + rwList, isRecorded := exec.rwListMap[txToRun.HashID] + hasConflicts := exec.checkRWInLoading && isRecorded && rwList.conflictsWith(touchedSet) + if hasConflicts { + ignoreList = append(ignoreList, txToRun) + } else { + rwList.updateTouchedSet(touchedSet) + txBundle = append(txBundle, txToRun) + } } ctx.Close(false) return @@ -562,7 +620,7 @@ type indexAndBool struct { // Check interdependency of TXs using 'touchedSet'. The ones with dependency with former committed TXs cannot // be committed and should be inserted back into the standby queue. -func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle []types.TxToRun, kvCount int) { +func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle, ignoreList []types.TxToRun, kvCount int) { touchedSet := make(map[uint64]struct{}, kvCount) var wg sync.WaitGroup idxChan := make(chan indexAndBool, 10) @@ -579,8 +637,10 @@ func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle []typ }() for idx := range txBundle { canCommit := true + rwList := newRWList() Runners[idx].Ctx.Rbt.ScanAllShortKeys(func(key [rabbit.KeySize]byte, dirty bool) (stop bool) { k := binary.LittleEndian.Uint64(key[:]) + rwList.add(k, dirty) if _, ok := touchedSet[k]; ok { canCommit = false // cannot commit if conflicts with touched KV set Runners[idx].Status = types.FAILED_TO_COMMIT @@ -590,13 +650,10 @@ func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle []typ } }) if canCommit { // record the dirty KVs written by a committable TX into toucchedSet - Runners[idx].Ctx.Rbt.ScanAllShortKeys(func(key [rabbit.KeySize]byte, dirty bool) (stop bool) { - if dirty { - k := binary.LittleEndian.Uint64(key[:]) - touchedSet[k] = struct{}{} - } - return false - }) + rwList.updateTouchedSet(touchedSet) + } + if exec.checkRWInLoading { + exec.rwListMap[Runners[idx].Tx.HashID] = rwList } idxChan <- indexAndBool{idx, canCommit} } @@ -622,6 +679,11 @@ func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle []typ Runners[idx] = nil } } + for _, tx := range ignoreList { + newK := types.GetStandbyTxKey(txRange.end) + txRange.end++ + store.Set(newK, tx.ToBytes()) + } }) } From 993faa7510c74469ae6fd6e743d04db173bfcd98 Mon Sep 17 00:00:00 2001 From: wangkui0508 Date: Sat, 6 Jan 2024 22:52:31 +0800 Subject: [PATCH 2/6] Update engine.go --- ebp/engine.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebp/engine.go b/ebp/engine.go index 2523fb7..255ecaf 100644 --- a/ebp/engine.go +++ b/ebp/engine.go @@ -51,9 +51,9 @@ func newRWList() rwList { func (rwl *rwList) add(k uint64, isWrite bool) { if isWrite { - rwl.rList = append(rwl.rList, k) - } else { rwl.wList = append(rwl.wList, k) + } else { + rwl.rList = append(rwl.rList, k) } } From 7cd5e4ed187a91dc18da826b3584337e79dc938f Mon Sep 17 00:00:00 2001 From: helldealer Date: Fri, 12 Jan 2024 09:39:16 +0800 Subject: [PATCH 3/6] Fix ignoreList tx repeat in stanbyQ --- ebp/engine.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ebp/engine.go b/ebp/engine.go index 255ecaf..46d5802 100644 --- a/ebp/engine.go +++ b/ebp/engine.go @@ -680,8 +680,13 @@ func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle, igno } } for _, tx := range ignoreList { + k := types.GetStandbyTxKey(txRange.start) + trunk.PrepareForDeletion(k) + store.Delete(k) + txRange.start++ newK := types.GetStandbyTxKey(txRange.end) txRange.end++ + trunk.PrepareForUpdate(newK) store.Set(newK, tx.ToBytes()) } }) From 7ae8157a1eb1bb0e268e8a47794343675a156ac8 Mon Sep 17 00:00:00 2001 From: wangkui0508 Date: Fri, 12 Jan 2024 17:33:39 +0800 Subject: [PATCH 4/6] limit len(ignoreList) --- ebp/engine.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ebp/engine.go b/ebp/engine.go index 46d5802..03c5d49 100644 --- a/ebp/engine.go +++ b/ebp/engine.go @@ -49,6 +49,11 @@ func newRWList() rwList { } } +func (rwl *rwList) reset() { + rwl.wList = rwl.wList[:0] + rwl.rList = rwl.rList[:0] +} + func (rwl *rwList) add(k uint64, isWrite bool) { if isWrite { rwl.wList = append(rwl.wList, k) @@ -566,8 +571,8 @@ func (exec *txEngine) loadStandbyTxs(txRange *TxRange) (txBundle, ignoreList []t touchedSet := make(map[uint64]struct{}, 4096) ctx := exec.cleanCtx.WithRbtCopy() txBundle = make([]types.TxToRun, 0, exec.runnerNumber) - ignoreList = make([]types.TxToRun, 0, exec.runnerNumber) - for i := txRange.start; i < txRange.end && len(txBundle) < exec.runnerNumber; i++ { + ignoreList = make([]types.TxToRun, 0, 2*exec.runnerNumber) + for i := txRange.start; i < txRange.end && len(txBundle) < exec.runnerNumber && len(ignoreList) < 2*exec.runnerNumber; i++ { k := types.GetStandbyTxKey(i) bz := ctx.Rbt.GetBaseStore().Get(k) var txToRun types.TxToRun @@ -635,9 +640,9 @@ func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle, igno } wg.Done() }() + rwList := newRWList() for idx := range txBundle { canCommit := true - rwList := newRWList() Runners[idx].Ctx.Rbt.ScanAllShortKeys(func(key [rabbit.KeySize]byte, dirty bool) (stop bool) { k := binary.LittleEndian.Uint64(key[:]) rwList.add(k, dirty) @@ -654,6 +659,9 @@ func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle, igno } if exec.checkRWInLoading { exec.rwListMap[Runners[idx].Tx.HashID] = rwList + rwList = newRWList() + } else { + rwList.reset() } idxChan <- indexAndBool{idx, canCommit} } From 5b3da876e7ee1f749432d2560aeb11256eb72345 Mon Sep 17 00:00:00 2001 From: wangkui0508 Date: Tue, 16 Jan 2024 10:30:28 +0800 Subject: [PATCH 5/6] Update engine.go --- ebp/engine.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ebp/engine.go b/ebp/engine.go index 03c5d49..a14df6a 100644 --- a/ebp/engine.go +++ b/ebp/engine.go @@ -561,7 +561,7 @@ func (exec *txEngine) executeOneRound(txRange *TxRange, currBlock *types.BlockIn if exec.checkRWInLoading && len(txBundle) == 0 { return 0 } - kvCount := exec.runTxInParallel(txRange, txBundle, currBlock) + kvCount := exec.runTxInParallel(txRange, txBundle, len(ignoreList), currBlock) exec.checkTxDepsAndUptStandbyQ(txRange, txBundle, ignoreList, int(kvCount)) return len(txBundle) } @@ -592,19 +592,23 @@ func (exec *txEngine) loadStandbyTxs(txRange *TxRange) (txBundle, ignoreList []t // Assign the transactions to global 'Runners' and run them in parallel. // Record the count of touched KV pairs and return it as a hint for checkTxDepsAndUptStandbyQ -func (exec *txEngine) runTxInParallel(txRange *TxRange, txBundle []types.TxToRun, currBlock *types.BlockInfo) (kvCount int64) { +func (exec *txEngine) runTxInParallel(txRange *TxRange, txBundle []types.TxToRun, ignoreLen int, currBlock *types.BlockInfo) (kvCount int64) { sharedIdx := int64(-1) + trunk := exec.cleanCtx.Rbt.GetBaseStore() dt.ParallelRun(exec.parallelNum, func(_ int) { for { myIdx := atomic.AddInt64(&sharedIdx, 1) - if myIdx >= int64(len(txBundle)) { + if myIdx >= int64(len(txBundle) + ignoreLen) { return } - Runners[myIdx] = NewTxRunner(exec.cleanCtx.WithRbtCopy(), &txBundle[myIdx]) k := types.GetStandbyTxKey(txRange.start + uint64(myIdx)) - Runners[myIdx].Ctx.Rbt.GetBaseStore().PrepareForDeletion(k) // remove it from the standby queue + trunk.PrepareForDeletion(k) // remove it from the standby queue k = types.GetStandbyTxKey(txRange.end + uint64(myIdx)) - Runners[myIdx].Ctx.Rbt.GetBaseStore().PrepareForUpdate(k) //warm up + trunk.PrepareForUpdate(k) //warm up + if myIdx >= int64(len(txBundle)) { + continue + } + Runners[myIdx] = NewTxRunner(exec.cleanCtx.WithRbtCopy(), &txBundle[myIdx]) if myIdx > 0 && txBundle[myIdx-1].From == txBundle[myIdx].From { // In reorderInfoList, we placed the tx with same 'From' back-to-back // same from-address as previous transaction, cannot run in same round @@ -689,12 +693,10 @@ func (exec *txEngine) checkTxDepsAndUptStandbyQ(txRange *TxRange, txBundle, igno } for _, tx := range ignoreList { k := types.GetStandbyTxKey(txRange.start) - trunk.PrepareForDeletion(k) store.Delete(k) txRange.start++ newK := types.GetStandbyTxKey(txRange.end) txRange.end++ - trunk.PrepareForUpdate(newK) store.Set(newK, tx.ToBytes()) } }) From 3d3567b488a678b10e8ec4f58bd5b78647360a7c Mon Sep 17 00:00:00 2001 From: helldealer Date: Wed, 17 Jan 2024 18:21:25 +0800 Subject: [PATCH 6/6] Add ut --- ebp/engine.go | 9 +++- ebp/engine_test.go | 106 ++++++++++++++++++++++++++++++++------------- 2 files changed, 83 insertions(+), 32 deletions(-) diff --git a/ebp/engine.go b/ebp/engine.go index a14df6a..209cb14 100644 --- a/ebp/engine.go +++ b/ebp/engine.go @@ -44,7 +44,7 @@ type rwList struct { func newRWList() rwList { return rwList{ - rList: make([]uint64, 0, 32), + rList: make([]uint64, 0, 32), wList: make([]uint64, 0, 32), } } @@ -107,6 +107,9 @@ type txEngine struct { aotReloadInterval int64 logger log.Logger + + // for ut + txExecutedCount int } func (exec *txEngine) Context() *types.Context { @@ -508,6 +511,7 @@ func (exec *txEngine) Execute(currBlock *types.BlockInfo) { start: startKey, end: endKey, } + exec.txExecutedCount = 0 committableRunnerList := make([]*TxRunner, 0, 4096) // Repeat exec.roundNum round for execute txs in standby q. At the end of each round // modifications made by TXs are written to world state. So TXs in later rounds can @@ -517,6 +521,7 @@ func (exec *txEngine) Execute(currBlock *types.BlockInfo) { break } numTx := exec.executeOneRound(txRange, exec.currentBlock) + exec.txExecutedCount += numTx if numTx == 0 && exec.checkRWInLoading { break } @@ -598,7 +603,7 @@ func (exec *txEngine) runTxInParallel(txRange *TxRange, txBundle []types.TxToRun dt.ParallelRun(exec.parallelNum, func(_ int) { for { myIdx := atomic.AddInt64(&sharedIdx, 1) - if myIdx >= int64(len(txBundle) + ignoreLen) { + if myIdx >= int64(len(txBundle)+ignoreLen) { return } k := types.GetStandbyTxKey(txRange.start + uint64(myIdx)) diff --git a/ebp/engine_test.go b/ebp/engine_test.go index da4dd63..e213306 100644 --- a/ebp/engine_test.go +++ b/ebp/engine_test.go @@ -3,7 +3,6 @@ package ebp import ( "bytes" "encoding/hex" - "fmt" "math/big" "math/rand" "os" @@ -49,6 +48,7 @@ func prepareCtx(t *store.TrunkStore) *types.Context { var ( _, from1 = GenKeyAndAddr() from2 = common.HexToAddress("0x2") + from3 = common.HexToAddress("0x03") to1 = common.HexToAddress("0x10") to2 = common.HexToAddress("0x20") ) @@ -67,9 +67,12 @@ func prepareAccAndTx(e *txEngine) []*gethtypes.Transaction { acc2 := types.ZeroAccountInfo() balance2, _ := uint256.FromBig(big.NewInt(10000_0000_0000)) acc2.UpdateBalance(balance2) - + acc3 := types.ZeroAccountInfo() + balance3, _ := uint256.FromBig(big.NewInt(10000_0000_0000)) + acc3.UpdateBalance(balance3) e.cleanCtx.SetAccount(from1, acc1) e.cleanCtx.SetAccount(from2, acc2) + e.cleanCtx.SetAccount(from3, acc3) tx1, _ := gethtypes.NewTransaction(0, to1, big.NewInt(100), 100000, big.NewInt(1), nil).WithSignature(e.signer, from1.Bytes()) tx2, _ := gethtypes.NewTransaction(0, to2, big.NewInt(100), 100000, big.NewInt(1), nil).WithSignature(e.signer, from2.Bytes()) @@ -97,7 +100,7 @@ func TestTxEngine_DifferentAccount(t *testing.T) { e.Prepare(0, 0, DefaultTxGasLimit) e.SetContext(prepareCtx(trunk)) startKey, endKey := e.getStandbyQueueRange() - txsStandby := e.loadStandbyTxs(&TxRange{ + txsStandby, _ := e.loadStandbyTxs(&TxRange{ start: startKey, end: endKey, }) @@ -121,6 +124,48 @@ func TestTxEngine_DifferentAccount(t *testing.T) { require.Equal(t, true, startKey == endKey && endKey == 2) } +func TestTxEngine_CheckRWInLoading(t *testing.T) { + AdjustGasUsed = false + trunk, root := prepareTruck() + defer closeTestCtx(root) + e := NewEbpTxExec(5, 100, 2, 10, &testcase.DumbSigner{}, log.NewNopLogger()) + e.SetContext(prepareCtx(trunk)) + txs := prepareAccAndTx(e) + tx2, _ := gethtypes.NewTransaction(0, to1, big.NewInt(100), 100000, big.NewInt(1), nil).WithSignature(e.signer, from2.Bytes()) + txs[1] = tx2 + tx3, _ := gethtypes.NewTransaction(0, to1, big.NewInt(100), 100000, big.NewInt(1), nil).WithSignature(e.signer, from3.Bytes()) + txs = append(txs, tx3) + e.SetContext(prepareCtx(trunk)) + for _, tx := range txs { + e.CollectTx(tx) + } + e.checkRWInLoading = true + e.Prepare(0, 0, DefaultTxGasLimit) + e.SetContext(prepareCtx(trunk)) + startKey, endKey := e.getStandbyQueueRange() + txsStandby, _ := e.loadStandbyTxs(&TxRange{ + start: startKey, + end: endKey, + }) + require.Equal(t, 3, len(txsStandby)) + require.Equal(t, true, bytes.Equal(txs[0].To().Bytes(), txsStandby[0].To.Bytes())) + require.Equal(t, true, bytes.Equal(txs[1].To().Bytes(), txsStandby[1].To.Bytes())) + e.Execute(&types.BlockInfo{}) + require.Equal(t, 3, len(e.committedTxs)) + require.Equal(t, 3+1+1, e.txExecutedCount) + e.SetContext(prepareCtx(trunk)) + to1 := e.cleanCtx.GetAccount(*txs[0].To()) + require.Equal(t, uint64(300), to1.Balance().Uint64()) + from1Acc := e.cleanCtx.GetAccount(from1) + from2Acc := e.cleanCtx.GetAccount(from2) + require.Equal(t, uint64(10000_0000_0000-21000-100), from1Acc.Balance().Uint64()) + require.Equal(t, uint64(10000_0000_0000-21000-100), from2Acc.Balance().Uint64()) + e.cleanCtx.Close(false) + e.SetContext(prepareCtx(trunk)) + startKey, endKey = e.getStandbyQueueRange() + require.Equal(t, true, startKey == endKey && endKey == 6) +} + /* testcase: account1 send txs(nonce): 0, 0, 2, 1, 2 @@ -151,7 +196,7 @@ func TestTxEngine_SameAccount(t *testing.T) { e.Prepare(0, 0, DefaultTxGasLimit) e.SetContext(prepareCtx(trunk)) startKey, endKey := e.getStandbyQueueRange() - txsStandby := e.loadStandbyTxs(&TxRange{ + txsStandby, _ := e.loadStandbyTxs(&TxRange{ start: startKey, end: endKey, }) @@ -212,12 +257,12 @@ func TestRandomTxExecuteConsistent(t *testing.T) { require.Equal(t, true, bytes.Equal(tx1.To.Bytes(), r2.standbyTxs[i].To.Bytes())) require.Equal(t, tx1.Nonce, r2.standbyTxs[i].Nonce) require.Equal(t, true, bytes.Equal(tx1.Value[:], r2.standbyTxs[i].Value[:])) - fmt.Printf( - ` -from:%s -to:%s -nonce:%d -`, tx1.From.String(), tx1.To.String(), tx1.Nonce) + // fmt.Printf( + // ` + //from:%s + //to:%s + //nonce:%d + //`, tx1.From.String(), tx1.To.String(), tx1.Nonce) } //check balance require.Equal(t, r1.from1.Balance(), r2.from1.Balance()) @@ -264,7 +309,7 @@ func executeTxs(randomTxs []*gethtypes.Transaction, trunk *store.TrunkStore) exe } e.Prepare(0, 0, DefaultTxGasLimit) startKey, endKey := e.getStandbyQueueRange() - standbyTxs := e.loadStandbyTxs(&TxRange{ + standbyTxs, _ := e.loadStandbyTxs(&TxRange{ start: startKey, end: endKey, }) @@ -441,29 +486,30 @@ func TestConsistentForDebug(t *testing.T) { txs[7] = tx tx, _ = gethtypes.NewTransaction(3, to2, big.NewInt(109), 100000, big.NewInt(1), nil).WithSignature(signer, from2.Bytes()) txs[8] = tx - r := executeTxs(txs, trunk) + executeTxs(txs, trunk) + //r := executeTxs(txs, trunk) //fmt.Println(r.from1.Balance().Uint64()) //fmt.Println(r.from2.Balance().Uint64()) //fmt.Println(r.to1.Balance().Uint64()) //fmt.Println(r.to2.Balance().Uint64()) - for _, tx := range r.standbyTxs { - fmt.Printf( - ` -starndy tx: -from:%s -to:%s -nonce:%d -`, tx.From.String(), tx.To.String(), tx.Nonce) - } - for _, tx := range r.committedTxs { - fmt.Printf( - ` -commited tx: -from:%v -to:%v -nonce:%d -`, tx.From, tx.To, tx.Nonce) - } + // for _, tx := range r.standbyTxs { + // fmt.Printf( + // ` + //starndy tx: + //from:%s + //to:%s + //nonce:%d + //`, tx.From.String(), tx.To.String(), tx.Nonce) + // } + // for _, tx := range r.committedTxs { + // fmt.Printf( + // ` + //commited tx: + //from:%v + //to:%v + //nonce:%d + //`, tx.From, tx.To, tx.Nonce) + // } } func closeTestCtx(rootStore *store.RootStore) {