Added Zcoin support (#106)
* Add zcoin configuration * Update ports registry * Change verification_type to gpg-sha256 * Fix incorrect zcoin configurations * Change backend verification type to sha256 due to no public key for gpg-sha256 * Initializes Zcoin factory * Add zcoin parser * Finish BlockChain implementation for XZC * Implement EstimateFee for XZC * Add RPC integration tests for XZC * Add unittest for parser && fix wrong network params * Fix incorrect RPC marshaler for XZC * Add sync integration test for zcoin * Add zcoin block parser * Add more testdata for sync integration test * Remove EstimateSmartFee test for XZC due to it not supported * Refactor and cleanup XZC parser * Fix zerocoin spend vin error * Fix display zerocoin mint and spend * Support script parser for spend * Fix build errors and bugs after rebasepull/109/head
parent
b593643f63
commit
8e82b3da0f
|
@ -19,6 +19,7 @@ import (
|
|||
"blockbook/bchain/coins/namecoin"
|
||||
"blockbook/bchain/coins/pivx"
|
||||
"blockbook/bchain/coins/vertcoin"
|
||||
"blockbook/bchain/coins/xzc"
|
||||
"blockbook/bchain/coins/zec"
|
||||
"blockbook/common"
|
||||
"context"
|
||||
|
@ -64,6 +65,7 @@ func init() {
|
|||
BlockChainFactories["Groestlcoin"] = grs.NewGroestlcoinRPC
|
||||
BlockChainFactories["Groestlcoin Testnet"] = grs.NewGroestlcoinRPC
|
||||
BlockChainFactories["PIVX"] = pivx.NewPivXRPC
|
||||
BlockChainFactories["Zcoin"] = xzc.NewZcoinRPC
|
||||
BlockChainFactories["Fujicoin"] = fujicoin.NewFujicoinRPC
|
||||
}
|
||||
|
||||
|
|
|
@ -454,7 +454,7 @@ func (b *BitcoinRPC) GetChainInfo() (*bchain.ChainInfo, error) {
|
|||
return rv, nil
|
||||
}
|
||||
|
||||
func isErrBlockNotFound(err *bchain.RPCError) bool {
|
||||
func IsErrBlockNotFound(err *bchain.RPCError) bool {
|
||||
return err.Message == "Block not found" ||
|
||||
err.Message == "Block height out of range"
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ func (b *BitcoinRPC) GetBlockHash(height uint32) (string, error) {
|
|||
return "", errors.Annotatef(err, "height %v", height)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if isErrBlockNotFound(res.Error) {
|
||||
if IsErrBlockNotFound(res.Error) {
|
||||
return "", bchain.ErrBlockNotFound
|
||||
}
|
||||
return "", errors.Annotatef(res.Error, "height %v", height)
|
||||
|
@ -494,7 +494,7 @@ func (b *BitcoinRPC) GetBlockHeader(hash string) (*bchain.BlockHeader, error) {
|
|||
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if isErrBlockNotFound(res.Error) {
|
||||
if IsErrBlockNotFound(res.Error) {
|
||||
return nil, bchain.ErrBlockNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||
|
@ -548,7 +548,7 @@ func (b *BitcoinRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
|
|||
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if isErrBlockNotFound(res.Error) {
|
||||
if IsErrBlockNotFound(res.Error) {
|
||||
return nil, bchain.ErrBlockNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||
|
@ -586,7 +586,7 @@ func (b *BitcoinRPC) GetBlockRaw(hash string) ([]byte, error) {
|
|||
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if isErrBlockNotFound(res.Error) {
|
||||
if IsErrBlockNotFound(res.Error) {
|
||||
return nil, bchain.ErrBlockNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||
|
@ -608,7 +608,7 @@ func (b *BitcoinRPC) GetBlockFull(hash string) (*bchain.Block, error) {
|
|||
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if isErrBlockNotFound(res.Error) {
|
||||
if IsErrBlockNotFound(res.Error) {
|
||||
return nil, bchain.ErrBlockNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||
|
@ -633,7 +633,7 @@ func (b *BitcoinRPC) GetMempool() ([]string, error) {
|
|||
return res.Result, nil
|
||||
}
|
||||
|
||||
func isMissingTx(err *bchain.RPCError) bool {
|
||||
func IsMissingTx(err *bchain.RPCError) bool {
|
||||
if err.Code == -5 { // "No such mempool or blockchain transaction"
|
||||
return true
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ func (b *BitcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
|
|||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if isMissingTx(res.Error) {
|
||||
if IsMissingTx(res.Error) {
|
||||
return nil, bchain.ErrTxNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "txid %v", txid)
|
||||
|
@ -706,7 +706,7 @@ func (b *BitcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
|||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if isMissingTx(res.Error) {
|
||||
if IsMissingTx(res.Error) {
|
||||
return nil, bchain.ErrTxNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "txid %v", txid)
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,262 @@
|
|||
package xzc
|
||||
|
||||
import (
|
||||
"blockbook/bchain"
|
||||
"blockbook/bchain/coins/btc"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/martinboehm/btcd/chaincfg/chainhash"
|
||||
"github.com/martinboehm/btcd/wire"
|
||||
"github.com/martinboehm/btcutil/chaincfg"
|
||||
)
|
||||
|
||||
const (
|
||||
OpZeroCoinMint = 0xc1
|
||||
OpZeroCoinSpend = 0xc2
|
||||
|
||||
MainnetMagic wire.BitcoinNet = 0xe3d9fef1
|
||||
TestnetMagic wire.BitcoinNet = 0xcffcbeea
|
||||
RegtestMagic wire.BitcoinNet = 0xfabfb5da
|
||||
|
||||
GenesisBlockTime = 1414776286
|
||||
SwitchToMTPBlockHeader = 1544443200
|
||||
MTPL = 64
|
||||
|
||||
SpendTxID = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
)
|
||||
|
||||
var (
|
||||
MainNetParams chaincfg.Params
|
||||
TestNetParams chaincfg.Params
|
||||
RegtestParams chaincfg.Params
|
||||
)
|
||||
|
||||
func init() {
|
||||
// mainnet
|
||||
MainNetParams = chaincfg.MainNetParams
|
||||
MainNetParams.Net = MainnetMagic
|
||||
|
||||
MainNetParams.AddressMagicLen = 1
|
||||
MainNetParams.PubKeyHashAddrID = []byte{0x52}
|
||||
MainNetParams.ScriptHashAddrID = []byte{0x07}
|
||||
|
||||
// testnet
|
||||
TestNetParams = chaincfg.TestNet3Params
|
||||
TestNetParams.Net = TestnetMagic
|
||||
|
||||
TestNetParams.AddressMagicLen = 1
|
||||
TestNetParams.PubKeyHashAddrID = []byte{0x41}
|
||||
TestNetParams.ScriptHashAddrID = []byte{0xb2}
|
||||
|
||||
// regtest
|
||||
RegtestParams = chaincfg.RegressionNetParams
|
||||
RegtestParams.Net = RegtestMagic
|
||||
}
|
||||
|
||||
// ZcoinParser handle
|
||||
type ZcoinParser struct {
|
||||
*btc.BitcoinParser
|
||||
}
|
||||
|
||||
// NewZcoinParser returns new ZcoinParser instance
|
||||
func NewZcoinParser(params *chaincfg.Params, c *btc.Configuration) *ZcoinParser {
|
||||
return &ZcoinParser{
|
||||
BitcoinParser: btc.NewBitcoinParser(params, c),
|
||||
}
|
||||
}
|
||||
|
||||
// GetChainParams contains network parameters for the main Zcoin network,
|
||||
// the regression test Zcoin network, the test Zcoin network and
|
||||
// the simulation test Zcoin network, in this order
|
||||
func GetChainParams(chain string) *chaincfg.Params {
|
||||
if !chaincfg.IsRegistered(&MainNetParams) {
|
||||
err := chaincfg.Register(&MainNetParams)
|
||||
if err == nil {
|
||||
err = chaincfg.Register(&TestNetParams)
|
||||
}
|
||||
if err == nil {
|
||||
err = chaincfg.Register(&RegtestParams)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
switch chain {
|
||||
case "test":
|
||||
return &TestNetParams
|
||||
case "regtest":
|
||||
return &RegtestParams
|
||||
default:
|
||||
return &MainNetParams
|
||||
}
|
||||
}
|
||||
|
||||
// GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable
|
||||
func (p *ZcoinParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) {
|
||||
if len(addrDesc) > 0 && addrDesc[0] == OpZeroCoinMint {
|
||||
return []string{"Zeromint"}, false, nil
|
||||
}
|
||||
|
||||
if len(addrDesc) > 0 && addrDesc[0] == OpZeroCoinSpend {
|
||||
return []string{"Zerospend"}, false, nil
|
||||
}
|
||||
|
||||
return p.OutputScriptToAddressesFunc(addrDesc)
|
||||
}
|
||||
|
||||
// PackTx packs transaction to byte array using protobuf
|
||||
func (p *ZcoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
||||
return p.BaseParser.PackTx(tx, height, blockTime)
|
||||
}
|
||||
|
||||
// UnpackTx unpacks transaction from protobuf byte array
|
||||
func (p *ZcoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
||||
return p.BaseParser.UnpackTx(buf)
|
||||
}
|
||||
|
||||
// ParseBlock parses raw block to our Block struct
|
||||
func (p *ZcoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
|
||||
reader := bytes.NewReader(b)
|
||||
|
||||
// parse standard block header first
|
||||
header, err := parseBlockHeader(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// then MTP header
|
||||
if isMTP(header) {
|
||||
mtpHeader := MTPBlockHeader{}
|
||||
mtpHashData := MTPHashData{}
|
||||
|
||||
// header
|
||||
err = binary.Read(reader, binary.LittleEndian, &mtpHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// hash data
|
||||
err = binary.Read(reader, binary.LittleEndian, &mtpHashData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// proof
|
||||
for i := 0; i < MTPL*3; i++ {
|
||||
var numberProofBlocks uint8
|
||||
|
||||
err = binary.Read(reader, binary.LittleEndian, &numberProofBlocks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for j := uint8(0); j < numberProofBlocks; j++ {
|
||||
var mtpData [16]uint8
|
||||
|
||||
err = binary.Read(reader, binary.LittleEndian, mtpData[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse txs
|
||||
ntx, err := wire.ReadVarInt(reader, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txs := make([]bchain.Tx, ntx)
|
||||
|
||||
for i := uint64(0); i < ntx; i++ {
|
||||
tx := wire.MsgTx{}
|
||||
|
||||
err := tx.BtcDecode(reader, 0, wire.WitnessEncoding)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
btx := p.TxFromMsgTx(&tx, false)
|
||||
|
||||
p.parseZcoinTx(&btx)
|
||||
|
||||
txs[i] = btx
|
||||
}
|
||||
|
||||
return &bchain.Block{
|
||||
BlockHeader: bchain.BlockHeader{
|
||||
Size: len(b),
|
||||
Time: header.Timestamp.Unix(),
|
||||
},
|
||||
Txs: txs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseTxFromJson parses JSON message containing transaction and returns Tx struct
|
||||
func (p *ZcoinParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) {
|
||||
var tx bchain.Tx
|
||||
err := json.Unmarshal(msg, &tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range tx.Vout {
|
||||
vout := &tx.Vout[i]
|
||||
// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
|
||||
vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vout.JsonValue = ""
|
||||
}
|
||||
|
||||
p.parseZcoinTx(&tx)
|
||||
|
||||
return &tx, nil
|
||||
}
|
||||
|
||||
func (p *ZcoinParser) parseZcoinTx(tx *bchain.Tx) error {
|
||||
for i := range tx.Vin {
|
||||
vin := &tx.Vin[i]
|
||||
|
||||
// FIXME: right now we treat zerocoin spend vin as coinbase
|
||||
// change this after blockbook support special type of vin
|
||||
if vin.Txid == SpendTxID {
|
||||
vin.Coinbase = vin.Txid
|
||||
vin.Txid = ""
|
||||
vin.Sequence = 0
|
||||
vin.Vout = 0
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseBlockHeader(r io.Reader) (*wire.BlockHeader, error) {
|
||||
h := &wire.BlockHeader{}
|
||||
err := h.Deserialize(r)
|
||||
return h, err
|
||||
}
|
||||
|
||||
func isMTP(h *wire.BlockHeader) bool {
|
||||
epoch := h.Timestamp.Unix()
|
||||
|
||||
// the genesis block never be MTP block
|
||||
return epoch > GenesisBlockTime && epoch >= SwitchToMTPBlockHeader
|
||||
}
|
||||
|
||||
type MTPHashData struct {
|
||||
HashRootMTP [16]uint8
|
||||
BlockMTP [128][128]uint64
|
||||
}
|
||||
|
||||
type MTPBlockHeader struct {
|
||||
VersionMTP int32
|
||||
MTPHashValue chainhash.Hash
|
||||
Reserved1 chainhash.Hash
|
||||
Reserved2 chainhash.Hash
|
||||
}
|
|
@ -0,0 +1,620 @@
|
|||
// +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]
|
||||
|
||||
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: true,
|
||||
},
|
||||
}
|
||||
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-4",
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
package xzc
|
||||
|
||||
import (
|
||||
"blockbook/bchain"
|
||||
"blockbook/bchain/coins/btc"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type ZcoinRPC struct {
|
||||
*btc.BitcoinRPC
|
||||
}
|
||||
|
||||
func NewZcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
|
||||
// init base implementation
|
||||
bc, err := btc.NewBitcoinRPC(config, pushHandler)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init zcoin implementation
|
||||
zc := &ZcoinRPC{
|
||||
BitcoinRPC: bc.(*btc.BitcoinRPC),
|
||||
}
|
||||
|
||||
zc.ChainConfig.Parse = true
|
||||
zc.ChainConfig.SupportsEstimateFee = true
|
||||
zc.ChainConfig.SupportsEstimateSmartFee = false
|
||||
zc.ParseBlocks = true
|
||||
zc.RPCMarshaler = btc.JSONMarshalerV1{}
|
||||
|
||||
return zc, nil
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) Initialize() error {
|
||||
chainName, err := zc.GetChainInfoAndInitializeMempool(zc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params := GetChainParams(chainName)
|
||||
|
||||
// always create parser
|
||||
zc.Parser = NewZcoinParser(params, zc.ChainConfig)
|
||||
|
||||
// parameters for getInfo request
|
||||
if params.Net == MainnetMagic {
|
||||
zc.Testnet = false
|
||||
zc.Network = "livenet"
|
||||
} else {
|
||||
zc.Testnet = true
|
||||
zc.Network = "testnet"
|
||||
}
|
||||
|
||||
glog.Info("rpc: block chain ", params.Name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
|
||||
var err error
|
||||
|
||||
if hash == "" {
|
||||
hash, err = zc.GetBlockHash(height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// optimization
|
||||
if height > 0 {
|
||||
return zc.GetBlockWithoutHeader(hash, height)
|
||||
}
|
||||
|
||||
header, err := zc.GetBlockHeader(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := zc.GetBlockRaw(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, err := zc.Parser.ParseBlock(data)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||
}
|
||||
|
||||
block.BlockHeader = *header
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
|
||||
glog.V(1).Info("rpc: getblock (verbosity=true) ", hash)
|
||||
|
||||
res := btc.ResGetBlockInfo{}
|
||||
req := cmdGetBlock{Method: "getblock"}
|
||||
req.Params.BlockHash = hash
|
||||
req.Params.Verbosity = true
|
||||
err := zc.Call(&req, &res)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if btc.IsErrBlockNotFound(res.Error) {
|
||||
return nil, bchain.ErrBlockNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||
}
|
||||
return &res.Result, nil
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) GetBlockWithoutHeader(hash string, height uint32) (*bchain.Block, error) {
|
||||
data, err := zc.GetBlockRaw(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, err := zc.Parser.ParseBlock(data)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "%v %v", height, hash)
|
||||
}
|
||||
|
||||
block.BlockHeader.Hash = hash
|
||||
block.BlockHeader.Height = height
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) GetBlockRaw(hash string) ([]byte, error) {
|
||||
glog.V(1).Info("rpc: getblock (verbosity=false) ", hash)
|
||||
|
||||
res := btc.ResGetBlockRaw{}
|
||||
req := cmdGetBlock{Method: "getblock"}
|
||||
req.Params.BlockHash = hash
|
||||
req.Params.Verbosity = false
|
||||
err := zc.Call(&req, &res)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "hash %v", hash)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if btc.IsErrBlockNotFound(res.Error) {
|
||||
return nil, bchain.ErrBlockNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "hash %v", hash)
|
||||
}
|
||||
return hex.DecodeString(res.Result)
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) {
|
||||
glog.V(1).Info("rpc: getrawtransaction nonverbose ", txid)
|
||||
|
||||
res := btc.ResGetRawTransactionNonverbose{}
|
||||
req := cmdGetRawTransaction{Method: "getrawtransaction"}
|
||||
req.Params.Txid = txid
|
||||
req.Params.Verbose = 0
|
||||
err := zc.Call(&req, &res)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if btc.IsMissingTx(res.Error) {
|
||||
return nil, bchain.ErrTxNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "txid %v", txid)
|
||||
}
|
||||
data, err := hex.DecodeString(res.Result)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
tx, err := zc.Parser.ParseTx(data)
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) GetTransaction(txid string) (*bchain.Tx, error) {
|
||||
r, err := zc.getRawTransaction(txid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, err := zc.Parser.ParseTxFromJson(r)
|
||||
tx.CoinSpecificData = r
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) GetTransactionSpecific(tx *bchain.Tx) (json.RawMessage, error) {
|
||||
if csd, ok := tx.CoinSpecificData.(json.RawMessage); ok {
|
||||
return csd, nil
|
||||
}
|
||||
return zc.getRawTransaction(tx.Txid)
|
||||
}
|
||||
|
||||
func (zc *ZcoinRPC) getRawTransaction(txid string) (json.RawMessage, error) {
|
||||
glog.V(1).Info("rpc: getrawtransaction ", txid)
|
||||
|
||||
res := btc.ResGetRawTransaction{}
|
||||
req := cmdGetRawTransaction{Method: "getrawtransaction"}
|
||||
req.Params.Txid = txid
|
||||
req.Params.Verbose = 1
|
||||
err := zc.Call(&req, &res)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "txid %v", txid)
|
||||
}
|
||||
if res.Error != nil {
|
||||
if btc.IsMissingTx(res.Error) {
|
||||
return nil, bchain.ErrTxNotFound
|
||||
}
|
||||
return nil, errors.Annotatef(res.Error, "txid %v", txid)
|
||||
}
|
||||
return res.Result, nil
|
||||
}
|
||||
|
||||
type cmdGetBlock struct {
|
||||
Method string `json:"method"`
|
||||
Params struct {
|
||||
BlockHash string `json:"blockhash"`
|
||||
Verbosity bool `json:"verbosity"`
|
||||
} `json:"params"`
|
||||
}
|
||||
|
||||
type cmdGetRawTransaction struct {
|
||||
Method string `json:"method"`
|
||||
Params struct {
|
||||
Txid string `json:"txid"`
|
||||
Verbose int `json:"verbose"`
|
||||
} `json:"params"`
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"coin": {
|
||||
"name": "Zcoin",
|
||||
"shortcut": "XZC",
|
||||
"label": "Zcoin",
|
||||
"alias": "zcoin"
|
||||
},
|
||||
"ports": {
|
||||
"backend_rpc": 8050,
|
||||
"backend_message_queue": 38350,
|
||||
"blockbook_internal": 9050,
|
||||
"blockbook_public": 9150
|
||||
},
|
||||
"ipc": {
|
||||
"rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}",
|
||||
"rpc_user": "rpc",
|
||||
"rpc_pass": "rpc",
|
||||
"rpc_timeout": 25,
|
||||
"message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}"
|
||||
},
|
||||
"backend": {
|
||||
"package_name": "backend-zcoin",
|
||||
"package_revision": "satoshilabs-1",
|
||||
"system_user": "zcoin",
|
||||
"version": "0.13.7.6",
|
||||
"binary_url": "https://github.com/zcoinofficial/zcoin/releases/download/v0.13.7.6/zcoin-0.13.7.6-linux64.tar.gz",
|
||||
"verification_type": "sha256",
|
||||
"verification_source": "d1567283a4c530ef5a9297857d47c17541be182f5feabb3e2ce607c0d1a67511",
|
||||
"extract_command": "tar -C backend --strip 1 -xf",
|
||||
"exclude_files": [
|
||||
"bin/test_bitcoin",
|
||||
"bin/tor",
|
||||
"bin/tor-gencert",
|
||||
"bin/tor-resolve",
|
||||
"bin/torify",
|
||||
"bin/zcoin-qt",
|
||||
"etc/tor/torrc.sample",
|
||||
"include/bitcoinconsensus.h",
|
||||
"lib/libbitcoinconsensus.so",
|
||||
"lib/libbitcoinconsensus.so.0",
|
||||
"lib/libbitcoinconsensus.so.0.0.0",
|
||||
"share/tor/geoip",
|
||||
"share/tor/geoip6"
|
||||
],
|
||||
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/zcoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
|
||||
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/*.log",
|
||||
"postinst_script_template": "",
|
||||
"service_type": "forking",
|
||||
"service_additional_params_template": "",
|
||||
"protect_memory": true,
|
||||
"mainnet": true,
|
||||
"server_config_file": "bitcoin_like.conf",
|
||||
"client_config_file": "bitcoin_like_client.conf",
|
||||
"additional_params": {
|
||||
"deprecatedrpc": "estimatefee"
|
||||
}
|
||||
},
|
||||
"blockbook": {
|
||||
"package_name": "blockbook-zcoin",
|
||||
"system_user": "blockbook-zcoin",
|
||||
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
|
||||
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
|
||||
"explorer_url": "",
|
||||
"additional_params": "",
|
||||
"block_chain": {
|
||||
"mempool_workers": 8,
|
||||
"mempool_sub_workers": 2,
|
||||
"block_addresses_to_keep": 300,
|
||||
"additional_params": {}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"package_maintainer": "Putta Khunchalee",
|
||||
"package_maintainer_email": "putta@zcoin.io"
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
| Liquid | 9047 | 9147 | 8047 | 38347 |
|
||||
| Fujicoin | 9048 | 9148 | 8048 | 38348 |
|
||||
| PIVX | 9049 | 9149 | 8049 | 38349 |
|
||||
| Zcoin | 9050 | 9150 | 8050 | 38350 |
|
||||
| Bitcoin Testnet | 19030 | 19130 | 18030 | 48330 |
|
||||
| Bitcoin Cash Testnet | 19031 | 19131 | 18031 | 48331 |
|
||||
| Zcash Testnet | 19032 | 19132 | 18032 | 48332 |
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"blockHeight": 126311,
|
||||
"blockHash": "4857051323dd6a10bc1c92facb00e7c8258adc9b8b680d0bcdd19034a777d72d",
|
||||
"blockTime": 1547120622,
|
||||
"blockTxs": [
|
||||
"5ee3ba91195adc9a22e61a570b168052764584305000450d04355ebcb9cc4be8",
|
||||
"2f831477d523ea717caf9a9520dd848b8fe932540207037fabf100a56d466e91",
|
||||
"347d7c8c1d77f2f835641be27d97900f88be71646bdaa14ffb11b37aaac72f79"
|
||||
],
|
||||
"txDetails": {
|
||||
"2f831477d523ea717caf9a9520dd848b8fe932540207037fabf100a56d466e91": {
|
||||
"hex": "010000000106be6afc693eb158fa010f751c347982851108ea316d0685109caaa8ec4580c2000000006a473044022048dcdd1121148ecf495df74f563384d91db0635dae3c608666511ef8f24adc19022004af5384be1bce1531d0bf8498a8bfb150f797e63e348ca3865f0322203384aa012102d79d7e7f40e091517465c50ed3f5345c7b9a4611a98103ee1ca1f8e66686ad9fffffffff02e04d6cb3160000001976a914b923050a6542d70d6eb6546ba3275a2b6ea0eda588ac06d8c849000000001976a914c353c188620cb33a72d218c0d67fb3f92ad1b6b088ac00000000",
|
||||
"txid": "2f831477d523ea717caf9a9520dd848b8fe932540207037fabf100a56d466e91",
|
||||
"blocktime": 1547120622,
|
||||
"time": 1547120622,
|
||||
"locktime": 0,
|
||||
"version": 1,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c28045eca8aa9c1085066d31ea0811858279341c750f01fa58b13e69fc6abe06",
|
||||
"vout": 0,
|
||||
"sequence": 4294967295,
|
||||
"scriptSig": {
|
||||
"hex": "473044022048dcdd1121148ecf495df74f563384d91db0635dae3c608666511ef8f24adc19022004af5384be1bce1531d0bf8498a8bfb150f797e63e348ca3865f0322203384aa012102d79d7e7f40e091517465c50ed3f5345c7b9a4611a98103ee1ca1f8e66686ad9f"
|
||||
}
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 974.99500000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914b923050a6542d70d6eb6546ba3275a2b6ea0eda588ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 12.37899270,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914c353c188620cb33a72d218c0d67fb3f92ad1b6b088ac"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"347d7c8c1d77f2f835641be27d97900f88be71646bdaa14ffb11b37aaac72f79": {
|
||||
"hex": "0100000004bc566f299c27644851e70f8646f2ed642985897f488090f5bd5b152d891388a9000000006b483045022100cd5ca45783f836db65a47ba568f97f890155c27ccf0769c1edf231bf6bf49f9b022021d8493fae950bced2c417ce6c4a62aaad495c4d8675e4a4a3e9d86ab44f4b29012102d91223be36388a51cef618ec34c2a1d95f85b6d85d0e07e9e963d84893b5cc4dfefffffff117437f28af1665a002c8351e903de10bd40ab73d54932bbaae28caa6f49a42640000006b483045022100962a7c4b0a96b25fa418f92a69e9f37c5517740d50e996a92724f064bfadcf75022073f1c0475215bef70de392273360655a0b0d4f1f8afd3917614a5dfd1ddd1ca1012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669eafeffffff0dd680cce849762fa7f3f117a1b0e3e7fb6493f2600152143502aa59ad7ca4ed4d0000006b483045022100a6b7befee6468f01e2b3813f05b81241dd5a4c0b04d97a783940c75d97b85ba502206c0dd2fa5cc5c153d359c55f24407c97aec32bf42b2723fc40374188443bd4b2012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669eafeffffffd7e86128b28dcf2046c33f098cfcc2b7f08ea781cc119c0944b2fb23e378135d150000006a47304402204116539acc084920a86bf837ade9d938b517dfa0d346beb969cc97505e6f21520220069a9a33f798a6c1912e29568be2cef12d4db0ea1db751054db5e2311b761854012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669eafeffffff0229b90000000000001976a914da8378d88cd781e0a6f9fdfa6668dd47a718cf6188ac80a35d06000000001976a914707077511db03836716dc01ce47442596264fd8a88acccea0100",
|
||||
"txid": "347d7c8c1d77f2f835641be27d97900f88be71646bdaa14ffb11b37aaac72f79",
|
||||
"blocktime": 1547120622,
|
||||
"time": 1547120622,
|
||||
"locktime": 125644,
|
||||
"version": 1,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "a98813892d155bbdf59080487f89852964edf246860fe7514864279c296f56bc",
|
||||
"vout": 0,
|
||||
"sequence": 4294967294,
|
||||
"scriptSig": {
|
||||
"hex": "483045022100cd5ca45783f836db65a47ba568f97f890155c27ccf0769c1edf231bf6bf49f9b022021d8493fae950bced2c417ce6c4a62aaad495c4d8675e4a4a3e9d86ab44f4b29012102d91223be36388a51cef618ec34c2a1d95f85b6d85d0e07e9e963d84893b5cc4d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"txid": "429af4a6ca28aeba2b93543db70ad40be13d901e35c802a06516af287f4317f1",
|
||||
"vout": 100,
|
||||
"sequence": 4294967294,
|
||||
"scriptSig": {
|
||||
"hex": "483045022100962a7c4b0a96b25fa418f92a69e9f37c5517740d50e996a92724f064bfadcf75022073f1c0475215bef70de392273360655a0b0d4f1f8afd3917614a5dfd1ddd1ca1012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"txid": "eda47cad59aa023514520160f29364fbe7e3b0a117f1f3a72f7649e8cc80d60d",
|
||||
"vout": 77,
|
||||
"sequence": 4294967294,
|
||||
"scriptSig": {
|
||||
"hex": "483045022100a6b7befee6468f01e2b3813f05b81241dd5a4c0b04d97a783940c75d97b85ba502206c0dd2fa5cc5c153d359c55f24407c97aec32bf42b2723fc40374188443bd4b2012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"txid": "5d1378e323fbb244099c11cc81a78ef0b7c2fc8c093fc34620cf8db22861e8d7",
|
||||
"vout": 21,
|
||||
"sequence": 4294967294,
|
||||
"scriptSig": {
|
||||
"hex": "47304402204116539acc084920a86bf837ade9d938b517dfa0d346beb969cc97505e6f21520220069a9a33f798a6c1912e29568be2cef12d4db0ea1db751054db5e2311b761854012103bbfb869bf408cfdc237c63c1dcec226faf56cc141c42ef6bb8ef4d156df669ea"
|
||||
}
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00047401,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914da8378d88cd781e0a6f9fdfa6668dd47a718cf6188ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 1.06800000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914707077511db03836716dc01ce47442596264fd8a88ac"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
{
|
||||
"connectBlocks": {
|
||||
"syncRanges": [
|
||||
{ "lower": 10012, "upper": 10020 },
|
||||
{ "lower": 121100, "upper": 121150 }
|
||||
],
|
||||
"blocks": {
|
||||
"10012": {
|
||||
"height": 10012,
|
||||
"hash": "270364b0b441f4b5b4c98d073462c0f00e1200fec00410e27f4361e4695a8530",
|
||||
"noTxs": 2,
|
||||
"txDetails": [
|
||||
{
|
||||
"hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff26021c27062f503253482f043c424258081000cd76000000000d2f6e6f64655374726174756d2f0000000006406a7aee000000001976a9146934fe23ac758cbc21953fadfab01dd3671c01b688ac00c2eb0b000000001976a9147d9ed014fc4e603fca7c2e3f9097fb7d0fb487fc88ac00c2eb0b000000001976a914dcf01f01f5655c10d4fa8149d71cfee36313c02e88ac00c2eb0b000000001976a914ff71b0c9c2a90c6164a50a2fb523eb54a8a6b55088ac00c2eb0b000000001976a9140654dd9b856f2ece1d56cb4ee5043cd9398d962c88ac00c2eb0b000000001976a9140b4bfb256ef4bfa360e3b9e66e53a0bd84d196bc88ac00000000",
|
||||
"txid": "ec09f614f427ac2553846d4e91bdbac34748502374bb981fc324f27f8c8683f6",
|
||||
"blocktime": 1480737340,
|
||||
"time": 1480737340,
|
||||
"version": 1,
|
||||
"vin": [
|
||||
{
|
||||
"coinbase": "021c27062f503253482f043c424258081000cd76000000000d2f6e6f64655374726174756d2f",
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 40.01,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a9146934fe23ac758cbc21953fadfab01dd3671c01b688ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 2.0,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a9147d9ed014fc4e603fca7c2e3f9097fb7d0fb487fc88ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 2.0,
|
||||
"n": 2,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914dcf01f01f5655c10d4fa8149d71cfee36313c02e88ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 2.0,
|
||||
"n": 3,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914ff71b0c9c2a90c6164a50a2fb523eb54a8a6b55088ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 2.0,
|
||||
"n": 4,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a9140654dd9b856f2ece1d56cb4ee5043cd9398d962c88ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 2.0,
|
||||
"n": 5,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a9140b4bfb256ef4bfa360e3b9e66e53a0bd84d196bc88ac"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hex": "0100000001a82d9bb9c02ad9eddfc9d760073b4fc2632b6c939a43d104a8ad08cebee12490000000006b483045022100ecadec884ee8e570bb77704672e223d5cfbaba0aa0957659b8efeabb71392587022076a17e47ac618bcf76c47f6a7fac739dad05f1efda3c61ec5d7cae7021088f370121021a1a3c0f862f7b757930d9654dce951175188eb49f659d9adce95113de5d05f2ffffffff02bc16367e000000001976a9149e694e14a690f487d2a42603dfa1e39e58adcb4688ac01a89721000000001976a914184f6e4e10fb4f1800d32537617528674b6afe0c88ac00000000",
|
||||
"txid": "c04be7747ef077477aedbec55f1cf6fd51ec2efd58ff978f08884eab3c6fdfbf",
|
||||
"time": 1480737340,
|
||||
"blocktime": 1480737340,
|
||||
"version": 1,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "9024e1bece08ada804d1439a936c2b63c24f3b0760d7c9dfedd92ac0b99b2da8",
|
||||
"vout": 0,
|
||||
"sequence": 4294967295,
|
||||
"scriptSig": {
|
||||
"hex": "483045022100ecadec884ee8e570bb77704672e223d5cfbaba0aa0957659b8efeabb71392587022076a17e47ac618bcf76c47f6a7fac739dad05f1efda3c61ec5d7cae7021088f370121021a1a3c0f862f7b757930d9654dce951175188eb49f659d9adce95113de5d05f2"
|
||||
}
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 21.1747398,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a9149e694e14a690f487d2a42603dfa1e39e58adcb4688ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 5.63587073,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914184f6e4e10fb4f1800d32537617528674b6afe0c88ac"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"10013": {
|
||||
"height": 10013,
|
||||
"hash": "8be1836104f7adefc0ac8067f56abd1d30725dc05ccb19236be6f538637ec213",
|
||||
"noTxs": 4,
|
||||
"txDetails": [
|
||||
{
|
||||
"hex": "0100000001e9f4e2d5180ae0aa5b1ef1fdc496118d6226b688c7986dd9b4215fb4ad59b729010000006a47304402206261d51bf92238e28432307e92fc58af641a15db3a72cfc3a21d5a2ddfdc4d2e022060cd1044cc0a1a2932eaf642f9a4d08b62abb82bde6e7332f65aa343aa204434012102038af35cb691fb64a5af8ae4f3739a3a834363436bb7a4a5d98d9d9eaf46704effffffff02e3c72c00000000001976a914d475cafdcf52e81ee0ed36fa5b1aacebc9cc436f88ac6b638506000000001976a914c8f06a3a16c1210ae30c95111b60c481e20dcc0088ac00000000",
|
||||
"txid": "01676407d835b8cb9a411136134efcfed3708ba123cb911532b63d9e464eae2e",
|
||||
"version": 1,
|
||||
"time": 1480737375,
|
||||
"blocktime": 1480737375,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "29b759adb45f21b4d96d98c788b626628d1196c4fdf11e5baae00a18d5e2f4e9",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"hex": "47304402206261d51bf92238e28432307e92fc58af641a15db3a72cfc3a21d5a2ddfdc4d2e022060cd1044cc0a1a2932eaf642f9a4d08b62abb82bde6e7332f65aa343aa204434012102038af35cb691fb64a5af8ae4f3739a3a834363436bb7a4a5d98d9d9eaf46704e"
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.02934755,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914d475cafdcf52e81ee0ed36fa5b1aacebc9cc436f88ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 1.09405035,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914c8f06a3a16c1210ae30c95111b60c481e20dcc0088ac"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"121100": {
|
||||
"height": 121100,
|
||||
"hash": "02bc0d5ae888024d95f1887712def2639c341c8fbb85c25cc3684e8b2b60081f",
|
||||
"noTxs": 30,
|
||||
"txDetails": [
|
||||
{
|
||||
"hex": "01000000017ce8aed3eec1d7891141857700287f431090c1f9466e65b4d0f6a751feafa23c000000006b483045022100b7934000466f52a2cbdb63ea099ad30685c82778890f9b06facc09e6e9b3cb5502204a44c5b9c48c2ba4e61b7af467b384fbea8e1efb63296326ca222c97642d61b901210257436124422382febf4003f5bff403aeccab2b6ad901ea1c4d4e08ebb26eadabfeffffff0200105e5f000000001976a914732cd1f18bc5455be4c5f04b120dc4f06ebb2fbc88ac8cd81e03000000001976a914cfcce1c68a8974b1410e971708839fb95c0afcd788ac0bd90100",
|
||||
"txid": "b71c6ed0b38c9a52fa02c25b79ba2b9f7da599fddae2fdf36dc2fa65bb127699",
|
||||
"version": 1,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "3ca2affe51a7f6d0b4656e46f9c19010437f28007785411189d7c1eed3aee87c",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"hex": "483045022100b7934000466f52a2cbdb63ea099ad30685c82778890f9b06facc09e6e9b3cb5502204a44c5b9c48c2ba4e61b7af467b384fbea8e1efb63296326ca222c97642d61b901210257436124422382febf4003f5bff403aeccab2b6ad901ea1c4d4e08ebb26eadab"
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 16.0,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914732cd1f18bc5455be4c5f04b120dc4f06ebb2fbc88ac"
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.52353164,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"hex": "76a914cfcce1c68a8974b1410e971708839fb95c0afcd788ac"
|
||||
}
|
||||
}
|
||||
],
|
||||
"time": 1545641453,
|
||||
"blocktime": 1545641453
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"handleFork": {
|
||||
"syncRanges": [
|
||||
{ "lower": 10012, "upper": 10017 },
|
||||
{ "lower": 121100, "upper": 121104 }
|
||||
],
|
||||
"fakeBlocks": {
|
||||
"10012": {
|
||||
"height": 10012,
|
||||
"hash": "8a647ed7cbc02600775dd6a7fff874a394a9abdfe5d86d9c46aa3d9a4307e010"
|
||||
},
|
||||
"10013": {
|
||||
"height": 10013,
|
||||
"hash": "005b810a796c05359264f847f968132981b608138e42655ffd9261e2a2f8e6c8"
|
||||
},
|
||||
"10014": {
|
||||
"height": 10014,
|
||||
"hash": "b11ee0e2620bc1a37da725f3cd4a1db9faec2b88ae3e77c9c4d66bbf5106bc44"
|
||||
},
|
||||
"10015": {
|
||||
"height": 10015,
|
||||
"hash": "712819a7a0c669c2367660cc246c725de58b68b7f77b803b1964a7c4343a115f"
|
||||
},
|
||||
"10016": {
|
||||
"height": 10016,
|
||||
"hash": "69b3ba86607980063eb9a04b9701c8d94206148bae1e3a4324e0fb36ca2e5d11"
|
||||
},
|
||||
"10017": {
|
||||
"height": 10017,
|
||||
"hash": "e60984c79e2723a19ebbc37f8d0c10e1e6294f1088c9bed3e532254f68c1a199"
|
||||
},
|
||||
"121100": {
|
||||
"height": 121100,
|
||||
"hash": "7eda2cf4cefb5945dbe60fd7e62296ff04fc8a2007f735d574edbbd6e30fb829"
|
||||
},
|
||||
"121101": {
|
||||
"height": 121101,
|
||||
"hash": "66d76166f8655a0394e26643c06bea61e0b1d0bc73acca3a53e48d80c7dab4af"
|
||||
},
|
||||
"121102": {
|
||||
"height": 121102,
|
||||
"hash": "65e94ebede51ea311784676b0673546e398b882b333be86ed16a100774bed32a"
|
||||
},
|
||||
"121103": {
|
||||
"height": 121103,
|
||||
"hash": "2d00b3d85882295717141e9c900d43d3e7b0a7e3ecdeaa05d32ed56d20577a97"
|
||||
},
|
||||
"121104": {
|
||||
"height": 121104,
|
||||
"hash": "199220df07b03ddacc3ba0e18a2562c83cb57dff0d12d8953b8233d5a47d7bf3"
|
||||
}
|
||||
},
|
||||
"realBlocks": {
|
||||
"10012": {
|
||||
"height": 10012,
|
||||
"hash": "270364b0b441f4b5b4c98d073462c0f00e1200fec00410e27f4361e4695a8530"
|
||||
},
|
||||
"10013": {
|
||||
"height": 10013,
|
||||
"hash": "8be1836104f7adefc0ac8067f56abd1d30725dc05ccb19236be6f538637ec213"
|
||||
},
|
||||
"10014": {
|
||||
"height": 10014,
|
||||
"hash": "def841c7406526043da07f202d67a0b1fe18d10650cbb3661a56722ad814815f"
|
||||
},
|
||||
"10015": {
|
||||
"height": 10015,
|
||||
"hash": "4dfab32ae8abb08ecd02b83305606d5d154e57018ff4d12cc744f9cd0b2d47b7"
|
||||
},
|
||||
"10016": {
|
||||
"height": 10016,
|
||||
"hash": "e4d49fd46e9d5e7488678356c91e7f8b4d2c69a0dd39e52e107a2987d41e230c"
|
||||
},
|
||||
"10017": {
|
||||
"height": 10017,
|
||||
"hash": "713837605fd64f8458cace5b961b28d0f1104665a054a6dde4b3572d520270f5"
|
||||
},
|
||||
"121100": {
|
||||
"height": 121100,
|
||||
"hash": "02bc0d5ae888024d95f1887712def2639c341c8fbb85c25cc3684e8b2b60081f"
|
||||
},
|
||||
"121101": {
|
||||
"height": 121101,
|
||||
"hash": "aa30be2d62075ee4d147149ef48ad42cd4f6d0fef90c0ec67c117f1b7d7e192f"
|
||||
},
|
||||
"121102": {
|
||||
"height": 121102,
|
||||
"hash": "77f49fc80ad9bb5398832332f98f7535e53971fab2dc81f7f3e1fc1dfac8ac7f"
|
||||
},
|
||||
"121103": {
|
||||
"height": 121103,
|
||||
"hash": "ed5947e57d68528929d32846a6b7942a5b9db4c98b9eacbd72e8662121bb7971"
|
||||
},
|
||||
"121104": {
|
||||
"height": 121104,
|
||||
"hash": "bea29f4df145ea43fd4450aad21ad79388f1fff36b9ab62a1b394440bf47eaf8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -95,5 +95,10 @@
|
|||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync",
|
||||
"EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"],
|
||||
"sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"]
|
||||
},
|
||||
"zcoin": {
|
||||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync",
|
||||
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"],
|
||||
"sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue