blockbook/bchain/coins/xzc/zcoinparser_test.go
2019-02-27 14:06:09 +01:00

623 lines
16 KiB
Go

// +build unittest
package xzc
import (
"bytes"
"encoding/hex"
"encoding/json"
"io/ioutil"
"math/big"
"os"
"reflect"
"strings"
"testing"
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"github.com/martinboehm/btcutil/chaincfg"
)
var (
testTx1, testTx2, testTx3, testTx4 bchain.Tx
testTxPacked1, testTxPacked2, testTxPacked3, testTxPacked4 string
rawBlock1, rawBlock2 string
jsonTx json.RawMessage
)
func readHexs(path string) []string {
raw, err := ioutil.ReadFile(path)
if err != nil {
panic(err)
}
rawStr := string(raw)
raws := strings.Split(rawStr, "\n")
return raws
}
func init() {
rawBlocks := readHexs("./testdata/rawblock.hex")
rawBlock1 = rawBlocks[0]
rawBlock2 = rawBlocks[1]
hextxs := readHexs("./testdata/txs.hex")
rawTestTx1 := hextxs[0]
rawTestTx2 := hextxs[1]
rawTestTx3 := hextxs[2]
rawTestTx4 := hextxs[3]
rawSpendHex := readHexs("./testdata/rawspend.hex")[0]
rawSpendTx, err := ioutil.ReadFile("./testdata/spendtx.json")
if err != nil {
panic(err)
}
jsonTx = json.RawMessage(rawSpendTx)
testTxPackeds := readHexs("./testdata/packedtxs.hex")
testTxPacked1 = testTxPackeds[0]
testTxPacked2 = testTxPackeds[1]
testTxPacked3 = testTxPackeds[2]
testTxPacked4 = testTxPackeds[3]
testTx1 = bchain.Tx{
Hex: rawTestTx1,
Blocktime: 1533980594,
Time: 1533980594,
Txid: "9d9e759dd970d86df9e105a7d4f671543bc16a03b6c5d2b48895f2a00aa7dd23",
LockTime: 0,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: "47304402205b7d9c9aae790b69017651e10134735928df3b4a4a2feacc9568eb4fa133ed5902203f21a399385ce29dd79831ea34aa535612aa4314c5bd0b002bbbc9bcd2de1436012102b8d462740c99032a00083ac7028879acec244849e54ad0a04ea87f632f54b1d2",
},
Txid: "463a2d66b04636a014da35724909425f3403d9d786dd4f79780de50d47b18716",
Vout: 1,
Sequence: 4294967294,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(18188266638),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "c10280004c80f767f3ee79953c67a7ed386dcccf1243619eb4bbbe414a3982dd94a83c1b69ac52d6ab3b653a3e05c4e4516c8dfe1e58ada40461bc5835a4a0d0387a51c29ac11b72ae25bbcdef745f50ad08f08b3e9bc2c31a35444398a490e65ac090e9f341f1abdebe47e57e8237ac25d098e951b4164a35caea29f30acb50b12e4425df28",
},
},
{
ValueSat: *big.NewInt(18188266638),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914c963f917c7f23cb4243e079db33107571b87690588ac",
Addresses: []string{
"aK5KKi8qqDbspcXFfDjx8UBGMouhYbYZVp",
},
},
},
},
}
testTx2 = bchain.Tx{
Hex: rawTestTx2,
Blocktime: 1481277009,
Time: 1481277009,
Txid: "3d721fdce2855e2b4a54b74a26edd58a7262e1f195b5acaaae7832be6e0b3d32",
LockTime: 0,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: rawSpendHex,
},
Txid: "0000000000000000000000000000000000000000000000000000000000000000",
Vout: 4294967295,
Sequence: 2,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(5000000000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914b9e262e30df03e88ccea312652bc83ca7290c8fc88ac",
Addresses: []string{
"aHfKwzFZMiSxDuNL4jts819nh57t2yJG1h",
},
},
},
},
}
testTx3 = bchain.Tx{
Hex: rawTestTx3,
Blocktime: 1547091829,
Time: 1547091829,
Txid: "96ae951083651f141d1fb2719c76d47e5a3ad421b81905f679c0edb60f2de0ff",
LockTime: 126200,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: "483045022100bdc6b51c114617e29e28390dc9b3ad95b833ca3d1f0429ba667c58a667f9124702204ca2ed362dd9ef723ddbdcf4185b47c28b127a36f46bc4717662be863309b3e601210387e7ff08b953e3736955408fc6ebcd8aa84a04cc4b45758ea29cc2cfe1820535",
},
Txid: "448ccfd9c3f375be8701b86aff355a230dbe240334233f2ed476fcae6abd295d",
Vout: 1,
Sequence: 4294967294,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(42000000000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a91429bef7962c5c65a2f0f4f7d9ec791866c54f851688ac",
Addresses: []string{
"a4XCDQ7AnRH9opZ4h6LcG3g7ocSV2SbBmS",
},
},
},
{
ValueSat: *big.NewInt(107300000000),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914e2cee7b71c3a4637dbdfe613f19f4b4f2d070d7f88ac",
Addresses: []string{
"aMPiKHB3E1AGPi8kKLknx6j1L4JnKCGkLw",
},
},
},
},
}
testTx4 = bchain.Tx{
Hex: rawTestTx4,
Blocktime: 1533977563,
Time: 1533977563,
Txid: "914ccbdb72f593e5def15978cf5891e1384a1b85e89374fc1c440c074c6dd286",
LockTime: 0,
Vin: []bchain.Vin{
{
Coinbase: "03a1860104dba36e5b082a00077c00000000052f6d70682f",
Sequence: 0,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(2800200000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a91436e086acf6561a68ba64196e7b92b606d0b8516688ac",
Addresses: []string{
"a5idCcHN8WYxvFCeBXSXvMPrZHuBkZmqEJ",
},
},
},
{
ValueSat: *big.NewInt(1500000000),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914381a5dd1a279e8e63e67cde39ecfa61a99dd2ba288ac",
Addresses: []string{
"a5q7Ad4okSFFVh5adyqx5DT21RTxJykpUM",
},
},
},
{
ValueSat: *big.NewInt(100000000),
N: 2,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9147d9ed014fc4e603fca7c2e3f9097fb7d0fb487fc88ac",
Addresses: []string{
"aCAgTPgtYcA4EysU4UKC86EQd5cTtHtCcr",
},
},
},
{
ValueSat: *big.NewInt(100000000),
N: 3,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914bc7e5a5234db3ab82d74c396ad2b2af419b7517488ac",
Addresses: []string{
"aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD",
},
},
},
{
ValueSat: *big.NewInt(100000000),
N: 4,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914ff71b0c9c2a90c6164a50a2fb523eb54a8a6b55088ac",
Addresses: []string{
"a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3",
},
},
},
{
ValueSat: *big.NewInt(300000000),
N: 5,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9140654dd9b856f2ece1d56cb4ee5043cd9398d962c88ac",
Addresses: []string{
"a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3",
},
},
},
{
ValueSat: *big.NewInt(100000000),
N: 6,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a9140b4bfb256ef4bfa360e3b9e66e53a0bd84d196bc88ac",
Addresses: []string{
"a1kCCGddf5pMXSipLVD9hBG2MGGVNaJ15U",
},
},
},
},
}
}
func TestMain(m *testing.M) {
c := m.Run()
chaincfg.ResetParams()
os.Exit(c)
}
func TestGetAddrDesc(t *testing.T) {
type args struct {
tx bchain.Tx
parser *ZcoinParser
}
tests := []struct {
name string
args args
}{
{
name: "xzc-1",
args: args{
tx: testTx1,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
},
// FIXME: work around handle zerocoin spend as coinbase
// {
// name: "xzc-2",
// args: args{
// tx: testTx2,
// parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
// },
// },
{
name: "xzc-3",
args: args{
tx: testTx3,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for n, vout := range tt.args.tx.Vout {
got1, err := tt.args.parser.GetAddrDescFromVout(&vout)
if err != nil {
t.Errorf("getAddrDescFromVout() error = %v, vout = %d", err, n)
return
}
// normal vout
if len(vout.ScriptPubKey.Addresses) >= 1 {
got2, err := tt.args.parser.GetAddrDescFromAddress(vout.ScriptPubKey.Addresses[0])
if err != nil {
t.Errorf("getAddrDescFromAddress() error = %v, vout = %d", err, n)
return
}
if !bytes.Equal(got1, got2) {
t.Errorf("Address descriptors mismatch: got1 = %v, got2 = %v", got1, got2)
}
}
}
})
}
}
func TestGetAddrDescFromVoutForMint(t *testing.T) {
type args struct {
vout bchain.Vout
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "OP_RETURN",
args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "6a072020f1686f6a20"}}},
want: "6a072020f1686f6a20",
wantErr: false,
},
{
name: "OP_ZEROCOINMINT",
args: args{vout: bchain.Vout{ScriptPubKey: bchain.ScriptPubKey{Hex: "c10280004c80f767f3ee79953c67a7ed386dcccf1243619eb4bbbe414a3982dd94a83c1b69ac52d6ab3b653a3e05c4e4516c8dfe1e58ada40461bc5835a4a0d0387a51c29ac11b72ae25bbcdef745f50ad08f08b3e9bc2c31a35444398a490e65ac090e9f341f1abdebe47e57e8237ac25d098e951b4164a35caea29f30acb50b12e4425df28"}}},
want: "c10280004c80f767f3ee79953c67a7ed386dcccf1243619eb4bbbe414a3982dd94a83c1b69ac52d6ab3b653a3e05c4e4516c8dfe1e58ada40461bc5835a4a0d0387a51c29ac11b72ae25bbcdef745f50ad08f08b3e9bc2c31a35444398a490e65ac090e9f341f1abdebe47e57e8237ac25d098e951b4164a35caea29f30acb50b12e4425df28",
wantErr: false,
},
}
parser := NewZcoinParser(GetChainParams("main"), &btc.Configuration{})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parser.GetAddrDescFromVout(&tt.args.vout)
if (err != nil) != tt.wantErr {
t.Errorf("GetAddrDescFromVout() error = %v, wantErr %v", err, tt.wantErr)
return
}
h := hex.EncodeToString(got)
if !reflect.DeepEqual(h, tt.want) {
t.Errorf("GetAddrDescFromVout() = %v, want %v", h, tt.want)
}
})
}
}
func TestGetAddressesFromAddrDescForMint(t *testing.T) {
type args struct {
script string
}
tests := []struct {
name string
args args
want []string
want2 bool
wantErr bool
}{
{
name: "OP_RETURN hex",
args: args{script: "6a072020f1686f6a20"},
want: []string{"OP_RETURN 2020f1686f6a20"},
want2: false,
wantErr: false,
},
{
name: "OP_ZEROCOINMINT size hex",
args: args{script: "c10280004c80f767f3ee79953c67a7ed386dcccf1243619eb4bbbe414a3982dd94a83c1b69ac52d6ab3b653a3e05c4e4516c8dfe1e58ada40461bc5835a4a0d0387a51c29ac11b72ae25bbcdef745f50ad08f08b3e9bc2c31a35444398a490e65ac090e9f341f1abdebe47e57e8237ac25d098e951b4164a35caea29f30acb50b12e4425df28"},
want: []string{"Zeromint"},
want2: false,
wantErr: false,
},
}
parser := NewZcoinParser(GetChainParams("main"), &btc.Configuration{})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.script)
got, got2, err := parser.GetAddressesFromAddrDesc(b)
if (err != nil) != tt.wantErr {
t.Errorf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.want)
}
if !reflect.DeepEqual(got2, tt.want2) {
t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.want2)
}
})
}
}
func TestPackTx(t *testing.T) {
type args struct {
tx bchain.Tx
height uint32
blockTime int64
parser *ZcoinParser
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "xzc-1",
args: args{
tx: testTx1,
height: 100002,
blockTime: 1533980594,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: testTxPacked1,
wantErr: false,
},
// FIXME: work around handle zerocoin spend as coinbase
// {
// name: "xzc-2",
// args: args{
// tx: testTx2,
// height: 11002,
// blockTime: 1481277009,
// parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
// },
// want: testTxPacked2,
// wantErr: true,
// },
{
name: "xzc-3",
args: args{
tx: testTx3,
height: 126202,
blockTime: 1547091829,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: testTxPacked3,
wantErr: false,
},
{
name: "xzc-coinbase",
args: args{
tx: testTx4,
height: 100001,
blockTime: 1533977563,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: testTxPacked4,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime)
if (err != nil) != tt.wantErr {
t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
h := hex.EncodeToString(got)
if !reflect.DeepEqual(h, tt.want) {
t.Errorf("packTx() = %v, want %v", h, tt.want)
}
}
})
}
}
func TestUnpackTx(t *testing.T) {
type args struct {
packedTx string
parser *ZcoinParser
}
tests := []struct {
name string
args args
want *bchain.Tx
want1 uint32
wantErr bool
}{
{
name: "xzc-1",
args: args{
packedTx: testTxPacked1,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: &testTx1,
want1: 100002,
wantErr: false,
},
// FIXME: work around handle zerocoin spend as coinbase
// {
// name: "xzc-2",
// args: args{
// packedTx: testTxPacked2,
// parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
// },
// want: &testTx2,
// want1: 11002,
// wantErr: true,
// },
{
name: "xzc-3",
args: args{
packedTx: testTxPacked3,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: &testTx3,
want1: 126202,
wantErr: false,
},
{
name: "xzc-coinbase",
args: args{
packedTx: testTxPacked4,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: &testTx4,
want1: 100001,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.packedTx)
got, got1, err := tt.args.parser.UnpackTx(b)
if (err != nil) != tt.wantErr {
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1)
}
}
})
}
}
func TestParseBlock(t *testing.T) {
type args struct {
rawBlock string
parser *ZcoinParser
}
tests := []struct {
name string
args args
want *bchain.Block
wantTxs int
wantErr bool
}{
{
name: "normal-block",
args: args{
rawBlock: rawBlock1,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: &bchain.Block{
BlockHeader: bchain.BlockHeader{
Size: 200286,
Time: 1547120622,
},
},
wantTxs: 3,
wantErr: false,
},
{
name: "spend-block",
args: args{
rawBlock: rawBlock2,
parser: NewZcoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: &bchain.Block{
BlockHeader: bchain.BlockHeader{
Size: 25298,
Time: 1482107572,
},
},
wantTxs: 4,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.rawBlock)
got, err := tt.args.parser.ParseBlock(b)
if (err != nil) != tt.wantErr {
t.Errorf("parseBlock() error = %+v", err)
}
if got != nil {
if !reflect.DeepEqual(got.BlockHeader, tt.want.BlockHeader) {
t.Errorf("parseBlock() got = %v, want %v", got.BlockHeader, tt.want.BlockHeader)
}
if len(got.Txs) != tt.wantTxs {
t.Errorf("parseBlock() txs length got = %d, want %d", len(got.Txs), tt.wantTxs)
}
}
})
}
}