diff --git a/internal/ledger/account_test.go b/internal/ledger/account_test.go index 860154e..1903d98 100644 --- a/internal/ledger/account_test.go +++ b/internal/ledger/account_test.go @@ -44,3 +44,7 @@ func TestAccount_GetState(t *testing.T) { assert.False(t, ok) assert.Nil(t, v) } + +func TestAccount_AddState(t *testing.T) { + +} diff --git a/internal/ledger/ledger.go b/internal/ledger/ledger.go index ec3740c..8b6a64c 100644 --- a/internal/ledger/ledger.go +++ b/internal/ledger/ledger.go @@ -60,6 +60,9 @@ func New(repo *repo.Repo, blockchainStore storage.Storage, ldb storage.Storage, prevJnlHash := types.Hash{} if maxJnlHeight != 0 { blockJournal := getBlockJournal(maxJnlHeight, ldb) + if blockJournal == nil { + return nil, fmt.Errorf("get empty block journal for block: %d", maxJnlHeight) + } prevJnlHash = blockJournal.ChangedHash } @@ -181,4 +184,5 @@ func (l *ChainLedger) Events(txHash string) []*pb.Event { // Close close the ledger instance func (l *ChainLedger) Close() { l.ldb.Close() + l.blockchainStore.Close() } diff --git a/internal/ledger/ledger_test.go b/internal/ledger/ledger_test.go index 646420b..e23409e 100644 --- a/internal/ledger/ledger_test.go +++ b/internal/ledger/ledger_test.go @@ -3,6 +3,7 @@ package ledger import ( "crypto/sha256" "encoding/hex" + "encoding/json" "io/ioutil" "path/filepath" "testing" @@ -20,18 +21,101 @@ import ( "github.com/stretchr/testify/require" ) -func TestLedger_Commit(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_commit") - assert.Nil(t, err) +func TestNew001(t *testing.T) { + repoRoot, err := ioutil.TempDir("", "TestChainLedger") + require.Nil(t, err) + blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) assert.Nil(t, err) ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) assert.Nil(t, err) + ledger, err := New(createMockRepo(t), blockStorage, ldb, nil, log.NewWithModule("executor")) + require.Nil(t, err) + require.NotNil(t, ledger) +} + +func TestNew002(t *testing.T) { + repoRoot, err := ioutil.TempDir("", "TestChainLedger") + require.Nil(t, err) + + blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) + assert.Nil(t, err) + ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) + assert.Nil(t, err) + + blockStorage.Put([]byte(chainMetaKey), []byte{1}) + accountCache, err := NewAccountCache() assert.Nil(t, err) ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) + require.NotNil(t, err) + require.Nil(t, ledger) +} + +func TestNew003(t *testing.T) { + repoRoot, err := ioutil.TempDir("", "TestChainLedger") + require.Nil(t, err) + + blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) assert.Nil(t, err) + ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) + assert.Nil(t, err) + + ldb.Put(compositeKey(journalKey, maxHeightStr), marshalHeight(1)) + + ledger, err := New(createMockRepo(t), blockStorage, ldb, nil, log.NewWithModule("executor")) + require.NotNil(t, err) + require.Nil(t, ledger) +} + +func TestNew004(t *testing.T) { + repoRoot, err := ioutil.TempDir("", "TestChainLedger") + require.Nil(t, err) + + blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) + assert.Nil(t, err) + ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) + assert.Nil(t, err) + + ldb.Put(compositeKey(journalKey, maxHeightStr), marshalHeight(1)) + + journal := &BlockJournal{} + data, err := json.Marshal(journal) + assert.Nil(t, err) + + ldb.Put(compositeKey(journalKey, 1), data) + + ledger, err := New(createMockRepo(t), blockStorage, ldb, nil, log.NewWithModule("executor")) + require.Nil(t, err) + require.NotNil(t, ledger) +} + +func TestNew005(t *testing.T) { + repoRoot, err := ioutil.TempDir("", "TestChainLedger") + require.Nil(t, err) + + blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) + assert.Nil(t, err) + ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) + assert.Nil(t, err) + + ldb.Put(compositeKey(journalKey, maxHeightStr), marshalHeight(5)) + ldb.Put(compositeKey(journalKey, minHeightStr), marshalHeight(3)) + + journal := &BlockJournal{} + data, err := json.Marshal(journal) + assert.Nil(t, err) + + ldb.Put(compositeKey(journalKey, 5), data) + + ledger, err := New(createMockRepo(t), blockStorage, ldb, nil, log.NewWithModule("executor")) + require.NotNil(t, err) + require.Nil(t, ledger) +} + +func TestChainLedger_PersistBlockData(t *testing.T) { + ledger, _ := initLedger(t, "") // create an account account := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{100}, 20)) @@ -39,24 +123,38 @@ func TestLedger_Commit(t *testing.T) { ledger.SetState(account, []byte("a"), []byte("b")) accounts, journal := ledger.FlushDirtyDataAndComputeJournal() ledger.PersistBlockData(genBlockData(1, accounts, journal)) +} + +func TestChainLedger_Commit(t *testing.T) { + ledger, repoRoot := initLedger(t, "") + + // create an account + account := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{100}, 20)) + + ledger.SetState(account, []byte("a"), []byte("b")) + accounts, journal := ledger.FlushDirtyDataAndComputeJournal() + err := ledger.Commit(1, accounts, journal) + assert.Nil(t, err) assert.Equal(t, uint64(1), ledger.Version()) assert.Equal(t, "0xA1a6d35708Fa6Cf804B6cF9479F3a55d9A87FbFB83c55a64685AeaBdBa6116B1", journal.ChangedHash.Hex()) accounts, journal = ledger.FlushDirtyDataAndComputeJournal() - ledger.PersistBlockData(genBlockData(2, accounts, journal)) + err = ledger.Commit(2, accounts, journal) + assert.Nil(t, err) assert.Equal(t, uint64(2), ledger.Version()) assert.Equal(t, "0xF09F0198C06D549316D4ee7C497C9eaeF9D24f5b1075e7bCEF3D0a82DfA742cF", journal.ChangedHash.Hex()) ledger.SetState(account, []byte("a"), []byte("3")) ledger.SetState(account, []byte("a"), []byte("2")) accounts, journal = ledger.FlushDirtyDataAndComputeJournal() - ledger.PersistBlockData(genBlockData(3, accounts, journal)) + err = ledger.Commit(3, accounts, journal) + assert.Nil(t, err) assert.Equal(t, uint64(3), ledger.Version()) assert.Equal(t, "0xe9FC370DD36C9BD5f67cCfbc031C909F53A3d8bC7084C01362c55f2D42bA841c", journal.ChangedHash.Hex()) ledger.SetBalance(account, 100) accounts, journal = ledger.FlushDirtyDataAndComputeJournal() - ledger.PersistBlockData(genBlockData(4, accounts, journal)) + err = ledger.Commit(4, accounts, journal) assert.Nil(t, err) assert.Equal(t, uint64(4), ledger.Version()) assert.Equal(t, "0xC179056204BA33eD6CFC0bfE94ca03319BEb522fd7B0773A589899817B49ec08", journal.ChangedHash.Hex()) @@ -66,13 +164,13 @@ func TestLedger_Commit(t *testing.T) { ledger.SetState(account, []byte("b"), []byte("3")) ledger.SetState(account, []byte("c"), []byte("2")) accounts, journal = ledger.FlushDirtyDataAndComputeJournal() - ledger.PersistBlockData(genBlockData(5, accounts, journal)) + err = ledger.Commit(5, accounts, journal) + assert.Nil(t, err) assert.Equal(t, uint64(5), ledger.Version()) assert.Equal(t, uint64(5), ledger.maxJnlHeight) minHeight, maxHeight := getJournalRange(ledger.ldb) journal5 := getBlockJournal(maxHeight, ledger.ldb) - assert.Nil(t, err) assert.Equal(t, uint64(1), minHeight) assert.Equal(t, uint64(5), maxHeight) assert.Equal(t, journal.ChangedHash, journal5.ChangedHash) @@ -91,46 +189,29 @@ func TestLedger_Commit(t *testing.T) { ledger.Close() - // load ChainLedger from db - ldb, err = leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) + // load ChainLedger from db, rollback to height 0 since no chain meta stored + ldg, repoRoot := initLedger(t, repoRoot) + assert.Equal(t, uint64(0), ldg.maxJnlHeight) + assert.Equal(t, types.Hash{}, ldg.prevJnlHash) - ldg, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) - assert.Equal(t, uint64(5), ldg.maxJnlHeight) - assert.Equal(t, journal.ChangedHash, ldg.prevJnlHash) + ok, _ := ldg.GetState(account, []byte("a")) + assert.False(t, ok) - ok, value := ldg.GetState(account, []byte("a")) - assert.True(t, ok) - assert.Equal(t, []byte("2"), value) + ok, _ = ldg.GetState(account, []byte("b")) + assert.False(t, ok) - ok, value = ldg.GetState(account, []byte("b")) - assert.True(t, ok) - assert.Equal(t, []byte("3"), value) + ok, _ = ldg.GetState(account, []byte("c")) + assert.False(t, ok) - ok, value = ldg.GetState(account, []byte("c")) - assert.True(t, ok) - assert.Equal(t, []byte("2"), value) - - assert.Equal(t, uint64(100), ldg.GetBalance(account)) - assert.Equal(t, code, ldg.GetCode(account)) + assert.Equal(t, uint64(0), ldg.GetBalance(account)) + assert.Equal(t, []byte(nil), ldg.GetCode(account)) ver := ldg.Version() - assert.Equal(t, uint64(5), ver) + assert.Equal(t, uint64(0), ver) } func TestChainLedger_Rollback(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_rollback") - assert.Nil(t, err) - blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) - assert.Nil(t, err) - ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache, err := NewAccountCache() - assert.Nil(t, err) - ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) + ledger, repoRoot := initLedger(t, "") // create an addr0 addr0 := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{100}, 20)) @@ -228,13 +309,7 @@ func TestChainLedger_Rollback(t *testing.T) { ledger.Close() - ldb, err = leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache1, err := NewAccountCache() - assert.Nil(t, err) - ledger, err = New(createMockRepo(t), blockStorage, ldb, accountCache1, log.NewWithModule("executor")) - assert.Nil(t, err) + ledger, _ = initLedger(t, repoRoot) assert.Equal(t, uint64(2), ledger.minJnlHeight) assert.Equal(t, uint64(2), ledger.maxJnlHeight) @@ -243,17 +318,7 @@ func TestChainLedger_Rollback(t *testing.T) { } func TestChainLedger_RemoveJournalsBeforeBlock(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_removeJournal") - assert.Nil(t, err) - blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) - assert.Nil(t, err) - ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache, err := NewAccountCache() - assert.Nil(t, err) - ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) + ledger, repoRoot := initLedger(t, "") assert.Equal(t, uint64(0), ledger.minJnlHeight) assert.Equal(t, uint64(0), ledger.maxJnlHeight) @@ -276,7 +341,7 @@ func TestChainLedger_RemoveJournalsBeforeBlock(t *testing.T) { assert.Equal(t, uint64(4), maxHeight) assert.Equal(t, journal4.ChangedHash, journal.ChangedHash) - err = ledger.RemoveJournalsBeforeBlock(5) + err := ledger.RemoveJournalsBeforeBlock(5) assert.Equal(t, ErrorRemoveJournalOutOfRange, err) err = ledger.RemoveJournalsBeforeBlock(2) @@ -316,26 +381,15 @@ func TestChainLedger_RemoveJournalsBeforeBlock(t *testing.T) { assert.Equal(t, journal4.ChangedHash, journal.ChangedHash) ledger.Close() - ldb, err = leveldb.New(filepath.Join(repoRoot, "ledger")) - ledger, err = New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) + + ledger, repoRoot = initLedger(t, repoRoot) assert.Equal(t, uint64(4), ledger.minJnlHeight) assert.Equal(t, uint64(4), ledger.maxJnlHeight) assert.Equal(t, journal4.ChangedHash, ledger.prevJnlHash) } func TestChainLedger_QueryByPrefix(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_queryByPrefix") - assert.Nil(t, err) - blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) - assert.Nil(t, err) - ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache, err := NewAccountCache() - assert.Nil(t, err) - ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) + ledger, _ := initLedger(t, "") addr := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{1}, 20)) key0 := []byte{100, 100} @@ -357,7 +411,7 @@ func TestChainLedger_QueryByPrefix(t *testing.T) { assert.Equal(t, []byte("1"), vals[1]) assert.Equal(t, []byte("2"), vals[2]) - err = ledger.Commit(1, accounts, journal) + err := ledger.Commit(1, accounts, journal) assert.Nil(t, err) ok, vals = ledger.QueryByPrefix(addr, string([]byte{100})) @@ -370,17 +424,7 @@ func TestChainLedger_QueryByPrefix(t *testing.T) { } func TestChainLedger_GetAccount(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_getAccount") - assert.Nil(t, err) - blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) - assert.Nil(t, err) - ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache, err := NewAccountCache() - assert.Nil(t, err) - ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) + ledger, _ := initLedger(t, "") addr := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{1}, 20)) code := bytesutil.LeftPadBytes([]byte{1}, 120) @@ -396,7 +440,7 @@ func TestChainLedger_GetAccount(t *testing.T) { account.SetState(key1, key0) accounts, journal := ledger.FlushDirtyDataAndComputeJournal() - err = ledger.Commit(1, accounts, journal) + err := ledger.Commit(1, accounts, journal) assert.Nil(t, err) account1 := ledger.GetAccount(addr) @@ -438,17 +482,7 @@ func TestChainLedger_GetAccount(t *testing.T) { } func TestChainLedger_GetCode(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_getCode") - assert.Nil(t, err) - blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) - assert.Nil(t, err) - ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache, err := NewAccountCache() - assert.Nil(t, err) - ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) + ledger, _ := initLedger(t, "") addr := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{1}, 20)) code := bytesutil.LeftPadBytes([]byte{10}, 120) @@ -459,7 +493,7 @@ func TestChainLedger_GetCode(t *testing.T) { ledger.SetCode(addr, code) accounts, journal := ledger.FlushDirtyDataAndComputeJournal() - err = ledger.Commit(1, accounts, journal) + err := ledger.Commit(1, accounts, journal) assert.Nil(t, err) vals := ledger.GetCode(addr) @@ -477,17 +511,7 @@ func TestChainLedger_GetCode(t *testing.T) { } func TestChainLedger_AddAccountsToCache(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_addAccountToCache") - assert.Nil(t, err) - blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) - assert.Nil(t, err) - ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache, err := NewAccountCache() - assert.Nil(t, err) - ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - assert.Nil(t, err) + ledger, _ := initLedger(t, "") addr := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{1}, 20)) key := []byte{1} @@ -524,7 +548,7 @@ func TestChainLedger_AddAccountsToCache(t *testing.T) { assert.Equal(t, val, val1) assert.Equal(t, code, ledger.GetCode(addr)) - err = ledger.Commit(1, accounts, journal) + err := ledger.Commit(1, accounts, journal) assert.Nil(t, err) assert.Equal(t, uint64(100), ledger.GetBalance(addr)) @@ -546,17 +570,7 @@ func TestChainLedger_AddAccountsToCache(t *testing.T) { } func TestChainLedger_GetInterchainMeta(t *testing.T) { - repoRoot, err := ioutil.TempDir("", "ledger_GetInterchainMeta") - require.Nil(t, err) - blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) - assert.Nil(t, err) - ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) - assert.Nil(t, err) - - accountCache, err := NewAccountCache() - assert.Nil(t, err) - ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) - require.Nil(t, err) + ledger, _ := initLedger(t, "") // create an account account := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{100}, 20)) @@ -592,6 +606,75 @@ func TestChainLedger_GetInterchainMeta(t *testing.T) { require.Equal(t, len(meta.L2Roots), len(meta2.Counter)) } +func TestChainLedger_AddState(t *testing.T) { + ledger, _ := initLedger(t, "") + + account := types.Bytes2Address(bytesutil.LeftPadBytes([]byte{100}, 20)) + key0 := "100" + value0 := []byte{100} + ledger.AddState(account, []byte(key0), value0) + accounts, journal := ledger.FlushDirtyDataAndComputeJournal() + + ledger.PersistBlockData(genBlockData(1, accounts, journal)) + require.Equal(t, uint64(1), ledger.Version()) + + ok, val := ledger.GetState(account, []byte(key0)) + assert.True(t, ok) + assert.Equal(t, value0, val) + + key1 := "101" + value0 = []byte{99} + value1 := []byte{101} + ledger.SetState(account, []byte(key0), value0) + ledger.AddState(account, []byte(key1), value1) + accounts, journal = ledger.FlushDirtyDataAndComputeJournal() + + ledger.PersistBlockData(genBlockData(2, accounts, journal)) + require.Equal(t, uint64(2), ledger.Version()) + + ok, val = ledger.GetState(account, []byte(key0)) + assert.True(t, ok) + assert.Equal(t, value0, val) + + ok, val = ledger.GetState(account, []byte(key1)) + assert.True(t, ok) + assert.Equal(t, value1, val) +} + +func TestChainLedger_AddEvent(t *testing.T) { + ledger, _ := initLedger(t, "") + + hash0 := types.Hash{1} + hash1 := types.Hash{2} + event00 := &pb.Event{ + TxHash: hash0, + Data: nil, + Interchain: false, + } + event01 := &pb.Event{ + TxHash: hash0, + Data: []byte{1}, + Interchain: true, + } + event10 := &pb.Event{ + TxHash: hash1, + Data: []byte{1}, + Interchain: true, + } + + ledger.AddEvent(event00) + ledger.AddEvent(event01) + ledger.AddEvent(event10) + + events := ledger.Events(hash0.Hex()) + assert.Equal(t, 2, len(events)) + assert.Equal(t, event00, events[0]) + assert.Equal(t, event01, events[1]) + + events = ledger.Events("123") + assert.Equal(t, 0, len(events)) +} + func genBlockData(height uint64, accounts map[types.Address]*Account, journal *BlockJournal) *BlockData { return &BlockData{ Block: &pb.Block{ @@ -626,3 +709,23 @@ BcNwjTDCxyxLNjFKQfMAc6sY6iJs+Ma59WZyC/4uhjE= }, } } + +func initLedger(t *testing.T, repoRoot string) (*ChainLedger, string) { + if repoRoot == "" { + root, err := ioutil.TempDir("", "TestChainLedger") + require.Nil(t, err) + repoRoot = root + } + + blockStorage, err := leveldb.New(filepath.Join(repoRoot, "storage")) + assert.Nil(t, err) + ldb, err := leveldb.New(filepath.Join(repoRoot, "ledger")) + assert.Nil(t, err) + + accountCache, err := NewAccountCache() + assert.Nil(t, err) + ledger, err := New(createMockRepo(t), blockStorage, ldb, accountCache, log.NewWithModule("executor")) + require.Nil(t, err) + + return ledger, repoRoot +}