Skip to content

Change hash representation from slice to 32-byte array #505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions common/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"path/filepath"
"sync"

"github.com/zcash/lightwalletd/hash32"
"github.com/zcash/lightwalletd/walletrpc"
"google.golang.org/protobuf/proto"
)
Expand All @@ -22,10 +23,10 @@ import (
type BlockCache struct {
lengthsName, blocksName string // pathnames
lengthsFile, blocksFile *os.File
starts []int64 // Starting offset of each block within blocksFile
firstBlock int // height of the first block in the cache (usually Sapling activation)
nextBlock int // height of the first block not in the cache
latestHash []byte // hash of the most recent (highest height) block, for detecting reorgs.
starts []int64 // Starting offset of each block within blocksFile
firstBlock int // height of the first block in the cache (usually Sapling activation)
nextBlock int // height of the first block not in the cache
latestHash hash32.T // hash of the most recent (highest height) block, for detecting reorgs.
mutex sync.RWMutex
}

Expand All @@ -44,18 +45,18 @@ func (c *BlockCache) GetFirstHeight() int {
}

// GetLatestHash returns the hash (block ID) of the most recent (highest) known block.
func (c *BlockCache) GetLatestHash() []byte {
func (c *BlockCache) GetLatestHash() hash32.T {
c.mutex.RLock()
defer c.mutex.RUnlock()
return c.latestHash
}

// HashMatch indicates if the given prev-hash matches the most recent block's hash
// so reorgs can be detected.
func (c *BlockCache) HashMatch(prevhash []byte) bool {
func (c *BlockCache) HashMatch(prevhash hash32.T) bool {
c.mutex.RLock()
defer c.mutex.RUnlock()
return c.latestHash == nil || bytes.Equal(c.latestHash, prevhash)
return c.latestHash == hash32.Nil || c.latestHash == prevhash
}

// Make the block at the given height the lowest height that we don't have.
Expand Down Expand Up @@ -167,7 +168,7 @@ func (c *BlockCache) readBlock(height int) *walletrpc.CompactBlock {

// Caller should hold c.mutex.Lock().
func (c *BlockCache) setLatestHash() {
c.latestHash = nil
c.latestHash = hash32.Nil
// There is at least one block; get the last block's hash
if c.nextBlock > c.firstBlock {
// At least one block remains; get the last block's hash
Expand All @@ -176,8 +177,7 @@ func (c *BlockCache) setLatestHash() {
c.recoverFromCorruption(c.nextBlock - 10000)
return
}
c.latestHash = make([]byte, len(block.Hash))
copy(c.latestHash, block.Hash)
c.latestHash = hash32.T(block.Hash)
}
}

Expand Down Expand Up @@ -312,10 +312,7 @@ func (c *BlockCache) Add(height int, block *walletrpc.CompactBlock) error {
offset := c.starts[len(c.starts)-1]
c.starts = append(c.starts, offset+int64(len(data)+8))

if c.latestHash == nil {
c.latestHash = make([]byte, len(block.Hash))
}
copy(c.latestHash, block.Hash)
c.latestHash = hash32.T(block.Hash)
c.nextBlock++
// Invariant: m[firstBlock..nextBlock) are valid.
return nil
Expand Down
3 changes: 2 additions & 1 deletion common/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"testing"

"github.com/zcash/lightwalletd/hash32"
"github.com/zcash/lightwalletd/parser"
"github.com/zcash/lightwalletd/walletrpc"
)
Expand Down Expand Up @@ -84,7 +85,7 @@ func TestCache(t *testing.T) {

// Reorg to before the first block moves back to only the first block
cache.Reorg(289459)
if cache.latestHash != nil {
if cache.latestHash != hash32.Nil {
t.Fatal("unexpected latestHash, should be nil")
}
if cache.nextBlock != 289460 {
Expand Down
18 changes: 9 additions & 9 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package common

import (
"bytes"
"encoding/hex"
"encoding/json"
"errors"
Expand All @@ -15,6 +14,7 @@ import (
"time"

"github.com/sirupsen/logrus"
"github.com/zcash/lightwalletd/hash32"
"github.com/zcash/lightwalletd/parser"
"github.com/zcash/lightwalletd/walletrpc"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -373,12 +373,12 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) {
return nil, errors.New("received unexpected height block")
}
for i, t := range block.Transactions() {
txidBigEndian, err := hex.DecodeString(block1.Tx[i])
txidBigEndian, err := hash32.Decode(block1.Tx[i])
if err != nil {
return nil, fmt.Errorf("error decoding getblock txid: %w", err)
}
// convert from big-endian
t.SetTxID(parser.Reverse(txidBigEndian))
t.SetTxID(hash32.Reverse(txidBigEndian))
}
r := block.ToCompact()
r.ChainMetadata.SaplingCommitmentTreeSize = block1.Trees.Sapling.Size
Expand Down Expand Up @@ -430,13 +430,13 @@ func BlockIngestor(c *BlockCache, rep int) {
if err != nil {
Log.Fatal("bad getbestblockhash return:", err, result)
}
lastBestBlockHashBE, err := hex.DecodeString(hashHex)
lastBestBlockHashBE, err := hash32.Decode(hashHex)
if err != nil {
Log.Fatal("error decoding getbestblockhash", err, hashHex)
}

height := c.GetNextHeight()
if bytes.Equal(lastBestBlockHashBE, parser.Reverse(c.GetLatestHash())) {
if lastBestBlockHashBE == hash32.Reverse(c.GetLatestHash()) {
// Synced
c.Sync()
if lastHeightLogged != height-1 {
Expand All @@ -454,14 +454,14 @@ func BlockIngestor(c *BlockCache, rep int) {
Time.Sleep(8 * time.Second)
continue
}
if block != nil && c.HashMatch(block.PrevHash) {
if block != nil && c.HashMatch(hash32.T(block.PrevHash)) {
if err = c.Add(height, block); err != nil {
Log.Fatal("Cache add failed:", err)
}
// Don't log these too often.
if DarksideEnabled || Time.Now().Sub(lastLog).Seconds() >= 4 {
lastLog = Time.Now()
Log.Info("Adding block to cache ", height, " ", displayHash(block.Hash))
Log.Info("Adding block to cache ", height, " ", displayHash(hash32.T(block.Hash)))
}
continue
}
Expand Down Expand Up @@ -567,6 +567,6 @@ func ParseRawTransaction(message json.RawMessage) (*walletrpc.RawTransaction, er
}, nil
}

func displayHash(hash []byte) string {
return hex.EncodeToString(parser.Reverse(hash))
func displayHash(hash hash32.T) string {
return hash32.Encode(hash32.Reverse(hash))
}
63 changes: 35 additions & 28 deletions common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ var (
testcache *BlockCache
)

const (
testTxid = "1234000000000000000000000000000000000000000000000000000000000000"
testBlockid40 = "0000000000000000000000000000000000000000000000000000000000380640"
testBlockid41 = "0000000000000000000000000000000000000000000000000000000000380641"
testBlockid42 = "0000000000000000000000000000000000000000000000000000000000380642"
)

// TestMain does common setup that's shared across multiple tests
func TestMain(m *testing.M) {
output, err := os.OpenFile("test-log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
Expand Down Expand Up @@ -196,36 +203,36 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
case 1:
checkSleepMethod(0, 0, "getbestblockhash", method)
// This hash doesn't matter, won't match anything
r, _ := json.Marshal("010101")
r, _ := json.Marshal(strings.Repeat("01", 32))
return r, nil
case 2:
checkSleepMethod(0, 0, "getblock", method)
if arg != "380640" {
testT.Fatal("incorrect height requested")
}
// height 380640
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380640\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid40 + "\"}"), nil
case 3:
checkSleepMethod(0, 0, "getblock", method)
if arg != "0000380640" {
if arg != testBlockid40 {
testT.Fatal("incorrect hash requested")
}
return blocks[0], nil
case 4:
checkSleepMethod(0, 0, "getbestblockhash", method)
// This hash doesn't matter, won't match anything
r, _ := json.Marshal("010101")
r, _ := json.Marshal(strings.Repeat("01", 32))
return r, nil
case 5:
checkSleepMethod(0, 0, "getblock", method)
if arg != "380641" {
testT.Fatal("incorrect height requested")
}
// height 380641
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380641\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid41 + "\"}"), nil
case 6:
checkSleepMethod(0, 0, "getblock", method)
if arg != "0000380641" {
if arg != testBlockid41 {
testT.Fatal("incorrect hash requested")
}
return blocks[1], nil
Expand All @@ -244,18 +251,18 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
case 9:
// Simulate new block (any non-matching hash will do)
checkSleepMethod(2, 4, "getbestblockhash", method)
r, _ := json.Marshal("aabb")
r, _ := json.Marshal(strings.Repeat("ab", 32))
return r, nil
case 10:
checkSleepMethod(2, 4, "getblock", method)
if arg != "380642" {
testT.Fatal("incorrect height requested")
}
// height 380642
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380642\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid42 + "\"}"), nil
case 11:
checkSleepMethod(2, 4, "getblock", method)
if arg != "0000380642" {
if arg != testBlockid42 {
testT.Fatal("incorrect hash requested")
}
return blocks[2], nil
Expand All @@ -270,7 +277,7 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
// simulate a 1-block reorg, new version (replacement) of 380642
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("4545")
r, _ := json.Marshal(strings.Repeat("45", 32))
return r, nil
case 14:
// It thinks there may simply be a new block, but we'll say
Expand All @@ -284,7 +291,7 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
// It will re-ask the best hash (let's make no change)
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("4545")
r, _ := json.Marshal(strings.Repeat("45", 32))
return r, nil
case 16:
// It should have backed up one block
Expand All @@ -293,10 +300,10 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
testT.Fatal("incorrect height requested")
}
// height 380642
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380642\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid42 + "\"}"), nil
case 17:
checkSleepMethod(3, 6, "getblock", method)
if arg != "0000380642" {
if arg != testBlockid42 {
testT.Fatal("incorrect height requested")
}
return blocks[2], nil
Expand All @@ -305,7 +312,7 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
// we'll make it back up 2 blocks (rather than one)
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("5656")
r, _ := json.Marshal(strings.Repeat("56", 32))
return r, nil
case 19:
// It thinks there may simply be a new block, but we'll say
Expand All @@ -318,7 +325,7 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
case 20:
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("5656")
r, _ := json.Marshal(strings.Repeat("56", 32))
return r, nil
case 21:
// Like case 13, it should have backed up one block, but
Expand All @@ -331,18 +338,18 @@ func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage
case 22:
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("5656")
r, _ := json.Marshal(strings.Repeat("56", 32))
return r, nil
case 23:
// It should have backed up one more
checkSleepMethod(3, 6, "getblock", method)
if arg != "380641" {
testT.Fatal("incorrect height requested")
}
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380641\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid41 + "\"}"), nil
case 24:
checkSleepMethod(3, 6, "getblock", method)
if arg != "0000380641" {
if arg != testBlockid41 {
testT.Fatal("incorrect height requested")
}
return blocks[1], nil
Expand Down Expand Up @@ -385,17 +392,17 @@ func getblockStub(method string, params []json.RawMessage) (json.RawMessage, err
step++
switch step {
case 1:
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380640\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid40 + "\"}"), nil
case 2:
if arg != "0000380640" {
if arg != testBlockid40 {
testT.Error("unexpected hash")
}
// Sunny-day
return blocks[0], nil
case 3:
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380641\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid41 + "\"}"), nil
case 4:
if arg != "0000380641" {
if arg != testBlockid41 {
testT.Error("unexpected hash")
}
// Sunny-day
Expand Down Expand Up @@ -475,9 +482,9 @@ func getblockStubReverse(method string, params []json.RawMessage) (json.RawMessa
testT.Error("unexpected height")
}
// Sunny-day
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380642\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid42 + "\"}"), nil
case 2:
if arg != "0000380642" {
if arg != testBlockid42 {
testT.Error("unexpected hash")
}
return blocks[2], nil
Expand All @@ -486,9 +493,9 @@ func getblockStubReverse(method string, params []json.RawMessage) (json.RawMessa
testT.Error("unexpected height")
}
// Sunny-day
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380641\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid41 + "\"}"), nil
case 4:
if arg != "0000380641" {
if arg != testBlockid41 {
testT.Error("unexpected hash")
}
return blocks[1], nil
Expand All @@ -497,9 +504,9 @@ func getblockStubReverse(method string, params []json.RawMessage) (json.RawMessa
testT.Error("unexpected height")
}
// Sunny-day
return []byte("{\"Tx\": [\"00\"], \"Hash\": \"0000380640\"}"), nil
return []byte("{\"Tx\": [\"" + testTxid + "\"], \"Hash\": \"" + testBlockid40 + "\"}"), nil
case 6:
if arg != "0000380640" {
if arg != testBlockid40 {
testT.Error("unexpected hash")
}
return blocks[0], nil
Expand Down
Loading