Move packing/unpacking of Txid and Block Hash to coin specific code

This commit is contained in:
Martin Boehm 2018-04-08 11:24:29 +02:00
parent 8a8952d103
commit a75376706e
9 changed files with 170 additions and 88 deletions

View File

@ -14,13 +14,12 @@ import (
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
) )
// bitcoinwire parsing // BitcoinParser handle
type BitcoinParser struct {
type BitcoinBlockParser struct {
Params *chaincfg.Params 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 regression test Bitcoin network, the test Bitcoin network and
// the simulation test Bitcoin network, in this order // the simulation test Bitcoin network, in this order
func GetChainParams(chain string) *chaincfg.Params { func GetChainParams(chain string) *chaincfg.Params {
@ -33,18 +32,18 @@ func GetChainParams(chain string) *chaincfg.Params {
return &chaincfg.MainNetParams return &chaincfg.MainNetParams
} }
// GetAddrIDFromAddress returns internal address representation of given transaction output // GetAddrIDFromVout returns internal address representation of given transaction output
func (p *BitcoinBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { func (p *BitcoinParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) {
return hex.DecodeString(output.ScriptPubKey.Hex) return hex.DecodeString(output.ScriptPubKey.Hex)
} }
// GetAddrIDFromAddress returns internal address representation of given address // 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) return p.AddressToOutputScript(address)
} }
// AddressToOutputScript converts bitcoin address to ScriptPubKey // 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) da, err := btcutil.DecodeAddress(address, p.Params)
if err != nil { if err != nil {
return nil, err return nil, err
@ -57,7 +56,7 @@ func (p *BitcoinBlockParser) AddressToOutputScript(address string) ([]byte, erro
} }
// OutputScriptToAddresses converts ScriptPubKey to bitcoin addresses // 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) _, addresses, _, err := txscript.ExtractPkScriptAddrs(script, p.Params)
if err != nil { if err != nil {
return nil, err return nil, err
@ -69,7 +68,7 @@ func (p *BitcoinBlockParser) OutputScriptToAddresses(script []byte) ([]string, e
return rv, nil 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)) vin := make([]bchain.Vin, len(t.TxIn))
for i, in := range t.TxIn { for i, in := range t.TxIn {
if blockchain.IsCoinBaseTx(t) { 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 // 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{} t := wire.MsgTx{}
r := bytes.NewReader(b) r := bytes.NewReader(b)
if err := t.Deserialize(r); err != nil { 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 // 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{} w := wire.MsgBlock{}
r := bytes.NewReader(b) r := bytes.NewReader(b)
@ -152,7 +151,7 @@ func (p *BitcoinBlockParser) ParseBlock(b []byte) (*bchain.Block, error) {
} }
// PackTx packs transaction to byte array // 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) buf := make([]byte, 4+vlq.MaxLen64+len(tx.Hex)/2)
binary.BigEndian.PutUint32(buf[0:4], height) binary.BigEndian.PutUint32(buf[0:4], height)
vl := vlq.PutInt(buf[4:4+vlq.MaxLen64], blockTime) 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 // 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) height := binary.BigEndian.Uint32(buf)
bt, l := vlq.Int(buf[4:]) bt, l := vlq.Int(buf[4:])
tx, err := p.ParseTx(buf[4+l:]) 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 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 return true
} }

View File

@ -42,7 +42,7 @@ func TestAddressToOutputScript(t *testing.T) {
wantErr: false, wantErr: false,
}, },
} }
parser := &BitcoinBlockParser{Params: GetChainParams("main")} parser := &BitcoinParser{Params: GetChainParams("main")}
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -94,7 +94,7 @@ func TestOutputScriptToAddresses(t *testing.T) {
wantErr: false, wantErr: false,
}, },
} }
parser := &BitcoinBlockParser{Params: GetChainParams("main")} parser := &BitcoinParser{Params: GetChainParams("main")}
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.script) b, _ := hex.DecodeString(tt.args.script)
@ -185,7 +185,7 @@ func Test_PackTx(t *testing.T) {
tx bchain.Tx tx bchain.Tx
height uint32 height uint32
blockTime int64 blockTime int64
parser *BitcoinBlockParser parser *BitcoinParser
} }
tests := []struct { tests := []struct {
name string name string
@ -199,7 +199,7 @@ func Test_PackTx(t *testing.T) {
tx: testTx1, tx: testTx1,
height: 123456, height: 123456,
blockTime: 1519053802, blockTime: 1519053802,
parser: &BitcoinBlockParser{Params: GetChainParams("main")}, parser: &BitcoinParser{Params: GetChainParams("main")},
}, },
want: testTxPacked1, want: testTxPacked1,
wantErr: false, wantErr: false,
@ -210,7 +210,7 @@ func Test_PackTx(t *testing.T) {
tx: testTx2, tx: testTx2,
height: 510234, height: 510234,
blockTime: 1235678901, blockTime: 1235678901,
parser: &BitcoinBlockParser{Params: GetChainParams("test")}, parser: &BitcoinParser{Params: GetChainParams("test")},
}, },
want: testTxPacked2, want: testTxPacked2,
wantErr: false, wantErr: false,
@ -234,7 +234,7 @@ func Test_PackTx(t *testing.T) {
func Test_UnpackTx(t *testing.T) { func Test_UnpackTx(t *testing.T) {
type args struct { type args struct {
packedTx string packedTx string
parser *BitcoinBlockParser parser *BitcoinParser
} }
tests := []struct { tests := []struct {
name string name string
@ -247,7 +247,7 @@ func Test_UnpackTx(t *testing.T) {
name: "btc-1", name: "btc-1",
args: args{ args: args{
packedTx: testTxPacked1, packedTx: testTxPacked1,
parser: &BitcoinBlockParser{Params: GetChainParams("main")}, parser: &BitcoinParser{Params: GetChainParams("main")},
}, },
want: &testTx1, want: &testTx1,
want1: 123456, want1: 123456,
@ -257,7 +257,7 @@ func Test_UnpackTx(t *testing.T) {
name: "testnet-1", name: "testnet-1",
args: args{ args: args{
packedTx: testTxPacked2, packedTx: testTxPacked2,
parser: &BitcoinBlockParser{Params: GetChainParams("test")}, parser: &BitcoinParser{Params: GetChainParams("test")},
}, },
want: &testTx2, want: &testTx2,
want1: 510234, want1: 510234,

View File

@ -83,7 +83,7 @@ func (b *BitcoinRPC) Initialize() error {
params := GetChainParams(chainName) params := GetChainParams(chainName)
// always create parser // always create parser
b.Parser = &BitcoinBlockParser{ b.Parser = &BitcoinParser{
Params: params, Params: params,
} }

View File

@ -98,9 +98,11 @@ func ethTxToTx(tx *rpcTransaction, blocktime int64, confirmations uint32) (*bcha
}, nil }, nil
} }
// EthereumParser handle
type EthereumParser struct { type EthereumParser struct {
} }
// GetAddrIDFromVout returns internal address representation of given transaction output
func (p *EthereumParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { func (p *EthereumParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) {
if len(output.ScriptPubKey.Addresses) != 1 { if len(output.ScriptPubKey.Addresses) != 1 {
return nil, bchain.ErrAddressMissing return nil, bchain.ErrAddressMissing
@ -108,6 +110,7 @@ func (p *EthereumParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error)
return p.GetAddrIDFromAddress(output.ScriptPubKey.Addresses[0]) return p.GetAddrIDFromAddress(output.ScriptPubKey.Addresses[0])
} }
// GetAddrIDFromAddress returns internal address representation of given address
func (p *EthereumParser) GetAddrIDFromAddress(address string) ([]byte, error) { func (p *EthereumParser) GetAddrIDFromAddress(address string) ([]byte, error) {
// github.com/ethereum/go-ethereum/common.HexToAddress does not handle address errors, using own decoding // github.com/ethereum/go-ethereum/common.HexToAddress does not handle address errors, using own decoding
if len(address) > 1 { if len(address) > 1 {
@ -126,18 +129,22 @@ func (p *EthereumParser) GetAddrIDFromAddress(address string) ([]byte, error) {
return hex.DecodeString(address) return hex.DecodeString(address)
} }
// AddressToOutputScript converts address to ScriptPubKey - currently not implemented
func (p *EthereumParser) AddressToOutputScript(address string) ([]byte, error) { func (p *EthereumParser) AddressToOutputScript(address string) ([]byte, error) {
return nil, errors.New("AddressToOutputScript: not implemented") return nil, errors.New("AddressToOutputScript: not implemented")
} }
// OutputScriptToAddresses converts ScriptPubKey to addresses - currently not implemented
func (p *EthereumParser) OutputScriptToAddresses(script []byte) ([]string, error) { func (p *EthereumParser) OutputScriptToAddresses(script []byte) ([]string, error) {
return nil, errors.New("OutputScriptToAddresses: not implemented") 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) { func (p *EthereumParser) ParseTx(b []byte) (*bchain.Tx, error) {
return nil, errors.New("ParseTx: not implemented") 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) { func (p *EthereumParser) ParseBlock(b []byte) (*bchain.Block, error) {
return nil, errors.New("ParseBlock: not implemented") return nil, errors.New("ParseBlock: not implemented")
} }
@ -164,6 +171,7 @@ func hexEncodeBig(b []byte) string {
return hexutil.EncodeBig(&i) return hexutil.EncodeBig(&i)
} }
// PackTx packs transaction to byte array
func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
b, err := hex.DecodeString(tx.Hex) b, err := hex.DecodeString(tx.Hex)
if err != nil { if err != nil {
@ -219,6 +227,7 @@ func (p *EthereumParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) (
return proto.Marshal(pt) return proto.Marshal(pt)
} }
// UnpackTx unpacks transaction from byte array
func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
var pt ProtoTransaction var pt ProtoTransaction
err := proto.Unmarshal(buf, &pt) err := proto.Unmarshal(buf, &pt)
@ -247,6 +256,32 @@ func (p *EthereumParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
return tx, pt.BlockNumber, nil 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 { func (p *EthereumParser) IsUTXOChain() bool {
return false return false
} }

View File

@ -5,13 +5,15 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/gob" "encoding/gob"
"encoding/hex"
"errors" "errors"
) )
type ZCashBlockParser struct{} // ZCashParser handle
type ZCashParser struct{}
// GetAddrIDFromAddress returns internal address representation of given transaction output // GetAddrIDFromVout returns internal address representation of given transaction output
func (p *ZCashBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) { func (p *ZCashParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error) {
if len(output.ScriptPubKey.Addresses) != 1 { if len(output.ScriptPubKey.Addresses) != 1 {
return nil, nil return nil, nil
} }
@ -20,13 +22,13 @@ func (p *ZCashBlockParser) GetAddrIDFromVout(output *bchain.Vout) ([]byte, error
} }
// GetAddrIDFromAddress returns internal address representation of given address // 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) hash, _, err := CheckDecode(address)
return hash, err return hash, err
} }
// PackTx packs transaction to byte array // 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) buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, height) binary.BigEndian.PutUint32(buf, height)
buf, err := encodeTx(buf, tx) buf, err := encodeTx(buf, tx)
@ -44,7 +46,7 @@ func encodeTx(b []byte, tx *bchain.Tx) ([]byte, error) {
} }
// UnpackTx unpacks transaction from byte array // 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) height := binary.BigEndian.Uint32(buf)
tx, err := decodeTx(buf[4:]) tx, err := decodeTx(buf[4:])
if err != nil { if err != nil {
@ -63,22 +65,52 @@ func decodeTx(buf []byte) (*bchain.Tx, error) {
return tx, nil 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") 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") 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") 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") 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 return true
} }

View File

@ -87,7 +87,7 @@ func TestPackTx(t *testing.T) {
tx bchain.Tx tx bchain.Tx
height uint32 height uint32
blockTime int64 blockTime int64
parser *ZCashBlockParser parser *ZCashParser
} }
tests := []struct { tests := []struct {
name string name string
@ -101,7 +101,7 @@ func TestPackTx(t *testing.T) {
tx: testTx1, tx: testTx1,
height: 292272, height: 292272,
blockTime: 1521645728, blockTime: 1521645728,
parser: &ZCashBlockParser{}, parser: &ZCashParser{},
}, },
want: testTxPacked1, want: testTxPacked1,
wantErr: false, wantErr: false,
@ -112,7 +112,7 @@ func TestPackTx(t *testing.T) {
tx: testTx2, tx: testTx2,
height: 292217, height: 292217,
blockTime: 1521637604, blockTime: 1521637604,
parser: &ZCashBlockParser{}, parser: &ZCashParser{},
}, },
want: testTxPacked2, want: testTxPacked2,
wantErr: false, wantErr: false,
@ -136,7 +136,7 @@ func TestPackTx(t *testing.T) {
func TestUnpackTx(t *testing.T) { func TestUnpackTx(t *testing.T) {
type args struct { type args struct {
packedTx string packedTx string
parser *ZCashBlockParser parser *ZCashParser
} }
tests := []struct { tests := []struct {
name string name string
@ -149,7 +149,7 @@ func TestUnpackTx(t *testing.T) {
name: "zec-1", name: "zec-1",
args: args{ args: args{
packedTx: testTxPacked1, packedTx: testTxPacked1,
parser: &ZCashBlockParser{}, parser: &ZCashParser{},
}, },
want: &testTx1, want: &testTx1,
want1: 292272, want1: 292272,
@ -159,7 +159,7 @@ func TestUnpackTx(t *testing.T) {
name: "zec-2", name: "zec-2",
args: args{ args: args{
packedTx: testTxPacked2, packedTx: testTxPacked2,
parser: &ZCashBlockParser{}, parser: &ZCashParser{},
}, },
want: &testTx2, want: &testTx2,
want1: 292217, want1: 292217,

View File

@ -26,7 +26,7 @@ func NewZCashRPC(config json.RawMessage, pushHandler func(bchain.NotificationTyp
func (z *ZCashRPC) Initialize() error { func (z *ZCashRPC) Initialize() error {
z.Mempool = bchain.NewUTXOMempool(z) z.Mempool = bchain.NewUTXOMempool(z)
z.Parser = &ZCashBlockParser{} z.Parser = &ZCashParser{}
z.Testnet = false z.Testnet = false
z.Network = "livenet" z.Network = "livenet"

View File

@ -100,6 +100,7 @@ func (e *RPCError) Error() string {
return fmt.Sprintf("%d: %s", e.Code, e.Message) return fmt.Sprintf("%d: %s", e.Code, e.Message)
} }
// BlockChain defines common interface to block chain daemon
type BlockChain interface { type BlockChain interface {
// life-cycle methods // life-cycle methods
Initialize() error Initialize() error
@ -127,6 +128,7 @@ type BlockChain interface {
GetChainParser() BlockChainParser GetChainParser() BlockChainParser
} }
// BlockChainParser defines common interface to parsing and conversions of block chain data
type BlockChainParser interface { type BlockChainParser interface {
// self description // self description
// UTXO chains need "inputs" column in db, that map transactions to transactions that spend them // 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) AddressToOutputScript(address string) ([]byte, error)
OutputScriptToAddresses(script []byte) ([]string, error) OutputScriptToAddresses(script []byte) ([]string, error)
// transactions // transactions
PackedTxidLen() int
PackTxid(txid string) ([]byte, error)
UnpackTxid(buf []byte) (string, error)
ParseTx(b []byte) (*Tx, error) ParseTx(b []byte) (*Tx, error)
PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error) PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error)
UnpackTx(buf []byte) (*Tx, uint32, error) UnpackTx(buf []byte) (*Tx, uint32, error)
// blocks // blocks
PackBlockHash(hash string) ([]byte, error)
UnpackBlockHash(buf []byte) (string, error)
ParseBlock(b []byte) (*Block, error) ParseBlock(b []byte) (*Block, error)
} }

View File

@ -167,7 +167,7 @@ func (d *RocksDB) GetTransactions(address string, lower uint32, higher uint32, f
if bytes.Compare(key, kstop) > 0 { if bytes.Compare(key, kstop) > 0 {
break break
} }
outpoints, err := unpackOutputValue(val) outpoints, err := d.unpackOutputValue(val)
if err != nil { if err != nil {
return err return err
} }
@ -268,7 +268,7 @@ func (d *RocksDB) addAddrIDToRecords(op int, wb *gorocksdb.WriteBatch, records m
}) })
if op == opDelete { if op == opDelete {
// remove transactions from cache // remove transactions from cache
b, err := packTxid(txid) b, err := d.chainParser.PackTxid(txid)
if err != nil { if err != nil {
return err return err
} }
@ -324,7 +324,7 @@ func (d *RocksDB) writeOutputs(wb *gorocksdb.WriteBatch, block *bchain.Block, op
switch op { switch op {
case opInsert: case opInsert:
val, err := packOutputValue(outpoints) val, err := d.packOutputValue(outpoints)
if err != nil { if err != nil {
glog.Warningf("rocksdb: packOutputValue: %v", err) glog.Warningf("rocksdb: packOutputValue: %v", err)
continue continue
@ -346,10 +346,10 @@ func packOutputKey(outputScript []byte, height uint32) ([]byte, error) {
return buf, nil return buf, nil
} }
func packOutputValue(outpoints []outpoint) ([]byte, error) { func (d *RocksDB) packOutputValue(outpoints []outpoint) ([]byte, error) {
buf := make([]byte, 0) buf := make([]byte, 0)
for _, o := range outpoints { for _, o := range outpoints {
btxid, err := packTxid(o.txid) btxid, err := d.chainParser.PackTxid(o.txid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -360,14 +360,15 @@ func packOutputValue(outpoints []outpoint) ([]byte, error) {
return buf, nil 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) outpoints := make([]outpoint, 0)
for i := 0; i < len(buf); { 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 { if err != nil {
return nil, err return nil, err
} }
i += txIdUnpackedLen i += txidUnpackedLen
vout, voutLen := unpackVarint(buf[i:]) vout, voutLen := unpackVarint(buf[i:])
i += voutLen i += voutLen
outpoints = append(outpoints, outpoint{ outpoints = append(outpoints, outpoint{
@ -390,11 +391,11 @@ func (d *RocksDB) writeInputs(
if input.Coinbase != "" { if input.Coinbase != "" {
continue continue
} }
key, err := packOutpoint(input.Txid, int32(input.Vout)) key, err := d.packOutpoint(input.Txid, int32(input.Vout))
if err != nil { if err != nil {
return err return err
} }
val, err := packOutpoint(tx.Txid, int32(i)) val, err := d.packOutpoint(tx.Txid, int32(i))
if err != nil { if err != nil {
return err return err
} }
@ -409,8 +410,8 @@ func (d *RocksDB) writeInputs(
return nil return nil
} }
func packOutpoint(txid string, vout int32) ([]byte, error) { func (d *RocksDB) packOutpoint(txid string, vout int32) ([]byte, error) {
btxid, err := packTxid(txid) btxid, err := d.chainParser.PackTxid(txid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -421,10 +422,11 @@ func packOutpoint(txid string, vout int32) ([]byte, error) {
return buf, nil return buf, nil
} }
func unpackOutpoint(buf []byte) (string, int32, int) { func (d *RocksDB) unpackOutpoint(buf []byte) (string, int32, int) {
txid, _ := unpackTxid(buf[:txIdUnpackedLen]) txidUnpackedLen := d.chainParser.PackedTxidLen()
vout, o := unpackVarint(buf[txIdUnpackedLen:]) txid, _ := d.chainParser.UnpackTxid(buf[:txidUnpackedLen])
return txid, vout, txIdUnpackedLen + o vout, o := unpackVarint(buf[txidUnpackedLen:])
return txid, vout, txidUnpackedLen + o
} }
// Block index // Block index
@ -435,7 +437,7 @@ func (d *RocksDB) GetBestBlock() (uint32, string, error) {
defer it.Close() defer it.Close()
if it.SeekToLast(); it.Valid() { if it.SeekToLast(); it.Valid() {
bestHeight := unpackUint(it.Key().Data()) bestHeight := unpackUint(it.Key().Data())
val, err := unpackBlockValue(it.Value().Data()) val, err := d.chainParser.UnpackBlockHash(it.Value().Data())
if glog.V(1) { if glog.V(1) {
glog.Infof("rocksdb: bestblock %d %s", bestHeight, val) glog.Infof("rocksdb: bestblock %d %s", bestHeight, val)
} }
@ -452,12 +454,12 @@ func (d *RocksDB) GetBlockHash(height uint32) (string, error) {
return "", err return "", err
} }
defer val.Free() defer val.Free()
return unpackBlockValue(val.Data()) return d.chainParser.UnpackBlockHash(val.Data())
} }
// GetSpentOutput returns output which is spent by input tx // GetSpentOutput returns output which is spent by input tx
func (d *RocksDB) GetSpentOutput(txid string, i int32) (string, int32, error) { 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 { if err != nil {
return "", 0, err return "", 0, err
} }
@ -466,7 +468,7 @@ func (d *RocksDB) GetSpentOutput(txid string, i int32) (string, int32, error) {
return "", 0, err return "", 0, err
} }
defer val.Free() defer val.Free()
p, err := unpackOutputValue(val.Data()) p, err := d.unpackOutputValue(val.Data())
if err != nil { if err != nil {
return "", 0, err return "", 0, err
} }
@ -488,7 +490,7 @@ func (d *RocksDB) writeHeight(
switch op { switch op {
case opInsert: case opInsert:
val, err := packBlockValue(block.Hash) val, err := d.chainParser.PackBlockHash(block.Hash)
if err != nil { if err != nil {
return err return err
} }
@ -551,13 +553,13 @@ func (d *RocksDB) DisconnectBlocksFullScan(lower uint32, higher uint32) error {
glog.Info("output ", hex.EncodeToString(outputKeys[i])) glog.Info("output ", hex.EncodeToString(outputKeys[i]))
} }
wb.DeleteCF(d.cfh[cfOutputs], outputKeys[i]) wb.DeleteCF(d.cfh[cfOutputs], outputKeys[i])
outpoints, err := unpackOutputValue(outputValues[i]) outpoints, err := d.unpackOutputValue(outputValues[i])
if err != nil { if err != nil {
return err return err
} }
for _, o := range outpoints { for _, o := range outpoints {
// delete from inputs // delete from inputs
boutpoint, err := packOutpoint(o.txid, o.vout) boutpoint, err := d.packOutpoint(o.txid, o.vout)
if err != nil { if err != nil {
return err return err
} }
@ -566,7 +568,7 @@ func (d *RocksDB) DisconnectBlocksFullScan(lower uint32, higher uint32) error {
} }
wb.DeleteCF(d.cfh[cfInputs], boutpoint) wb.DeleteCF(d.cfh[cfInputs], boutpoint)
// delete from txCache // delete from txCache
b, err := packTxid(o.txid) b, err := d.chainParser.PackTxid(o.txid)
if err != nil { if err != nil {
return err return err
} }
@ -609,7 +611,7 @@ func (d *RocksDB) DatabaseSizeOnDisk() int64 {
// GetTx returns transaction stored in db and height of the block containing it // GetTx returns transaction stored in db and height of the block containing it
func (d *RocksDB) GetTx(txid string) (*bchain.Tx, uint32, error) { func (d *RocksDB) GetTx(txid string) (*bchain.Tx, uint32, error) {
key, err := packTxid(txid) key, err := d.chainParser.PackTxid(txid)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
@ -627,7 +629,7 @@ func (d *RocksDB) GetTx(txid string) (*bchain.Tx, uint32, error) {
// PutTx stores transactions in db // PutTx stores transactions in db
func (d *RocksDB) PutTx(tx *bchain.Tx, height uint32, blockTime int64) error { 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 { if err != nil {
return nil return nil
} }
@ -640,7 +642,7 @@ func (d *RocksDB) PutTx(tx *bchain.Tx, height uint32, blockTime int64) error {
// DeleteTx removes transactions from db // DeleteTx removes transactions from db
func (d *RocksDB) DeleteTx(txid string) error { func (d *RocksDB) DeleteTx(txid string) error {
key, err := packTxid(txid) key, err := d.chainParser.PackTxid(txid)
if err != nil { if err != nil {
return nil return nil
} }
@ -649,9 +651,6 @@ func (d *RocksDB) DeleteTx(txid string) error {
// Helpers // Helpers
// TODO - this may be coin specific, refactor
const txIdUnpackedLen = 32
var ErrInvalidAddress = errors.New("invalid address") var ErrInvalidAddress = errors.New("invalid address")
func packUint(i uint32) []byte { func packUint(i uint32) []byte {
@ -695,19 +694,3 @@ func unpackVarint64(buf []byte) (int64, int) {
i, ofs := vlq.Int(buf) i, ofs := vlq.Int(buf)
return i, ofs 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
}