diff --git a/bchain/coins/bitcore/bitcoreparser.go b/bchain/coins/bitcore/bitcoreparser.go new file mode 100644 index 00000000..93951cb2 --- /dev/null +++ b/bchain/coins/bitcore/bitcoreparser.go @@ -0,0 +1,83 @@ +package bitcore + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "github.com/martinboehm/btcd/wire" + "github.com/martinboehm/btcutil/chaincfg" +) + +const ( + MainnetMagic wire.BitcoinNet = 0xf9beb4d9 + TestnetMagic wire.BitcoinNet = 0xfdd2c8f1 + RegtestMagic wire.BitcoinNet = 0xfabfb5da +) + +var ( + MainNetParams chaincfg.Params + TestNetParams chaincfg.Params +) + +func init() { + MainNetParams = chaincfg.MainNetParams + MainNetParams.Net = MainnetMagic + MainNetParams.PubKeyHashAddrID = []byte{3} + MainNetParams.ScriptHashAddrID = []byte{125} + MainNetParams.Bech32HRPSegwit = "btx" + + TestNetParams = chaincfg.TestNet3Params + TestNetParams.Net = TestnetMagic + TestNetParams.PubKeyHashAddrID = []byte{111} + TestNetParams.ScriptHashAddrID = []byte{196} + TestNetParams.Bech32HRPSegwit = "tbtx" + + err := chaincfg.Register(&MainNetParams) + if err != nil { + panic(err) + } +} + +// BitcoreParser handle +type BitcoreParser struct { + *btc.BitcoinParser + baseparser *bchain.BaseParser +} + +// NewBitcoreParser returns new BitcoreParser instance +func NewBitcoreParser(params *chaincfg.Params, c *btc.Configuration) *BitcoreParser { + return &BitcoreParser{ + BitcoinParser: btc.NewBitcoinParser(params, c), + baseparser: &bchain.BaseParser{}, + } +} + +// GetChainParams contains network parameters for the main Bitcore network, +// and the test Bitcore network +func GetChainParams(chain string) *chaincfg.Params { + if !chaincfg.IsRegistered(&MainNetParams) { + err := chaincfg.Register(&MainNetParams) + if err == nil { + err = chaincfg.Register(&TestNetParams) + } + if err != nil { + panic(err) + } + } + switch chain { + case "test": + return &TestNetParams + default: + return &MainNetParams + } +} + +// PackTx packs transaction to byte array using protobuf +func (p *BitcoreParser) 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 *BitcoreParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { + return p.baseparser.UnpackTx(buf) +} + diff --git a/bchain/coins/bitcore/bitcoreparser_test.go b/bchain/coins/bitcore/bitcoreparser_test.go new file mode 100644 index 00000000..96599a48 --- /dev/null +++ b/bchain/coins/bitcore/bitcoreparser_test.go @@ -0,0 +1,210 @@ +// +build unittest + +package bitcore + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "encoding/hex" + "math/big" + "os" + "reflect" + "testing" + "github.com/martinboehm/btcutil/chaincfg" +) + +func TestMain(m *testing.M) { + c := m.Run() + chaincfg.ResetParams() + os.Exit(c) +} + +func Test_GetAddrDescFromAddress_Mainnet(t *testing.T) { + type args struct { + address string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "pubkeyhash1", + args: args{address: "2HbJfcGD6NTm318VeBjfd2hLf44hHkzHVV"}, + want: "76a9143236327ebad3be5e336777bb3562439720f38dc488ac", + wantErr: false, + }, + { + name: "pubkeyhash2", + args: args{address: "2XFmLkpyBzJncnnkALQ3qnMqSqUdqcBdc4"}, + want: "76a914c815e7f760bbd5f109d58e848cf78ba808d972e088ac", + wantErr: false, + }, + { + name: "scripthash1", + args: args{address: "scUVfntFvnyTHRCvBwUNyKGVFLiBb2iHVK"}, + want: "a914c7ec567ef583a96a74c02980cc42f728cc987c3287", + wantErr: false, + }, + { + name: "scripthash2", + args: args{address: "sVeAXe1CMWVAuq5174hG49QRfkBp4GFvAu"}, + want: "a9147cf7a3a6b1305871ff5f0f064aaa634880ff67ab87", + wantErr: false, + }, + { + name: "witness_v0_keyhash", + args: args{address: "btx1qnfkmarp8pe8q05690zd48qma3gmp0pp66gqsv3"}, + want: "00149a6dbe8c270e4e07d345789b53837d8a3617843a", + wantErr: false, + }, + } + parser := NewBitcoreParser(GetChainParams("main"), &btc.Configuration{}) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parser.GetAddrDescFromAddress(tt.args.address) + if (err != nil) != tt.wantErr { + t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr) + return + } + h := hex.EncodeToString(got) + if !reflect.DeepEqual(h, tt.want) { + t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want) + } + }) + } +} + + +var ( + testTx1 bchain.Tx + + testTxPacked1 = "0a20fcd4f2e45787a33571bc9b2ce939d6e8e51fa053296de9240f05455702bd954012e2010200000001f69bd1fd76e52a426f21332e3b7cfbc3350eacbd21c6e0c11a7ae11919803ef0010000006b483045022100d1fa62b9d7860a03e1dcd4734fe42457cb508ebb49e896d7a77748d997d09fba022005f1657b39451afe97076d8667fe5f6f18ca76391521ab84d09d5b82137d933b0121035aaf032f13761f27465467dc73f1998a80dd4d85a6353d2832a7244d7b591d3effffffff02a87322b3010000001976a914d0c320db3fbd0abe2b6fe31a3bca4fed8ce8669588ac94b94f37000000001976a9145584ee07090af59938e991c9d8e9e945c99a449f88ac0000000018858a8ce205200028f9f3133299010a001220f03e801919e17a1ac1e0c621bdac0e35c3fb7c3b2e33216f422ae576fdd19bf61801226b483045022100d1fa62b9d7860a03e1dcd4734fe42457cb508ebb49e896d7a77748d997d09fba022005f1657b39451afe97076d8667fe5f6f18ca76391521ab84d09d5b82137d933b0121035aaf032f13761f27465467dc73f1998a80dd4d85a6353d2832a7244d7b591d3e28ffffffff0f3a480a0501b32273a810001a1976a914d0c320db3fbd0abe2b6fe31a3bca4fed8ce8669588ac22223259336546797741414673617039757139726942474143684e326858356a6e7268753a470a04374fb99410011a1976a9145584ee07090af59938e991c9d8e9e945c99a449f88ac2222324c6f7a646b704450723562356b6a66445042315a76454c597735734475684139594002" +) + +func init() { + testTx1 = bchain.Tx{ + Hex: "0200000001f69bd1fd76e52a426f21332e3b7cfbc3350eacbd21c6e0c11a7ae11919803ef0010000006b483045022100d1fa62b9d7860a03e1dcd4734fe42457cb508ebb49e896d7a77748d997d09fba022005f1657b39451afe97076d8667fe5f6f18ca76391521ab84d09d5b82137d933b0121035aaf032f13761f27465467dc73f1998a80dd4d85a6353d2832a7244d7b591d3effffffff02a87322b3010000001976a914d0c320db3fbd0abe2b6fe31a3bca4fed8ce8669588ac94b94f37000000001976a9145584ee07090af59938e991c9d8e9e945c99a449f88ac00000000", + Blocktime: 1547896069, + Time: 1547896069, + Txid: "fcd4f2e45787a33571bc9b2ce939d6e8e51fa053296de9240f05455702bd9540", + LockTime: 0, + Version: 2, + Vin: []bchain.Vin{ + { + ScriptSig: bchain.ScriptSig{ + Hex: "483045022100d1fa62b9d7860a03e1dcd4734fe42457cb508ebb49e896d7a77748d997d09fba022005f1657b39451afe97076d8667fe5f6f18ca76391521ab84d09d5b82137d933b0121035aaf032f13761f27465467dc73f1998a80dd4d85a6353d2832a7244d7b591d3e", + }, + Txid: "f03e801919e17a1ac1e0c621bdac0e35c3fb7c3b2e33216f422ae576fdd19bf6", + Vout: 1, + Sequence: 4294967295, + }, + }, + Vout: []bchain.Vout{ + { + ValueSat: *big.NewInt(7300346792), + N: 0, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "76a914d0c320db3fbd0abe2b6fe31a3bca4fed8ce8669588ac", + Addresses: []string{ + "2Y3eFywAAFsap9uq9riBGAChN2hX5jnrhu", + }, + }, + }, + { + ValueSat: *big.NewInt(927971732), + N: 1, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: "76a9145584ee07090af59938e991c9d8e9e945c99a449f88ac", + Addresses: []string{ + "2LozdkpDPr5b5kjfDPB1ZvELYw5sDuhA9Y", + }, + }, + }, + }, + } +} + +func Test_PackTx(t *testing.T) { + type args struct { + tx bchain.Tx + height uint32 + blockTime int64 + parser *BitcoreParser + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "bitcore-1", + args: args{ + tx: testTx1, + height: 326137, + blockTime: 1547896069, + parser: NewBitcoreParser(GetChainParams("main"), &btc.Configuration{}), + }, + want: testTxPacked1, + 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 + } + h := hex.EncodeToString(got) + if !reflect.DeepEqual(h, tt.want) { + t.Errorf("packTx() = %v, want %v", h, tt.want) + } + }) + } +} + +func Test_UnpackTx(t *testing.T) { + type args struct { + packedTx string + parser *BitcoreParser + } + tests := []struct { + name string + args args + want *bchain.Tx + want1 uint32 + wantErr bool + }{ + { + name: "bitcore-1", + args: args{ + packedTx: testTxPacked1, + parser: NewBitcoreParser(GetChainParams("main"), &btc.Configuration{}), + }, + want: &testTx1, + want1: 326137, + 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 !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) + } + }) + } +} + diff --git a/bchain/coins/bitcore/bitcorerpc.go b/bchain/coins/bitcore/bitcorerpc.go new file mode 100644 index 00000000..914461de --- /dev/null +++ b/bchain/coins/bitcore/bitcorerpc.go @@ -0,0 +1,134 @@ +package bitcore + +import ( + "blockbook/bchain" + "blockbook/bchain/coins/btc" + "encoding/json" + "github.com/juju/errors" + "github.com/golang/glog" +) + +// BitcoreRPC is an interface to JSON-RPC bitcoind service. +type BitcoreRPC struct { + *btc.BitcoinRPC +} + +// NewBitcoreRPC returns new BitcoreRPC instance. +func NewBitcoreRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) { + b, err := btc.NewBitcoinRPC(config, pushHandler) + if err != nil { + return nil, err + } + + s := &BitcoreRPC{ + b.(*btc.BitcoinRPC), + } + s.RPCMarshaler = btc.JSONMarshalerV2{} + s.ChainConfig.SupportsEstimateFee = false + + return s, nil +} + +// Initialize initializes BitcoreRPC instance. +func (b *BitcoreRPC) Initialize() error { + ci, err := b.GetChainInfo() + if err != nil { + return err + } + chainName := ci.Chain + glog.Info("Chain name ", chainName) + params := GetChainParams(chainName) + + // always create parser + b.Parser = NewBitcoreParser(params, b.ChainConfig) + + // parameters for getInfo request + if params.Net == MainnetMagic { + b.Testnet = false + b.Network = "livenet" + } else { + b.Testnet = true + b.Network = "testnet" + } + + glog.Info("rpc: block chain ", params.Name) + + return nil +} + + +// GetBlock returns block with given hash. + +func (f *BitcoreRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) { + var err error + if hash == "" { + hash, err = f.GetBlockHash(height) + if err != nil { + return nil, err + } + } + if !f.ParseBlocks { + return f.GetBlockFull(hash) + } + // optimization + if height > 0 { + return f.GetBlockWithoutHeader(hash, height) + } + header, err := f.GetBlockHeader(hash) + if err != nil { + return nil, err + } + data, err := f.GetBlockRaw(hash) + if err != nil { + return nil, err + } + block, err := f.Parser.ParseBlock(data) + if err != nil { + return nil, errors.Annotatef(err, "hash %v", hash) + } + block.BlockHeader = *header + return block, nil +} + + // GetBlockFull returns block with given hash +func (f *BitcoreRPC) GetBlockFull(hash string) (*bchain.Block, error) { + glog.V(1).Info("rpc: getblock (verbosity=2) ", hash) + + res := btc.ResGetBlockFull{} + req := btc.CmdGetBlock{Method: "getblock"} + req.Params.BlockHash = hash + req.Params.Verbosity = 2 + err := f.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) + } + + for i := range res.Result.Txs { + tx := &res.Result.Txs[i] + for j := range tx.Vout { + vout := &tx.Vout[j] + // convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal + vout.ValueSat, err = f.Parser.AmountToBigInt(vout.JsonValue) + if err != nil { + return nil, err + } + vout.JsonValue = "" + } + } + + return &res.Result, nil +} + + // GetTransactionForMempool returns a transaction by the transaction ID. +// It could be optimized for mempool, i.e. without block time and confirmations +func (f *BitcoreRPC) GetTransactionForMempool(txid string) (*bchain.Tx, error) { + return f.GetTransaction(txid) +} + diff --git a/bchain/coins/blockchain.go b/bchain/coins/blockchain.go index 328ddeb5..798aba86 100644 --- a/bchain/coins/blockchain.go +++ b/bchain/coins/blockchain.go @@ -4,6 +4,7 @@ import ( "blockbook/bchain" "blockbook/bchain/coins/bch" "blockbook/bchain/coins/bellcoin" + "blockbook/bchain/coins/bitcore" "blockbook/bchain/coins/btc" "blockbook/bchain/coins/btg" "blockbook/bchain/coins/cpuchain" @@ -105,6 +106,7 @@ func init() { BlockChainFactories["CPUchain"] = cpuchain.NewCPUchainRPC BlockChainFactories["Unobtanium"] = unobtanium.NewUnobtaniumRPC BlockChainFactories["DeepOnion"] = deeponion.NewDeepOnionRPC + BlockChainFactories["Bitcore"] = bitcore.NewBitcoreRPC } // GetCoinNameFromConfig gets coin name and coin shortcut from config file diff --git a/configs/coins/bitcore.json b/configs/coins/bitcore.json new file mode 100644 index 00000000..8cf72d54 --- /dev/null +++ b/configs/coins/bitcore.json @@ -0,0 +1,71 @@ +{ + "coin": { + "name": "Bitcore", + "shortcut": "BTX", + "label": "Bitcore", + "alias": "bitcore" + }, + "ports": { + "backend_rpc": 8054, + "backend_message_queue": 38354, + "blockbook_internal": 9054, + "blockbook_public": 9154 + }, + "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-bitcore", + "package_revision": "satoshilabs-1", + "system_user": "bitcore", + "version": "0.15.2.1", + "binary_url": "https://github.com/dalijolijo/BitCore/releases/download/0.15.2.1/bitcore-0.15.2.1-x86_64-linux-gnu_no-wallet.tar.gz", + "verification_type": "sha256", + "verification_source": "4e47b33d5fa7d67151c9860f4cd19c99a55d42b27c170bd2391988c67aa24fc8", + "extract_command": "tar -C backend -xf", + "exclude_files": [ + "bin/bitcore-qt", + "bin/test_bitcore-qt", + "bin/bench_bitcore", + "bin/test_bitcore" + ], + "exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcored -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": { + "whitelist": "127.0.0.1" + } + }, + "blockbook": { + "package_name": "blockbook-bitcore", + "system_user": "blockbook-bitcore", + "internal_binding_template": ":{{.Ports.BlockbookInternal}}", + "public_binding_template": ":{{.Ports.BlockbookPublic}}", + "explorer_url": "", + "additional_params": "", + "block_chain": { + "parse": true, + "mempool_workers": 8, + "mempool_sub_workers": 2, + "block_addresses_to_keep": 300, + "additional_params": { + "fiat_rates": "coingecko", + "fiat_rates_params": "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"bitcore\", \"periodSeconds\": 60}" + } + } + }, + "meta": { + "package_maintainer": "LIMXTEC", + "package_maintainer_email": "info@bitcore.cc" + } +} diff --git a/docs/ports.md b/docs/ports.md index 0c63c18b..c60b0f9a 100644 --- a/docs/ports.md +++ b/docs/ports.md @@ -26,6 +26,7 @@ | Koto | 9051 | 9151 | 8051 | 38351 | | Bellcoin | 9052 | 9152 | 8052 | 38352 | | NULS | 9053 | 9153 | 8053 | 38353 | +| Bitcore | 9054 | 9154 | 8054 | 38354 | | Viacoin | 9055 | 9155 | 8055 | 38355 | | VIPSTARCOIN | 9056 | 9156 | 8056 | 38356 | | MonetaryUnit | 9057 | 9157 | 8057 | 38357 | diff --git a/tests/rpc/testdata/bitcore.json b/tests/rpc/testdata/bitcore.json new file mode 100644 index 00000000..6af141dc --- /dev/null +++ b/tests/rpc/testdata/bitcore.json @@ -0,0 +1,46 @@ +{ + "blockHeight": 326137, + "blockHash": "e55c2494163b9c0fa52fdc94deaf69edb9c391c0de8831b036c84a5576e9bb4d", + "blockTime": 1547896069, + "blockTxs": [ + "a64bb0b727a8c726773f4d90c8844e4d67723002a02d0640dec9d6df81b1b8c0", + "77d9f84476e40fa48b2206e734f718d35dfd86911b945944ee05160699739c8b", + "fcd4f2e45787a33571bc9b2ce939d6e8e51fa053296de9240f05455702bd9540" + ], + "txDetails": { + "fcd4f2e45787a33571bc9b2ce939d6e8e51fa053296de9240f05455702bd9540": { + "hex": "0200000001f69bd1fd76e52a426f21332e3b7cfbc3350eacbd21c6e0c11a7ae11919803ef0010000006b483045022100d1fa62b9d7860a03e1dcd4734fe42457cb508ebb49e896d7a77748d997d09fba022005f1657b39451afe97076d8667fe5f6f18ca76391521ab84d09d5b82137d933b0121035aaf032f13761f27465467dc73f1998a80dd4d85a6353d2832a7244d7b591d3effffffff02a87322b3010000001976a914d0c320db3fbd0abe2b6fe31a3bca4fed8ce8669588ac94b94f37000000001976a9145584ee07090af59938e991c9d8e9e945c99a449f88ac00000000", + "txid": "fcd4f2e45787a33571bc9b2ce939d6e8e51fa053296de9240f05455702bd9540", + "blocktime": 1547896069, + "time": 1547896069, + "locktime": 0, + "version": 2, + "vin": [ + { + "txid": "f03e801919e17a1ac1e0c621bdac0e35c3fb7c3b2e33216f422ae576fdd19bf6", + "vout": 1, + "scriptSig": { + "hex": "483045022100d1fa62b9d7860a03e1dcd4734fe42457cb508ebb49e896d7a77748d997d09fba022005f1657b39451afe97076d8667fe5f6f18ca76391521ab84d09d5b82137d933b0121035aaf032f13761f27465467dc73f1998a80dd4d85a6353d2832a7244d7b591d3e" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 73.00346792, + "n": 0, + "scriptPubKey": { + "hex": "76a914d0c320db3fbd0abe2b6fe31a3bca4fed8ce8669588ac" + } + }, + { + "value": 9.27971732, + "n": 1, + "scriptPubKey": { + "hex": "76a9145584ee07090af59938e991c9d8e9e945c99a449f88ac" + } + } + ] + } + } +} diff --git a/tests/sync/testdata/bitcore.json b/tests/sync/testdata/bitcore.json new file mode 100644 index 00000000..c183c72a --- /dev/null +++ b/tests/sync/testdata/bitcore.json @@ -0,0 +1,165 @@ +{ + "connectBlocks": { + "syncRanges": [ + {"lower": 322212, "upper": 322232} + ], + "blocks": { + "322230": { + "height": 322230, + "hash": "7c5a032930a9e0250cc976a70cbc633b440e569f45b53c77b2c1ad3438430add", + "noTxs": 3, + "txDetails": [ + { + "txid": "54d2eacdd9aa1f91e9829dbbbfa1a9a9cb3dda75d5f7e134accccdf1c5b4b53c", + "version": 2, + "vin": [ + { + "txid": "36ca6b110a6e96c302e5d93d5ba7547e902a42d614e3e365cc0049dcb6f2cd06", + "vout": 1, + "scriptSig": { + "hex": "483045022100dbfc804b9fddb122b0b85e126786ce4be8bdec7cc74ae5c559ff47005947af5b02201d06c5bb13127170ee4002f28048f216c7b07359eec87c7c5d893ee709c2aff60121026c05efaacc255d07782f83d1b7ce948ecbf406adf0ff95454daa21a7ed2eaa62" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 549.9939726, + "n": 0, + "scriptPubKey": { + "hex": "76a9143bb26a2427f9790ff0e7afdecd3460cf59aa81d688ac" + } + }, + { + "value": 50.00000000, + "n": 1, + "scriptPubKey": { + "hex": "76a914bb36447fe1acc280e0304d00cf25772413b9954d88ac" + } + } + ], + "hex": "020000000106cdf2b6dc4900cc65e3e314d6422a907e54a75b3dd9e502c3966e0a116bca36010000006b483045022100dbfc804b9fddb122b0b85e126786ce4be8bdec7cc74ae5c559ff47005947af5b02201d06c5bb13127170ee4002f28048f216c7b07359eec87c7c5d893ee709c2aff60121026c05efaacc255d07782f83d1b7ce948ecbf406adf0ff95454daa21a7ed2eaa62feffffff028c3338ce0c0000001976a9143bb26a2427f9790ff0e7afdecd3460cf59aa81d688ac00f2052a010000001976a914bb36447fe1acc280e0304d00cf25772413b9954d88acb5ea0400", + "time": 1547300769, + "blocktime": 1547300769 + }, + { + "txid": "2506225de845f0a4078987c1aab115b6f08eaa6d08f76be0aa61ce9a3a86eabc", + "version": 2, + "vin": [ + { + "txid": "fbb10919a1cca68bafe4a2a9a09cd23e00231d84d0e6c010f31c962250921751", + "vout": 1, + "scriptSig": { + "hex": "4830450221009afeedd0eed56bd6bd2c1e361b811ce094659ca178a401af3e0aeae23748a66802206f29e6f7961f0e13bb5626d7c2393ead75642091187aa5c454427a7f4b2d9d1d012103bf507caf97b107e35ba894bd51fe677a5f4dd7a9523d54d58d622604e7a0099c" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 299.99729859, + "n": 0, + "scriptPubKey": { + "hex": "76a914cbd6c5e94d9ce8520ba81f32c74e02fc0b36c98588ac" + } + }, + { + "value": 50.00000000, + "n": 1, + "scriptPubKey": { + "hex": "76a914bb36447fe1acc280e0304d00cf25772413b9954d88ac" + } + } + ], + "hex": "02000000015117925022961cf310c0e6d0841d23003ed29ca0a9a2e4af8ba6cca11909b1fb010000006b4830450221009afeedd0eed56bd6bd2c1e361b811ce094659ca178a401af3e0aeae23748a66802206f29e6f7961f0e13bb5626d7c2393ead75642091187aa5c454427a7f4b2d9d1d012103bf507caf97b107e35ba894bd51fe677a5f4dd7a9523d54d58d622604e7a0099cfeffffff02c38c1ffc060000001976a914cbd6c5e94d9ce8520ba81f32c74e02fc0b36c98588ac00f2052a010000001976a914bb36447fe1acc280e0304d00cf25772413b9954d88acb5ea0400", + "blockhash": "7c5a032930a9e0250cc976a70cbc633b440e569f45b53c77b2c1ad3438430add", + "confirmations": 4126, + "time": 1547300769, + "blocktime": 1547300769 + } + ] + }, + "322214": { + "height": 322214, + "hash": "4ef7b0e81593fe596d2007755b7b9536a650367cd2faac20c109fe59692435e7", + "noTxs": 4, + "txDetails": [ + { + "txid": "7dc1059cb5824758a256c0e637e7282a97557b77d1d19c0862e3c909d48a3235", + "version": 2, + "vin": [ + { + "txid": "a6793b708e5b8fb0d4ac641e20f5f6ede4528c70946a64121459aad446d7c5c3", + "vout": 0, + "scriptSig": { + "hex": "47304402206951c77f111798349509b29ac05f0b4b12e31b08a5af63dbee53736ddbe4144a02205c8049556deadd2452e0cd0ac418402a641b9b94bae2a4d41e04ac755c658afd012102d9b6098eacbb5a58f984c76d75c99b6bfc0fae73590f946a6a4c2634acf8cc8e" + }, + "sequence": 4294967294 + }, + { + "txid": "5a1bdefc5a4f9b7074ae46893a2d8e908ecad01986519ffe7b8c97de489f33d9", + "vout": 1, + "scriptSig": { + "hex": "4730440220705673f1cbf506177ae65dafe87083df2aefc8f3652bfe367031252d41897a810220554082d80ed46c1f831cb33c50aaf9390b0c83f4a02955b3048958cb2a9f36cd012102532ad08c8e2084f3a4811fac622dff01dded81ee3ef200d3e7efbccce1f52d60" + }, + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 3.12682838, + "n": 0, + "scriptPubKey": { + "hex": "76a914ff65ae5ed06457a560130eb33befb79b7240807888ac" + } + }, + { + "value": 0.01459703, + "n": 1, + "scriptPubKey": { + "hex": "76a914cff0d08dd8853b20d0ecefa3a48452157a54e1ac88ac" + } + } + ], + "hex": "0200000002c3c5d746d4aa591412646a94708c52e4edf6f5201e64acd4b08f5b8e703b79a6000000006a47304402206951c77f111798349509b29ac05f0b4b12e31b08a5af63dbee53736ddbe4144a02205c8049556deadd2452e0cd0ac418402a641b9b94bae2a4d41e04ac755c658afd012102d9b6098eacbb5a58f984c76d75c99b6bfc0fae73590f946a6a4c2634acf8cc8efeffffffd9339f48de978c7bfe9f518619d0ca8e908e2d3a8946ae74709b4f5afcde1b5a010000006a4730440220705673f1cbf506177ae65dafe87083df2aefc8f3652bfe367031252d41897a810220554082d80ed46c1f831cb33c50aaf9390b0c83f4a02955b3048958cb2a9f36cd012102532ad08c8e2084f3a4811fac622dff01dded81ee3ef200d3e7efbccce1f52d60feffffff025629a312000000001976a914ff65ae5ed06457a560130eb33befb79b7240807888acf7451600000000001976a914cff0d08dd8853b20d0ecefa3a48452157a54e1ac88aca5ea0400", + "time": 1547296216, + "blocktime": 1547296216 + } + ] + } + } + }, + "handleFork": { + "syncRanges": [ + {"lower": 322225, "upper": 322232} + ], + "fakeBlocks": { + "322230": { + "height": 322230, + "hash": "39918a9e2be1ee0b67b0cdee18d5fa23c24e8770c19a2deeaf9782eb8d2e3803" + }, + "322231": { + "height": 322231, + "hash": "6f796caa1d61b44e4c149a12b7ba9fa11db58293642f620bf94c96a39667d7ba" + }, + "322232": { + "height": 322232, + "hash": "d41f4d45ba4bb1659674932183de4f9a26bfcf0df484e3fd70e75a475b85d038" + } + }, + "realBlocks": { + "322230": { + "height": 322230, + "hash": "7c5a032930a9e0250cc976a70cbc633b440e569f45b53c77b2c1ad3438430add" + }, + "322231": { + "height": 322231, + "hash": "a737e20511e55fe6b696475cc8c5ce43acb6bff49ce8eb09bf838bcdd0f49ccd" + }, + "322232": { + "height": 322232, + "hash": "7c3a4671c8faf59b35fcaa91a33a9e24cd24714b22e40c2b8e3e3c82410c991d" + } + } + } +} diff --git a/tests/tests.json b/tests/tests.json index 7f935426..213a1aa3 100644 --- a/tests/tests.json +++ b/tests/tests.json @@ -27,6 +27,11 @@ "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] }, + "bitcore": { + "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", + "EstimateSmartFee", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"], + "sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"] + }, "cpuchain": { "rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee", "EstimateFee"],