From 6f7b48aa440c2841e7fe2d97e1c977ecf4123203 Mon Sep 17 00:00:00 2001 From: Jeffrey Picard Date: Mon, 10 Jan 2022 03:11:55 -0500 Subject: [PATCH] ActiveAmount --- db/prefixes/prefixes.go | 112 ++++++++++++++++++++++++++++++++--- db/prefixes/prefixes_test.go | 92 ++++++++++++++++++++++++++++ main.go | 4 +- resources/active_amount.csv | 10 ++++ 4 files changed, 209 insertions(+), 9 deletions(-) create mode 100644 resources/active_amount.csv diff --git a/db/prefixes/prefixes.go b/db/prefixes/prefixes.go index af1d485..e0987d0 100644 --- a/db/prefixes/prefixes.go +++ b/db/prefixes/prefixes.go @@ -664,14 +664,110 @@ class ActiveAmountValue(typing.NamedTuple): type ActiveAmountKey struct { Prefix []byte `json:"prefix"` ClaimHash []byte `json:"claim_hash"` - TxoType int32 `json:"txo_type"` - ActivationHeight int32 `json:"activation_height"` - TxNum int32 `json:"tx_num"` - Position int32 `json:"position"` + TxoType uint8 `json:"txo_type"` + ActivationHeight uint32 `json:"activation_height"` + TxNum uint32 `json:"tx_num"` + Position uint16 `json:"position"` } type ActiveAmountValue struct { - Amount int32 `json:"amount"` + Amount uint64 `json:"amount"` +} + +func (k *ActiveAmountKey) PackKey() []byte { + prefixLen := 1 + // b'>20sBLLH' + n := prefixLen + 20 + 1 + 4 + 4 + 2 + key := make([]byte, n) + copy(key, k.Prefix) + copy(key[prefixLen:], k.ClaimHash[:20]) + copy(key[prefixLen+20:], []byte{k.TxoType}) + binary.BigEndian.PutUint32(key[prefixLen+20+1:], k.ActivationHeight) + binary.BigEndian.PutUint32(key[prefixLen+20+1+4:], k.TxNum) + binary.BigEndian.PutUint16(key[prefixLen+20+1+4+4:], k.Position) + + return key +} + +func (v *ActiveAmountValue) PackValue() []byte { + // b'>Q' + value := make([]byte, 8) + binary.BigEndian.PutUint64(value, v.Amount) + + return value +} + +func ActiveAmountKeyPackPartialNFields(nFields int) func(*ActiveAmountKey) []byte { + return func(u *ActiveAmountKey) []byte { + return ActiveAmountKeyPackPartial(u, nFields) + } +} + +func ActiveAmountKeyPackPartial(k *ActiveAmountKey, 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 > 5 { + nFields = 5 + } + if nFields < 0 { + nFields = 0 + } + + prefixLen := 1 + var n = prefixLen + for i := 0; i <= nFields; i++ { + switch i { + case 1: + n += 20 + case 2: + n += 1 + case 3: + n += 4 + case 4: + n += 4 + case 5: + n += 2 + } + } + + key := make([]byte, n) + + for i := 0; i <= nFields; i++ { + switch i { + case 0: + copy(key, k.Prefix) + case 1: + copy(key[prefixLen:], k.ClaimHash) + case 2: + copy(key[prefixLen+20:], []byte{k.TxoType}) + case 3: + binary.BigEndian.PutUint32(key[prefixLen+20+1:], k.ActivationHeight) + case 4: + binary.BigEndian.PutUint32(key[prefixLen+20+1+4:], k.TxNum) + case 5: + binary.BigEndian.PutUint16(key[prefixLen+20+1+4+4:], k.Position) + } + } + + return key +} + +func ActiveAmountKeyUnpack(key []byte) *ActiveAmountKey { + prefixLen := 1 + return &ActiveAmountKey{ + Prefix: key[:prefixLen], + ClaimHash: key[prefixLen : prefixLen+20], + TxoType: uint8(key[prefixLen+20 : prefixLen+20+1][0]), + ActivationHeight: binary.BigEndian.Uint32(key[prefixLen+20+1:]), + TxNum: binary.BigEndian.Uint32(key[prefixLen+20+1+4:]), + Position: binary.BigEndian.Uint16(key[prefixLen+20+1+4+4:]), + } +} + +func ActiveAmountValueUnpack(value []byte) *ActiveAmountValue { + return &ActiveAmountValue{ + Amount: binary.BigEndian.Uint64(value), + } } // @@ -1427,8 +1523,9 @@ func UnpackGenericKey(key []byte) (byte, interface{}, error) { case ClaimTakeover: case PendingActivation: case ActivatedClaimAndSupport: - case ActiveAmount: return 0x0, nil, errors.Base("key unpack function for %v not implemented", firstByte) + case ActiveAmount: + return ActiveAmount, ActiveAmountKeyUnpack(key), nil case Repost: return Repost, RepostKeyUnpack(key), nil @@ -1488,8 +1585,9 @@ func UnpackGenericValue(key, value []byte) (byte, interface{}, error) { case ClaimTakeover: case PendingActivation: case ActivatedClaimAndSupport: - case ActiveAmount: return 0x0, nil, errors.Base("value unpack not implemented for key %v", key) + case ActiveAmount: + return ActiveAmount, ActiveAmountValueUnpack(value), nil case Repost: return Repost, RepostValueUnpack(value), nil diff --git a/db/prefixes/prefixes_test.go b/db/prefixes/prefixes_test.go index 41c9c39..18778af 100644 --- a/db/prefixes/prefixes_test.go +++ b/db/prefixes/prefixes_test.go @@ -44,6 +44,98 @@ func testInit(filePath string) (*grocksdb.DB, [][]string, func()) { return db, records, toDefer } +func TestActiveAmount(t *testing.T) { + + filePath := "../../resources/active_amount.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.ActiveAmount}).WithIncludeValue(true) + ch := dbpkg.Iter(db, options) + var i = 0 + for kv := range ch { + // log.Println(kv.Key) + gotKey := kv.Key.(*prefixes.ActiveAmountKey).PackKey() + + keyPartial1 := prefixes.ActiveAmountKeyPackPartial(kv.Key.(*prefixes.ActiveAmountKey), 1) + keyPartial2 := prefixes.ActiveAmountKeyPackPartial(kv.Key.(*prefixes.ActiveAmountKey), 2) + keyPartial3 := prefixes.ActiveAmountKeyPackPartial(kv.Key.(*prefixes.ActiveAmountKey), 3) + keyPartial4 := prefixes.ActiveAmountKeyPackPartial(kv.Key.(*prefixes.ActiveAmountKey), 4) + keyPartial5 := prefixes.ActiveAmountKeyPackPartial(kv.Key.(*prefixes.ActiveAmountKey), 5) + + // Check pack partial for sanity + if !bytes.HasPrefix(gotKey, keyPartial1) { + t.Errorf("%+v should be prefix of %+v\n", keyPartial1, gotKey) + } + if !bytes.HasPrefix(gotKey, keyPartial2) { + t.Errorf("%+v should be prefix of %+v\n", keyPartial2, gotKey) + } + if !bytes.HasPrefix(gotKey, keyPartial3) { + t.Errorf("%+v should be prefix of %+v\n", keyPartial3, gotKey) + } + if !bytes.HasPrefix(gotKey, keyPartial4) { + t.Errorf("%+v should be prefix of %+v\n", keyPartial4, gotKey) + } + if !bytes.HasPrefix(gotKey, keyPartial5) { + t.Errorf("%+v should be prefix of %+v\n", keyPartial5, gotKey) + } + + got := kv.Value.(*prefixes.ActiveAmountValue).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.ActiveAmountValue).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 TestEffectiveAmount(t *testing.T) { filePath := "../../resources/effective_amount.csv" diff --git a/main.go b/main.go index e6b00ce..2831cdd 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,7 @@ func main() { options := &db.IterOptions{ FillCache: false, - Prefix: []byte{prefixes.EffectiveAmount}, + Prefix: []byte{prefixes.ActiveAmount}, Start: nil, Stop: nil, IncludeStart: true, @@ -49,7 +49,7 @@ func main() { RawValue: true, } - db.ReadWriteRawN(dbVal, options, "./resources/effective_amount.csv", 10) + db.ReadWriteRawN(dbVal, options, "./resources/active_amount.csv", 10) return } diff --git a/resources/active_amount.csv b/resources/active_amount.csv new file mode 100644 index 0000000..d8c7f63 --- /dev/null +++ b/resources/active_amount.csv @@ -0,0 +1,10 @@ +53000000a420c44374f4f399ab4807fa1901eefc8701000e94ad0297ec210000,00000000000f4240 +53000000c27eef5ea69e0d73f118826c7e326bb46901000773de00371d660000,000000001dcd6500 +5300000110e40894573f528c393fbcec7a472ec85301000d069c01516b320000,0000000000989680 +5300000324e40fcb63a0b517a3660645e9bd99244a01000f2fd8030bb6ba0000,00000000000f4240 +5300000324e40fcb63a0b517a3660645e9bd99244a02000f2ff4030bc8a50000,0000000001312d00 +53000003d1538a0f19f5cd4bc1a62cc294f5c8993401000c816a011c7c990000,00000000000f4240 +53000008d47beeff8325e795a8604226145b01702b01000ef1ed02dbb2a20000,00000000000186a0 +5300000906499e073e94370ceff37cb21c2821244401000fa7c40369842d0000,00000000000186a0 +53000009c3172e034a255f3c03566dca84bb9f046a01000e07020225c69c0000,000000000007a120 +53000009ca6e0caaaef16872b4bd4f6f1b8c2363e201000eb5af02b169560000,00000000000f4240