// Copyright (c) 2019-2020 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or https://www.opensource.org/licenses/mit-license.php . package common import ( "encoding/hex" "encoding/json" "io/ioutil" "os" "testing" "github.com/adityapk00/lightwalletd/parser" "github.com/adityapk00/lightwalletd/walletrpc" ) var compacts []*walletrpc.CompactBlock var cache *BlockCache const ( unitTestPath = "unittestcache" unitTestChain = "unittestnet" ) func TestCache(t *testing.T) { type compactTest struct { BlockHeight int `json:"block"` BlockHash string `json:"hash"` PrevHash string `json:"prev"` Full string `json:"full"` Compact string `json:"compact"` } var compactTests []compactTest blockJSON, err := ioutil.ReadFile("../testdata/compact_blocks.json") if err != nil { t.Fatal(err) } err = json.Unmarshal(blockJSON, &compactTests) if err != nil { t.Fatal(err) } // Derive compact blocks from file data (setup, not part of the test). for _, test := range compactTests { blockData, _ := hex.DecodeString(test.Full) block := parser.NewBlock() blockData, err = block.ParseFromSlice(blockData) if err != nil { t.Fatal(err) } if len(blockData) > 0 { t.Error("Extra data remaining") } compacts = append(compacts, block.ToCompact()) } // Pretend Sapling starts at 289460. os.RemoveAll(unitTestPath) cache = NewBlockCache(unitTestPath, unitTestChain, 289460, true) // Initially cache is empty. if cache.GetLatestHeight() != -1 { t.Fatal("unexpected GetLatestHeight") } if cache.firstBlock != 289460 { t.Fatal("unexpected initial firstBlock") } if cache.nextBlock != 289460 { t.Fatal("unexpected initial nextBlock") } fillCache(t) reorgCache(t) fillCache(t) // Simulate a restart to ensure the db files are read correctly. cache = NewBlockCache(unitTestPath, unitTestChain, 289460, false) // Should still be 6 blocks. if cache.nextBlock != 289466 { t.Fatal("unexpected nextBlock height") } reorgCache(t) // Reorg to before the first block moves back to only the first block cache.Reorg(289459) if cache.latestHash != nil { t.Fatal("unexpected latestHash, should be nil") } if cache.nextBlock != 289460 { t.Fatal("unexpected nextBlock: ", cache.nextBlock) } // Clean up the test files. cache.Close() os.RemoveAll(unitTestPath) } func reorgCache(t *testing.T) { // Simulate a reorg by adding a block whose height is lower than the latest; // we're replacing the second block, so there should be only two blocks. cache.Reorg(289461) err := cache.Add(289461, compacts[1]) if err != nil { t.Fatal(err) } if cache.firstBlock != 289460 { t.Fatal("unexpected firstBlock height") } if cache.nextBlock != 289462 { t.Fatal("unexpected nextBlock height") } if len(cache.starts) != 3 { t.Fatal("unexpected len(cache.starts)") } // some "black-box" tests (using exported interfaces) if cache.GetLatestHeight() != 289461 { t.Fatal("unexpected GetLatestHeight") } if int(cache.Get(289461).Height) != 289461 { t.Fatal("unexpected block contents") } // Make sure we can go forward from here err = cache.Add(289462, compacts[2]) if err != nil { t.Fatal(err) } if cache.firstBlock != 289460 { t.Fatal("unexpected firstBlock height") } if cache.nextBlock != 289463 { t.Fatal("unexpected nextBlock height") } if len(cache.starts) != 4 { t.Fatal("unexpected len(cache.starts)") } if cache.GetLatestHeight() != 289462 { t.Fatal("unexpected GetLatestHeight") } if int(cache.Get(289462).Height) != 289462 { t.Fatal("unexpected block contents") } } // Whatever the state of the cache, add 6 blocks starting at the // pretend Sapling height, 289460 (this could cause a reorg). func fillCache(t *testing.T) { next := 289460 cache.Reorg(next) for i, compact := range compacts { err := cache.Add(next, compact) if err != nil { t.Fatal(err) } next++ // some "white-box" checks if cache.firstBlock != 289460 { t.Fatal("unexpected firstBlock height") } if cache.nextBlock != 289460+i+1 { t.Fatal("unexpected nextBlock height") } if len(cache.starts) != i+2 { t.Fatal("unexpected len(cache.starts)") } // some "black-box" tests (using exported interfaces) if cache.GetLatestHeight() != 289460+i { t.Fatal("unexpected GetLatestHeight") } b := cache.Get(289460 + i) if b == nil { t.Fatal("unexpected Get failure") } if int(b.Height) != 289460+i { t.Fatal("unexpected block contents") } } }