diff --git a/db/prefixes/prefixes.go b/db/prefixes/prefixes.go index 39cda6d..6a6ac0a 100644 --- a/db/prefixes/prefixes.go +++ b/db/prefixes/prefixes.go @@ -129,6 +129,82 @@ type BlockHashValue struct { BlockHash []byte `json:"block_hash"` } +func (k *BlockHashKey) PackKey() []byte { + prefixLen := 1 + // b'>L' + n := prefixLen + 4 + key := make([]byte, n) + copy(key, k.Prefix) + binary.BigEndian.PutUint32(key[prefixLen:], k.Height) + + return key +} + +func (v *BlockHashValue) PackValue() []byte { + value := make([]byte, 32) + copy(value, v.BlockHash[:32]) + + return value +} + +func BlockHashKeyPackPartialNFields(nFields int) func(*BlockHashKey) []byte { + return func(u *BlockHashKey) []byte { + return BlockHashKeyPackPartial(u, nFields) + } +} + +func BlockHashKeyPackPartial(k *BlockHashKey, nFields int) []byte { + // Limit nFields between 0 and number of fields, we always at least need + // the prefix, and we never need to iterate past the number of fields. + if nFields > 1 { + nFields = 1 + } + if nFields < 0 { + nFields = 0 + } + + // b'>4sLH' + prefixLen := 1 + var n = prefixLen + for i := 0; i <= nFields; i++ { + switch i { + case 1: + n += 4 + case 2: + n += 4 + case 3: + n += 2 + } + } + + key := make([]byte, n) + + for i := 0; i <= nFields; i++ { + switch i { + case 0: + copy(key, k.Prefix) + case 1: + binary.BigEndian.PutUint32(key[prefixLen:], k.Height) + } + } + + return key +} + +func BlockHashKeyUnpack(key []byte) *BlockHashKey { + prefixLen := 1 + return &BlockHashKey{ + Prefix: key[:prefixLen], + Height: binary.BigEndian.Uint32(key[prefixLen:]), + } +} + +func BlockHashValueUnpack(value []byte) *BlockHashValue { + return &BlockHashValue{ + BlockHash: value[:32], + } +} + /* class BlockTxsKey(NamedTuple): height: int @@ -2590,8 +2666,9 @@ func UnpackGenericKey(key []byte) (byte, interface{}, error) { return ClaimDiff, TouchedOrDeletedClaimKeyUnpack(key), nil case Tx: - case BlockHash: return 0x0, nil, errors.Base("key unpack function for %v not implemented", firstByte) + case BlockHash: + return BlockHash, BlockHashKeyUnpack(key), nil case Header: return Header, BlockHeaderKeyUnpack(key), nil case TxNum: @@ -2664,8 +2741,9 @@ func UnpackGenericValue(key, value []byte) (byte, interface{}, error) { return ClaimDiff, TouchedOrDeletedClaimValueUnpack(value), nil case Tx: - case BlockHash: return 0x0, nil, errors.Base("value unpack not implemented for key %v", key) + case BlockHash: + return BlockHash, BlockHashValueUnpack(value), nil case Header: return Header, BlockHeaderValueUnpack(value), nil case TxNum: diff --git a/db/prefixes/prefixes_test.go b/db/prefixes/prefixes_test.go index d2ef1a6..9a29419 100644 --- a/db/prefixes/prefixes_test.go +++ b/db/prefixes/prefixes_test.go @@ -44,6 +44,82 @@ func testInit(filePath string) (*grocksdb.DB, [][]string, func()) { return db, records, toDefer } +func TestBlockHash(t *testing.T) { + + filePath := "../../resources/block_hash.csv" + + wOpts := grocksdb.NewDefaultWriteOptions() + db, records, toDefer := testInit(filePath) + defer toDefer() + for _, record := range records { + key, err := hex.DecodeString(record[0]) + if err != nil { + log.Println(err) + } + val, err := hex.DecodeString(record[1]) + if err != nil { + log.Println(err) + } + db.Put(wOpts, key, val) + } + // test prefix + options := dbpkg.NewIterateOptions().WithPrefix([]byte{prefixes.BlockHash}).WithIncludeValue(true) + ch := dbpkg.Iter(db, options) + var i = 0 + for kv := range ch { + // log.Println(kv.Key) + gotKey := kv.Key.(*prefixes.BlockHashKey).PackKey() + + keyPartial1 := prefixes.BlockHashKeyPackPartial(kv.Key.(*prefixes.BlockHashKey), 1) + + // Check pack partial for sanity + if !bytes.HasPrefix(gotKey, keyPartial1) { + t.Errorf("%+v should be prefix of %+v\n", keyPartial1, gotKey) + } + + got := kv.Value.(*prefixes.BlockHashValue).PackValue() + wantKey, err := hex.DecodeString(records[i][0]) + if err != nil { + log.Println(err) + } + want, err := hex.DecodeString(records[i][1]) + if err != nil { + log.Println(err) + } + if !bytes.Equal(gotKey, wantKey) { + t.Errorf("gotKey: %+v, wantKey: %+v\n", got, want) + } + if !bytes.Equal(got, want) { + t.Errorf("got: %+v, want: %+v\n", got, want) + } + i++ + } + + // Test start / stop + start, err := hex.DecodeString(records[0][0]) + if err != nil { + log.Println(err) + } + stop, err := hex.DecodeString(records[9][0]) + if err != nil { + log.Println(err) + } + options2 := dbpkg.NewIterateOptions().WithStart(start).WithStop(stop).WithIncludeValue(true) + ch2 := dbpkg.Iter(db, options2) + i = 0 + for kv := range ch2 { + got := kv.Value.(*prefixes.BlockHashValue).PackValue() + want, err := hex.DecodeString(records[i][1]) + if err != nil { + log.Println(err) + } + if !bytes.Equal(got, want) { + t.Errorf("got: %+v, want: %+v\n", got, want) + } + i++ + } +} + func TestBlockHeader(t *testing.T) { filePath := "../../resources/header.csv" diff --git a/main.go b/main.go index 2943ebf..2fd0b01 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,7 @@ func main() { options := &db.IterOptions{ FillCache: false, - Prefix: []byte{prefixes.Header}, + Prefix: []byte{prefixes.BlockHash}, Start: nil, Stop: nil, IncludeStart: true, @@ -49,7 +49,7 @@ func main() { RawValue: true, } - db.ReadWriteRawN(dbVal, options, "./resources/header.csv", 10) + db.ReadWriteRawN(dbVal, options, "./resources/block_hash.csv", 10) return } diff --git a/resources/block_hash.csv b/resources/block_hash.csv new file mode 100644 index 0000000..5037ce8 --- /dev/null +++ b/resources/block_hash.csv @@ -0,0 +1,10 @@ +4300000000,63f4346a4db34fdfce29a70f5e8d11f065f6b91602b7036c7f22f3a03b28899c +4300000001,246cb85843ac936d55388f2ff288b011add5b1b20cca9cfd19a403ca2c9ecbde +4300000002,0044e1258b865d262587c28ff98853bc52bb31266230c1c648cc9004047a5428 +4300000003,bbf8980e3f7604896821203bf62f97f311124da1fbb95bf523fcfdb356ad19c9 +4300000004,1a650b9b7b9d132e257ff6b336ba7cd96b1796357c4fc8dd7d0bd1ff1de057d5 +4300000005,6d694b93a2bb5ac23a13ed6749a789ca751cf73d5982c459e0cd9d5d303da74c +4300000006,b57808c188b7315583cf120fe89de923583bc7a8ebff03189145b86bf859b21b +4300000007,a6a5b330e816242d54c8586ba9b6d63c19d921171ef3d4525b8ffc635742e83a +4300000008,b8447f415279dffe8a09afe6f6d5e335a2f6911fce8e1d1866723d5e5e8a5306 +4300000009,558daee5a4a55fe03d912e35c7b6b0bc19ece82fd5bcb685bc36f2bc381babfd