diff --git a/bchain/coins/btc/bitcoinparser.go b/bchain/coins/btc/bitcoinparser.go index 6918c980..79c88e31 100644 --- a/bchain/coins/btc/bitcoinparser.go +++ b/bchain/coins/btc/bitcoinparser.go @@ -14,13 +14,12 @@ import ( "github.com/btcsuite/btcutil" ) -// bitcoinwire parsing - -type BitcoinBlockParser struct { +// BitcoinParser handle +type BitcoinParser struct { Params *chaincfg.Params } -// getChainParams contains network parameters for the main Bitcoin network, +// GetChainParams contains network parameters for the main Bitcoin network, // the regression test Bitcoin network, the test Bitcoin network and // the simulation test Bitcoin network, in this order func GetChainParams(chain string) *chaincfg.Params { @@ -33,18 +32,18 @@ func GetChainParams(chain string) *chaincfg.Params { return &chaincfg.MainNetParams } -// GetAddrIDFromAddress returns internal address representation of given transaction output -func (p *BitcoinBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { +// GetAddrIDFromVout returns internal address representation of given transaction output +func (p *BitcoinParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { return hex.DecodeString(output.ScriptPubKey.Hex) } // GetAddrIDFromAddress returns internal address representation of given address -func (p *BitcoinBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) { +func (p *BitcoinParser) GetAddrIDFromAddress(address string) ([]byte, error) { return p.AddressToOutputScript(address) } // AddressToOutputScript converts bitcoin address to ScriptPubKey -func (p *BitcoinBlockParser) AddressToOutputScript(address string) ([]byte, error) { +func (p *BitcoinParser) AddressToOutputScript(address string) ([]byte, error) { da, err := btcutil.DecodeAddress(address, p.Params) if err != nil { return nil, err @@ -57,7 +56,7 @@ func (p *BitcoinBlockParser) AddressToOutputScript(address string) ([]byte, erro } // OutputScriptToAddresses converts ScriptPubKey to bitcoin addresses -func (p *BitcoinBlockParser) OutputScriptToAddresses(script []byte) ([]string, error) { +func (p *BitcoinParser) OutputScriptToAddresses(script []byte) ([]string, error) { _, addresses, _, err := txscript.ExtractPkScriptAddrs(script, p.Params) if err != nil { return nil, err @@ -69,7 +68,7 @@ func (p *BitcoinBlockParser) OutputScriptToAddresses(script []byte) ([]string, e return rv, nil } -func (p *BitcoinBlockParser) txFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx { +func (p *BitcoinParser) txFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx { vin := make([]bchain.Vin, len(t.TxIn)) for i, in := range t.TxIn { if blockchain.IsCoinBaseTx(t) { @@ -123,7 +122,7 @@ func (p *BitcoinBlockParser) txFromMsgTx(t *wire.MsgTx, parseAddresses bool) bch } // ParseTx parses byte array containing transaction and returns Tx struct -func (p *BitcoinBlockParser) ParseTx(b []byte) (*bchain.Tx, error) { +func (p *BitcoinParser) ParseTx(b []byte) (*bchain.Tx, error) { t := wire.MsgTx{} r := bytes.NewReader(b) if err := t.Deserialize(r); err != nil { @@ -135,7 +134,7 @@ func (p *BitcoinBlockParser) ParseTx(b []byte) (*bchain.Tx, error) { } // ParseBlock parses raw block to our Block struct -func (p *BitcoinBlockParser) ParseBlock(b []byte) (*bchain.Block, error) { +func (p *BitcoinParser) ParseBlock(b []byte) (*bchain.Block, error) { w := wire.MsgBlock{} r := bytes.NewReader(b) @@ -152,7 +151,7 @@ func (p *BitcoinBlockParser) ParseBlock(b []byte) (*bchain.Block, error) { } // PackTx packs transaction to byte array -func (p *BitcoinBlockParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { +func (p *BitcoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { buf := make([]byte, 4+vlq.MaxLen64+len(tx.Hex)/2) binary.BigEndian.PutUint32(buf[0:4], height) vl := vlq.PutInt(buf[4:4+vlq.MaxLen64], blockTime) @@ -161,7 +160,7 @@ func (p *BitcoinBlockParser) PackTx(tx *bchain.Tx, height uint32, blockTime int6 } // UnpackTx unpacks transaction from byte array -func (p *BitcoinBlockParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { +func (p *BitcoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { height := binary.BigEndian.Uint32(buf) bt, l := vlq.Int(buf[4:]) tx, err := p.ParseTx(buf[4+l:]) @@ -172,6 +171,32 @@ func (p *BitcoinBlockParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { return tx, height, nil } -func (p *BitcoinBlockParser) IsUTXOChain() bool { +// PackedTxidLen returns length in bytes of packed txid +func (p *BitcoinParser) PackedTxidLen() int { + return 32 +} + +// PackTxid packs txid to byte array +func (p *BitcoinParser) PackTxid(txid string) ([]byte, error) { + return hex.DecodeString(txid) +} + +// UnpackTxid unpacks byte array to txid +func (p *BitcoinParser) UnpackTxid(buf []byte) (string, error) { + return hex.EncodeToString(buf), nil +} + +// PackBlockHash packs block hash to byte array +func (p *BitcoinParser) PackBlockHash(hash string) ([]byte, error) { + return hex.DecodeString(hash) +} + +// UnpackBlockHash unpacks byte array to block hash +func (p *BitcoinParser) UnpackBlockHash(buf []byte) (string, error) { + return hex.EncodeToString(buf), nil +} + +// IsUTXOChain returns true if the block chain is UTXO type, otherwise false +func (p *BitcoinParser) IsUTXOChain() bool { return true } diff --git a/bchain/coins/btc/bitcoinparser_test.go b/bchain/coins/btc/bitcoinparser_test.go index 761bd9a6..35adacea 100644 --- a/bchain/coins/btc/bitcoinparser_test.go +++ b/bchain/coins/btc/bitcoinparser_test.go @@ -42,7 +42,7 @@ func TestAddressToOutputScript(t *testing.T) { wantErr: false, }, } - parser := &BitcoinBlockParser{Params: GetChainParams("main")} + parser := &BitcoinParser{Params: GetChainParams("main")} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -94,7 +94,7 @@ func TestOutputScriptToAddresses(t *testing.T) { wantErr: false, }, } - parser := &BitcoinBlockParser{Params: GetChainParams("main")} + parser := &BitcoinParser{Params: GetChainParams("main")} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b, _ := hex.DecodeString(tt.args.script) @@ -185,7 +185,7 @@ func Test_PackTx(t *testing.T) { tx bchain.Tx height uint32 blockTime int64 - parser *BitcoinBlockParser + parser *BitcoinParser } tests := []struct { name string @@ -199,7 +199,7 @@ func Test_PackTx(t *testing.T) { tx: testTx1, height: 123456, blockTime: 1519053802, - parser: &BitcoinBlockParser{Params: GetChainParams("main")}, + parser: &BitcoinParser{Params: GetChainParams("main")}, }, want: testTxPacked1, wantErr: false, @@ -210,7 +210,7 @@ func Test_PackTx(t *testing.T) { tx: testTx2, height: 510234, blockTime: 1235678901, - parser: &BitcoinBlockParser{Params: GetChainParams("test")}, + parser: &BitcoinParser{Params: GetChainParams("test")}, }, want: testTxPacked2, wantErr: false, @@ -234,7 +234,7 @@ func Test_PackTx(t *testing.T) { func Test_UnpackTx(t *testing.T) { type args struct { packedTx string - parser *BitcoinBlockParser + parser *BitcoinParser } tests := []struct { name string @@ -247,7 +247,7 @@ func Test_UnpackTx(t *testing.T) { name: "btc-1", args: args{ packedTx: testTxPacked1, - parser: &BitcoinBlockParser{Params: GetChainParams("main")}, + parser: &BitcoinParser{Params: GetChainParams("main")}, }, want: &testTx1, want1: 123456, @@ -257,7 +257,7 @@ func Test_UnpackTx(t *testing.T) { name: "testnet-1", args: args{ packedTx: testTxPacked2, - parser: &BitcoinBlockParser{Params: GetChainParams("test")}, + parser: &BitcoinParser{Params: GetChainParams("test")}, }, want: &testTx2, want1: 510234, diff --git a/bchain/coins/btc/bitcoinrpc.go b/bchain/coins/btc/bitcoinrpc.go index ce1e7f3a..af6a3617 100644 --- a/bchain/coins/btc/bitcoinrpc.go +++ b/bchain/coins/btc/bitcoinrpc.go @@ -83,7 +83,7 @@ func (b *BitcoinRPC) Initialize() error { params := GetChainParams(chainName) // always create parser - b.Parser = &BitcoinBlockParser{ + b.Parser = &BitcoinParser{ Params: params, } diff --git a/bchain/coins/eth/ethparser.go b/bchain/coins/eth/ethparser.go index cf6d3993..50b78cbe 100644 --- a/bchain/coins/eth/ethparser.go +++ b/bchain/coins/eth/ethparser.go @@ -98,9 +98,11 @@ func ethTxToTx(tx *rpcTransaction, blocktime int64, confirmations uint32) (*bcha }, nil } +// EthereumParser handle type EthereumParser struct { } +// GetAddrIDFromVout returns internal address representation of given transaction output func (p *EthereumParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { if len(output.ScriptPubKey.Addresses) != 1 { return nil, bchain.ErrAddressMissing @@ -108,6 +110,7 @@ func (p *EthereumParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) return p.GetAddrIDFromAddress(output.ScriptPubKey.Addresses[0]) } +// GetAddrIDFromAddress returns internal address representation of given address func (p *EthereumParser) GetAddrIDFromAddress(address string) ([]byte, error) { // github.com/ethereum/go-ethereum/common.HexToAddress does not handle address errors, using own decoding if len(address) > 1 { @@ -126,18 +129,22 @@ func (p *EthereumParser) GetAddrIDFromAddress(address string) ([]byte, error) { return hex.DecodeString(address) } +// AddressToOutputScript converts address to ScriptPubKey - currently not implemented func (p *EthereumParser) AddressToOutputScript(address string) ([]byte, error) { return nil, errors.New("AddressToOutputScript: not implemented") } +// OutputScriptToAddresses converts ScriptPubKey to addresses - currently not implemented func (p *EthereumParser) OutputScriptToAddresses(script []byte) ([]string, error) { return nil, errors.New("OutputScriptToAddresses: not implemented") } +// ParseTx parses byte array containing transaction and returns Tx struct - currently not implemented func (p *EthereumParser) ParseTx(b []byte) (*bchain.Tx, error) { return nil, errors.New("ParseTx: not implemented") } +// ParseBlock parses raw block to our Block struct - currently not implemented func (p *EthereumParser) ParseBlock(b []byte) (*bchain.Block, error) { return nil, errors.New("ParseBlock: not implemented") } @@ -164,6 +171,7 @@ func hexEncodeBig(b []byte) string { return hexutil.EncodeBig(&i) } +// PackTx packs transaction to byte array func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { b, err := hex.DecodeString(tx.Hex) if err != nil { @@ -219,6 +227,7 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ( return proto.Marshal(pt) } +// UnpackTx unpacks transaction from byte array func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { var pt ProtoTransaction err := proto.Unmarshal(buf, &pt) @@ -247,6 +256,32 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { return tx, pt.BlockNumber, nil } +// PackedTxidLen returns length in bytes of packed txid +func (p *EthereumParser) PackedTxidLen() int { + return 32 +} + +// PackTxid packs txid to byte array +func (p *EthereumParser) PackTxid(txid string) ([]byte, error) { + return hex.DecodeString(txid) +} + +// UnpackTxid unpacks byte array to txid +func (p *EthereumParser) UnpackTxid(buf []byte) (string, error) { + return hex.EncodeToString(buf), nil +} + +// PackBlockHash packs block hash to byte array +func (p *EthereumParser) PackBlockHash(hash string) ([]byte, error) { + return hex.DecodeString(hash) +} + +// UnpackBlockHash unpacks byte array to block hash +func (p *EthereumParser) UnpackBlockHash(buf []byte) (string, error) { + return hex.EncodeToString(buf), nil +} + +// IsUTXOChain returns true if the block chain is UTXO type, otherwise false func (p *EthereumParser) IsUTXOChain() bool { return false } diff --git a/bchain/coins/zec/zcashparser.go b/bchain/coins/zec/zcashparser.go index 66a80a69..45afb00f 100644 --- a/bchain/coins/zec/zcashparser.go +++ b/bchain/coins/zec/zcashparser.go @@ -5,13 +5,15 @@ import ( "bytes" "encoding/binary" "encoding/gob" + "encoding/hex" "errors" ) -type ZCashBlockParser struct{} +// ZCashParser handle +type ZCashParser struct{} -// GetAddrIDFromAddress returns internal address representation of given transaction output -func (p *ZCashBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { +// GetAddrIDFromVout returns internal address representation of given transaction output +func (p *ZCashParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { if len(output.ScriptPubKey.Addresses) != 1 { return nil, nil } @@ -20,13 +22,13 @@ func (p *ZCashBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error } // GetAddrIDFromAddress returns internal address representation of given address -func (p *ZCashBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) { +func (p *ZCashParser) GetAddrIDFromAddress(address string) ([]byte, error) { hash, _, err := CheckDecode(address) return hash, err } // PackTx packs transaction to byte array -func (p *ZCashBlockParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { +func (p *ZCashParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { buf := make([]byte, 4) binary.BigEndian.PutUint32(buf, height) buf, err := encodeTx(buf, tx) @@ -44,7 +46,7 @@ func encodeTx(b []byte, tx *bchain.Tx) ([]byte, error) { } // UnpackTx unpacks transaction from byte array -func (p *ZCashBlockParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { +func (p *ZCashParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { height := binary.BigEndian.Uint32(buf) tx, err := decodeTx(buf[4:]) if err != nil { @@ -63,22 +65,52 @@ func decodeTx(buf []byte) (*bchain.Tx, error) { return tx, nil } -func (p *ZCashBlockParser) AddressToOutputScript(address string) ([]byte, error) { +// AddressToOutputScript converts address to ScriptPubKey - currently not implemented +func (p *ZCashParser) AddressToOutputScript(address string) ([]byte, error) { return nil, errors.New("AddressToOutputScript: not implemented") } -func (p *ZCashBlockParser) OutputScriptToAddresses(script []byte) ([]string, error) { +// OutputScriptToAddresses converts ScriptPubKey to addresses - currently not implemented +func (p *ZCashParser) OutputScriptToAddresses(script []byte) ([]string, error) { return nil, errors.New("OutputScriptToAddresses: not implemented") } -func (p *ZCashBlockParser) ParseBlock(b []byte) (*bchain.Block, error) { +// ParseBlock parses raw block to our Block struct - currently not implemented +func (p *ZCashParser) ParseBlock(b []byte) (*bchain.Block, error) { return nil, errors.New("ParseBlock: not implemented") } -func (p *ZCashBlockParser) ParseTx(b []byte) (*bchain.Tx, error) { +// ParseTx parses byte array containing transaction and returns Tx struct - currently not implemented +func (p *ZCashParser) ParseTx(b []byte) (*bchain.Tx, error) { return nil, errors.New("ParseTx: not implemented") } -func (p *ZCashBlockParser) IsUTXOChain() bool { +// PackedTxidLen returns length in bytes of packed txid +func (p *ZCashParser) PackedTxidLen() int { + return 32 +} + +// PackTxid packs txid to byte array +func (p *ZCashParser) PackTxid(txid string) ([]byte, error) { + return hex.DecodeString(txid) +} + +// UnpackTxid unpacks byte array to txid +func (p *ZCashParser) UnpackTxid(buf []byte) (string, error) { + return hex.EncodeToString(buf), nil +} + +// PackBlockHash packs block hash to byte array +func (p *ZCashParser) PackBlockHash(hash string) ([]byte, error) { + return hex.DecodeString(hash) +} + +// UnpackBlockHash unpacks byte array to block hash +func (p *ZCashParser) UnpackBlockHash(buf []byte) (string, error) { + return hex.EncodeToString(buf), nil +} + +// IsUTXOChain returns true if the block chain is UTXO type, otherwise false +func (p *ZCashParser) IsUTXOChain() bool { return true } diff --git a/bchain/coins/zec/zcashparser_test.go b/bchain/coins/zec/zcashparser_test.go index fbff4870..5c713668 100644 --- a/bchain/coins/zec/zcashparser_test.go +++ b/bchain/coins/zec/zcashparser_test.go @@ -87,7 +87,7 @@ func TestPackTx(t *testing.T) { tx bchain.Tx height uint32 blockTime int64 - parser *ZCashBlockParser + parser *ZCashParser } tests := []struct { name string @@ -101,7 +101,7 @@ func TestPackTx(t *testing.T) { tx: testTx1, height: 292272, blockTime: 1521645728, - parser: &ZCashBlockParser{}, + parser: &ZCashParser{}, }, want: testTxPacked1, wantErr: false, @@ -112,7 +112,7 @@ func TestPackTx(t *testing.T) { tx: testTx2, height: 292217, blockTime: 1521637604, - parser: &ZCashBlockParser{}, + parser: &ZCashParser{}, }, want: testTxPacked2, wantErr: false, @@ -136,7 +136,7 @@ func TestPackTx(t *testing.T) { func TestUnpackTx(t *testing.T) { type args struct { packedTx string - parser *ZCashBlockParser + parser *ZCashParser } tests := []struct { name string @@ -149,7 +149,7 @@ func TestUnpackTx(t *testing.T) { name: "zec-1", args: args{ packedTx: testTxPacked1, - parser: &ZCashBlockParser{}, + parser: &ZCashParser{}, }, want: &testTx1, want1: 292272, @@ -159,7 +159,7 @@ func TestUnpackTx(t *testing.T) { name: "zec-2", args: args{ packedTx: testTxPacked2, - parser: &ZCashBlockParser{}, + parser: &ZCashParser{}, }, want: &testTx2, want1: 292217, diff --git a/bchain/coins/zec/zcashrpc.go b/bchain/coins/zec/zcashrpc.go index ec20eb1e..3f346340 100644 --- a/bchain/coins/zec/zcashrpc.go +++ b/bchain/coins/zec/zcashrpc.go @@ -26,7 +26,7 @@ func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp func (z *ZCashRPC) Initialize() error { z.Mempool = bchain.NewUTXOMempool(z) - z.Parser = &ZCashBlockParser{} + z.Parser = &ZCashParser{} z.Testnet = false z.Network = "livenet" diff --git a/bchain/types.go b/bchain/types.go index 5fa9712b..8e2a3d1b 100644 --- a/bchain/types.go +++ b/bchain/types.go @@ -100,6 +100,7 @@ func (e *RPCError) Error() string { return fmt.Sprintf("%d: %s", e.Code, e.Message) } +// BlockChain defines common interface to block chain daemon type BlockChain interface { // life-cycle methods Initialize() error @@ -127,6 +128,7 @@ type BlockChain interface { GetChainParser() BlockChainParser } +// BlockChainParser defines common interface to parsing and conversions of block chain data type BlockChainParser interface { // self description // UTXO chains need "inputs" column in db, that map transactions to transactions that spend them @@ -139,9 +141,14 @@ type BlockChainParser interface { AddressToOutputScript(address string) ([]byte, error) OutputScriptToAddresses(script []byte) ([]string, error) // transactions + PackedTxidLen() int + PackTxid(txid string) ([]byte, error) + UnpackTxid(buf []byte) (string, error) ParseTx(b []byte) (*Tx, error) PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error) UnpackTx(buf []byte) (*Tx, uint32, error) // blocks + PackBlockHash(hash string) ([]byte, error) + UnpackBlockHash(buf []byte) (string, error) ParseBlock(b []byte) (*Block, error) } diff --git a/db/rocksdb.go b/db/rocksdb.go index ac84e00d..959fd498 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -167,7 +167,7 @@ func (d *RocksDB) GetTransactions(address string, lower uint32, higher uint32, f if bytes.Compare(key, kstop) > 0 { break } - outpoints, err := unpackOutputValue(val) + outpoints, err := d.unpackOutputValue(val) if err != nil { return err } @@ -268,7 +268,7 @@ func (d *RocksDB) addAddrIDToRecords(op int, wb *gorocksdb.WriteBatch, records m }) if op == opDelete { // remove transactions from cache - b, err := packTxid(txid) + b, err := d.chainParser.PackTxid(txid) if err != nil { return err } @@ -324,7 +324,7 @@ func (d *RocksDB) writeOutputs(wb *gorocksdb.WriteBatch, block *bchain.Block, op switch op { case opInsert: - val, err := packOutputValue(outpoints) + val, err := d.packOutputValue(outpoints) if err != nil { glog.Warningf("rocksdb: packOutputValue: %v", err) continue @@ -346,10 +346,10 @@ func packOutputKey(outputScript []byte, height uint32) ([]byte, error) { return buf, nil } -func packOutputValue(outpoints []outpoint) ([]byte, error) { +func (d *RocksDB) packOutputValue(outpoints []outpoint) ([]byte, error) { buf := make([]byte, 0) for _, o := range outpoints { - btxid, err := packTxid(o.txid) + btxid, err := d.chainParser.PackTxid(o.txid) if err != nil { return nil, err } @@ -360,14 +360,15 @@ func packOutputValue(outpoints []outpoint) ([]byte, error) { return buf, nil } -func unpackOutputValue(buf []byte) ([]outpoint, error) { +func (d *RocksDB) unpackOutputValue(buf []byte) ([]outpoint, error) { + txidUnpackedLen := d.chainParser.PackedTxidLen() outpoints := make([]outpoint, 0) for i := 0; i < len(buf); { - txid, err := unpackTxid(buf[i : i+txIdUnpackedLen]) + txid, err := d.chainParser.UnpackTxid(buf[i : i+txidUnpackedLen]) if err != nil { return nil, err } - i += txIdUnpackedLen + i += txidUnpackedLen vout, voutLen := unpackVarint(buf[i:]) i += voutLen outpoints = append(outpoints, outpoint{ @@ -390,11 +391,11 @@ func (d *RocksDB) writeInputs( if input.Coinbase != "" { continue } - key, err := packOutpoint(input.Txid, int32(input.Vout)) + key, err := d.packOutpoint(input.Txid, int32(input.Vout)) if err != nil { return err } - val, err := packOutpoint(tx.Txid, int32(i)) + val, err := d.packOutpoint(tx.Txid, int32(i)) if err != nil { return err } @@ -409,8 +410,8 @@ func (d *RocksDB) writeInputs( return nil } -func packOutpoint(txid string, vout int32) ([]byte, error) { - btxid, err := packTxid(txid) +func (d *RocksDB) packOutpoint(txid string, vout int32) ([]byte, error) { + btxid, err := d.chainParser.PackTxid(txid) if err != nil { return nil, err } @@ -421,10 +422,11 @@ func packOutpoint(txid string, vout int32) ([]byte, error) { return buf, nil } -func unpackOutpoint(buf []byte) (string, int32, int) { - txid, _ := unpackTxid(buf[:txIdUnpackedLen]) - vout, o := unpackVarint(buf[txIdUnpackedLen:]) - return txid, vout, txIdUnpackedLen + o +func (d *RocksDB) unpackOutpoint(buf []byte) (string, int32, int) { + txidUnpackedLen := d.chainParser.PackedTxidLen() + txid, _ := d.chainParser.UnpackTxid(buf[:txidUnpackedLen]) + vout, o := unpackVarint(buf[txidUnpackedLen:]) + return txid, vout, txidUnpackedLen + o } // Block index @@ -435,7 +437,7 @@ func (d *RocksDB) GetBestBlock() (uint32, string, error) { defer it.Close() if it.SeekToLast(); it.Valid() { bestHeight := unpackUint(it.Key().Data()) - val, err := unpackBlockValue(it.Value().Data()) + val, err := d.chainParser.UnpackBlockHash(it.Value().Data()) if glog.V(1) { glog.Infof("rocksdb: bestblock %d %s", bestHeight, val) } @@ -452,12 +454,12 @@ func (d *RocksDB) GetBlockHash(height uint32) (string, error) { return "", err } defer val.Free() - return unpackBlockValue(val.Data()) + return d.chainParser.UnpackBlockHash(val.Data()) } // GetSpentOutput returns output which is spent by input tx func (d *RocksDB) GetSpentOutput(txid string, i int32) (string, int32, error) { - b, err := packOutpoint(txid, i) + b, err := d.packOutpoint(txid, i) if err != nil { return "", 0, err } @@ -466,7 +468,7 @@ func (d *RocksDB) GetSpentOutput(txid string, i int32) (string, int32, error) { return "", 0, err } defer val.Free() - p, err := unpackOutputValue(val.Data()) + p, err := d.unpackOutputValue(val.Data()) if err != nil { return "", 0, err } @@ -488,7 +490,7 @@ func (d *RocksDB) writeHeight( switch op { case opInsert: - val, err := packBlockValue(block.Hash) + val, err := d.chainParser.PackBlockHash(block.Hash) if err != nil { return err } @@ -551,13 +553,13 @@ func (d *RocksDB) DisconnectBlocksFullScan(lower uint32, higher uint32) error { glog.Info("output ", hex.EncodeToString(outputKeys[i])) } wb.DeleteCF(d.cfh[cfOutputs], outputKeys[i]) - outpoints, err := unpackOutputValue(outputValues[i]) + outpoints, err := d.unpackOutputValue(outputValues[i]) if err != nil { return err } for _, o := range outpoints { // delete from inputs - boutpoint, err := packOutpoint(o.txid, o.vout) + boutpoint, err := d.packOutpoint(o.txid, o.vout) if err != nil { return err } @@ -566,7 +568,7 @@ func (d *RocksDB) DisconnectBlocksFullScan(lower uint32, higher uint32) error { } wb.DeleteCF(d.cfh[cfInputs], boutpoint) // delete from txCache - b, err := packTxid(o.txid) + b, err := d.chainParser.PackTxid(o.txid) if err != nil { return err } @@ -609,7 +611,7 @@ func (d *RocksDB) DatabaseSizeOnDisk() int64 { // GetTx returns transaction stored in db and height of the block containing it func (d *RocksDB) GetTx(txid string) (*bchain.Tx, uint32, error) { - key, err := packTxid(txid) + key, err := d.chainParser.PackTxid(txid) if err != nil { return nil, 0, err } @@ -627,7 +629,7 @@ func (d *RocksDB) GetTx(txid string) (*bchain.Tx, uint32, error) { // PutTx stores transactions in db func (d *RocksDB) PutTx(tx *bchain.Tx, height uint32, blockTime int64) error { - key, err := packTxid(tx.Txid) + key, err := d.chainParser.PackTxid(tx.Txid) if err != nil { return nil } @@ -640,7 +642,7 @@ func (d *RocksDB) PutTx(tx *bchain.Tx, height uint32, blockTime int64) error { // DeleteTx removes transactions from db func (d *RocksDB) DeleteTx(txid string) error { - key, err := packTxid(txid) + key, err := d.chainParser.PackTxid(txid) if err != nil { return nil } @@ -649,9 +651,6 @@ func (d *RocksDB) DeleteTx(txid string) error { // Helpers -// TODO - this may be coin specific, refactor -const txIdUnpackedLen = 32 - var ErrInvalidAddress = errors.New("invalid address") func packUint(i uint32) []byte { @@ -695,19 +694,3 @@ func unpackVarint64(buf []byte) (int64, int) { i, ofs := vlq.Int(buf) return i, ofs } - -func packTxid(txid string) ([]byte, error) { - return hex.DecodeString(txid) -} - -func unpackTxid(buf []byte) (string, error) { - return hex.EncodeToString(buf), nil -} - -func packBlockValue(hash string) ([]byte, error) { - return hex.DecodeString(hash) -} - -func unpackBlockValue(buf []byte) (string, error) { - return hex.EncodeToString(buf), nil -}