add support for eCash (#731)

This commit is contained in:
Pierre K 2022-03-23 10:01:55 +01:00 committed by GitHub
parent 05baef7035
commit 6ca53f69f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1175 additions and 1 deletions

View File

@ -24,6 +24,7 @@ import (
"github.com/trezor/blockbook/bchain/coins/digibyte"
"github.com/trezor/blockbook/bchain/coins/divi"
"github.com/trezor/blockbook/bchain/coins/dogecoin"
"github.com/trezor/blockbook/bchain/coins/ecash"
"github.com/trezor/blockbook/bchain/coins/eth"
"github.com/trezor/blockbook/bchain/coins/firo"
"github.com/trezor/blockbook/bchain/coins/flo"
@ -124,6 +125,7 @@ func init() {
BlockChainFactories["Omotenashicoin Testnet"] = omotenashicoin.NewOmotenashiCoinRPC
BlockChainFactories["BitZeny"] = bitzeny.NewBitZenyRPC
BlockChainFactories["Trezarcoin"] = trezarcoin.NewTrezarcoinRPC
BlockChainFactories["ECash"] = ecash.NewECashRPC
}
// GetCoinNameFromConfig gets coin name and coin shortcut from config file

View File

@ -0,0 +1,189 @@
package ecash
import (
"fmt"
"github.com/pirk/ecashutil"
"github.com/martinboehm/btcutil"
"github.com/martinboehm/btcutil/chaincfg"
"github.com/martinboehm/btcutil/txscript"
"github.com/pirk/ecashaddr-converter/address"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/btc"
)
// AddressFormat type is used to specify different formats of address
type AddressFormat = uint8
const (
// Legacy AddressFormat is the same as Bitcoin
Legacy AddressFormat = iota
// CashAddr AddressFormat is new eCash standard
CashAddr
)
const (
// MainNetPrefix is CashAddr prefix for mainnet
MainNetPrefix = "ecash:"
// TestNetPrefix is CashAddr prefix for testnet
TestNetPrefix = "ectest:"
// RegTestPrefix is CashAddr prefix for regtest
RegTestPrefix = "ecreg:"
)
var (
// MainNetParams are parser parameters for mainnet
MainNetParams chaincfg.Params
// TestNetParams are parser parameters for testnet
TestNetParams chaincfg.Params
// RegtestParams are parser parameters for regtest
RegtestParams chaincfg.Params
)
func init() {
MainNetParams = chaincfg.MainNetParams
MainNetParams.Net = ecashutil.MainnetMagic
TestNetParams = chaincfg.TestNet3Params
TestNetParams.Net = ecashutil.TestnetMagic
RegtestParams = chaincfg.RegressionNetParams
RegtestParams.Net = ecashutil.Regtestmagic
}
// ECashParser handle
type ECashParser struct {
*btc.BitcoinLikeParser
AddressFormat AddressFormat
}
// NewECashParser returns new ECashParser instance
func NewECashParser(params *chaincfg.Params, c *btc.Configuration) (*ECashParser, error) {
var format AddressFormat
switch c.AddressFormat {
case "":
fallthrough
case "cashaddr":
format = CashAddr
case "legacy":
format = Legacy
default:
return nil, fmt.Errorf("Unknown address format: %s", c.AddressFormat)
}
p := &ECashParser{
BitcoinLikeParser: btc.NewBitcoinLikeParser(params, c),
AddressFormat: format,
}
p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
p.AmountDecimalPoint = 2
return p, nil
}
// GetChainParams contains network parameters for the main eCash network,
// the regression test eCash network, the test eCash network and
// the simulation test eCash 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
}
}
// GetAddrDescFromAddress returns internal address representation of given address
func (p *ECashParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) {
return p.addressToOutputScript(address)
}
// addressToOutputScript converts address to ScriptPubKey
func (p *ECashParser) addressToOutputScript(address string) ([]byte, error) {
if isCashAddr(address) {
da, err := ecashutil.DecodeAddress(address, p.Params)
if err != nil {
return nil, err
}
script, err := ecashutil.PayToAddrScript(da)
if err != nil {
return nil, err
}
return script, nil
}
da, err := btcutil.DecodeAddress(address, p.Params)
if err != nil {
return nil, err
}
script, err := txscript.PayToAddrScript(da)
if err != nil {
return nil, err
}
return script, nil
}
func isCashAddr(addr string) bool {
n := len(addr)
switch {
case n > len(MainNetPrefix) && addr[0:len(MainNetPrefix)] == MainNetPrefix:
return true
case n > len(TestNetPrefix) && addr[0:len(TestNetPrefix)] == TestNetPrefix:
return true
case n > len(RegTestPrefix) && addr[0:len(RegTestPrefix)] == RegTestPrefix:
return true
}
return false
}
// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
func (p *ECashParser) outputScriptToAddresses(script []byte) ([]string, bool, error) {
// convert possible P2PK script to P2PK, which ecashutil can process
var err error
script, err = txscript.ConvertP2PKtoP2PKH(p.Params.Base58CksumHasher, script)
if err != nil {
return nil, false, err
}
a, err := ecashutil.ExtractPkScriptAddrs(script, p.Params)
if err != nil {
// do not return unknown script type error as error
if err.Error() == "unknown script type" {
// try OP_RETURN script
or := p.TryParseOPReturn(script)
if or != "" {
return []string{or}, false, nil
}
return []string{}, false, nil
}
return nil, false, err
}
// EncodeAddress returns CashAddr address
addr := a.EncodeAddress()
if p.AddressFormat == Legacy {
da, err := address.NewFromString(addr)
if err != nil {
return nil, false, err
}
ca, err := da.Legacy()
if err != nil {
return nil, false, err
}
addr, err = ca.Encode()
if err != nil {
return nil, false, err
}
}
return []string{addr}, len(addr) > 0, nil
}

View File

@ -0,0 +1,353 @@
//go:build unittest
package ecash
import (
"encoding/hex"
"math/big"
"os"
"reflect"
"testing"
"github.com/martinboehm/btcutil/chaincfg"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/btc"
)
func TestMain(m *testing.M) {
c := m.Run()
chaincfg.ResetParams()
os.Exit(c)
}
func Test_GetAddrDescFromAddress(t *testing.T) {
mainParserCashAddr, mainParserLegacy, testParserCashAddr, _ := setupParsers(t)
tests := []struct {
name string
parser *ECashParser
addresses []string
hex string
wantErr bool
}{
{
name: "test-P2PKH-0",
parser: testParserCashAddr,
addresses: []string{"mnnAKPTSrWjgoi3uEYaQkHA1QEC5btFeBr"},
hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac",
wantErr: false,
},
{
name: "test-P2PKH-1",
parser: testParserCashAddr,
addresses: []string{"ectest:qp86jfla8084048rckpv85ht90falr050s59h7rejp"},
hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac",
wantErr: false,
},
{
name: "main-P2PKH-0",
parser: mainParserLegacy,
addresses: []string{"129HiRqekqPVucKy2M8zsqvafGgKypciPp"},
hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac",
wantErr: false,
},
{
name: "main-P2PKH-1",
parser: mainParserCashAddr,
addresses: []string{"ecash:qqxgjelx8qk85t9xfk8g2zlunxmhxms6p5dtfghs9r"},
hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac",
wantErr: false,
},
{
name: "main-P2SH-0",
parser: mainParserCashAddr,
addresses: []string{"3EBEFWPtDYWCNszQ7etoqtWmmygccayLiH"},
hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787",
wantErr: false,
},
{
name: "main-P2SH-1",
parser: mainParserLegacy,
addresses: []string{"ecash:pzy0wuj9pjps5v8dmlwq32fatu4wrgcwzuyf5lgn3q"},
hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.parser.GetAddrDescFromAddress(tt.addresses[0])
if (err != nil) != tt.wantErr {
t.Errorf("%v", tt.addresses[0])
t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
return
}
h := hex.EncodeToString(got)
if !reflect.DeepEqual(h, tt.hex) {
t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.hex)
}
})
}
}
func Test_GetAddressesFromAddrDesc(t *testing.T) {
mainParserCashAddr, mainParserLegacy, testParserCashAddr, testParserLegacy := setupParsers(t)
tests := []struct {
name string
parser *ECashParser
addresses []string
searchable bool
hex string
wantErr bool
}{
{
name: "test-P2PKH-0",
parser: testParserLegacy,
addresses: []string{"mnnAKPTSrWjgoi3uEYaQkHA1QEC5btFeBr"},
searchable: true,
hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac",
wantErr: false,
},
{
name: "test-P2PKH-1",
parser: testParserCashAddr,
addresses: []string{"ectest:qp86jfla8084048rckpv85ht90falr050s59h7rejp"},
searchable: true,
hex: "76a9144fa927fd3bcf57d4e3c582c3d2eb2bd3df8df47c88ac",
wantErr: false,
},
{
name: "main-P2PKH-0",
parser: mainParserLegacy,
addresses: []string{"129HiRqekqPVucKy2M8zsqvafGgKypciPp"},
searchable: true,
hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac",
wantErr: false,
},
{
name: "main-P2PKH-0",
parser: mainParserCashAddr,
addresses: []string{"ecash:qqxgjelx8qk85t9xfk8g2zlunxmhxms6p5dtfghs9r"},
searchable: true,
hex: "76a9140c8967e6382c7a2ca64d8e850bfc99b7736e1a0d88ac",
wantErr: false,
},
{
name: "main-P2SH-0",
parser: mainParserLegacy,
addresses: []string{"3EBEFWPtDYWCNszQ7etoqtWmmygccayLiH"},
searchable: true,
hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787",
wantErr: false,
},
{
name: "main-P2SH-1",
parser: mainParserCashAddr,
addresses: []string{"ecash:pzy0wuj9pjps5v8dmlwq32fatu4wrgcwzuyf5lgn3q"},
searchable: true,
hex: "a91488f772450c830a30eddfdc08a93d5f2ae1a30e1787",
wantErr: false,
},
{
name: "main-P2PK",
parser: mainParserCashAddr,
addresses: []string{"ecash:qqr95pwp0w5jqnh9vcjl4qm4x45atr0er587pw66cr"},
searchable: true,
hex: "2103db3c3977c5165058bf38c46f72d32f4e872112dbafc13083a948676165cd1603ac",
wantErr: false,
},
{
name: "OP_RETURN ascii",
parser: mainParserCashAddr,
addresses: []string{"OP_RETURN (ahoj)"},
searchable: false,
hex: "6a0461686f6a",
wantErr: false,
},
{
name: "OP_RETURN hex",
parser: mainParserCashAddr,
addresses: []string{"OP_RETURN 2020f1686f6a20"},
searchable: false,
hex: "6a072020f1686f6a20",
wantErr: false,
},
{
name: "empty",
parser: mainParserCashAddr,
addresses: []string{},
searchable: false,
hex: "",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.hex)
got, got2, err := tt.parser.GetAddressesFromAddrDesc(b)
if (err != nil) != tt.wantErr {
t.Errorf("GetAddressesFromAddrDesc() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.addresses) {
t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got, tt.addresses)
}
if !reflect.DeepEqual(got2, tt.searchable) {
t.Errorf("GetAddressesFromAddrDesc() = %v, want %v", got2, tt.searchable)
}
})
}
}
var (
testTx1, testTx2 bchain.Tx
testTxPacked1 = "0001e2408ba8d7af5401000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700"
testTxPacked2 = "0007c91a899ab7da6a010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000"
)
func setupParsers(t *testing.T) (mainParserCashAddr, mainParserLegacy, testParserCashAddr, testParserLegacy *ECashParser) {
parser1, err := NewECashParser(GetChainParams("main"), &btc.Configuration{AddressFormat: "cashaddr"})
if err != nil {
t.Fatalf("NewECashParser() error = %v", err)
}
parser2, err := NewECashParser(GetChainParams("main"), &btc.Configuration{AddressFormat: "legacy"})
if err != nil {
t.Fatalf("NewECashParser() error = %v", err)
}
parser3, err := NewECashParser(GetChainParams("test"), &btc.Configuration{AddressFormat: "cashaddr"})
if err != nil {
t.Fatalf("NewECashParser() error = %v", err)
}
parser4, err := NewECashParser(GetChainParams("test"), &btc.Configuration{AddressFormat: "legacy"})
if err != nil {
t.Fatalf("NewECashParser() error = %v", err)
}
return parser1, parser2, parser3, parser4
}
func init() {
testTx1 = bchain.Tx{
Hex: "01000000017f9a22c9cbf54bd902400df746f138f37bcf5b4d93eb755820e974ba43ed5f42040000006a4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80feffffff019c9700000000000017a9146144d57c8aff48492c9dfb914e120b20bad72d6f8773d00700",
Blocktime: 1519053802,
Txid: "056e3d82e5ffd0e915fb9b62797d76263508c34fe3e5dbed30dd3e943930f204",
LockTime: 512115,
Version: 1,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: "4730440220037f4ed5427cde81d55b9b6a2fd08c8a25090c2c2fff3a75c1a57625ca8a7118022076c702fe55969fa08137f71afd4851c48e31082dd3c40c919c92cdbc826758d30121029f6da5623c9f9b68a9baf9c1bc7511df88fa34c6c2f71f7c62f2f03ff48dca80",
},
Txid: "425fed43ba74e9205875eb934d5bcf7bf338f146f70d4002d94bf5cbc9229a7f",
Vout: 4,
Sequence: 4294967294,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(38812),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a9146144d57c8aff48492c9dfb914e120b20bad72d6f87",
Addresses: []string{
"ecash:pps5f4tu3tl5sjfvnhaeznsjpvst44eddu3yvcmmzj",
},
},
},
},
}
testTx2 = bchain.Tx{
Hex: "010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000",
Blocktime: 1235678901,
Txid: "474e6795760ebe81cb4023dc227e5a0efe340e1771c89a0035276361ed733de7",
LockTime: 0,
Version: 1,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: "160014550da1f5d25a9dae2eafd6902b4194c4c6500af6",
},
Txid: "c13e32a4428e31f85d7aee4ec7344504b12e72aaffcbde0160200d2ac7f0649d",
Vout: 0,
Sequence: 4294967295,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(10000000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914cd668d781ece600efa4b2404dc91fd26b8b8aed887",
Addresses: []string{
"ectest:prxkdrtcrm8xqrh6fvjqfhy3l5nt3w9wmq7a4ujkec",
},
},
},
{
ValueSat: *big.NewInt(920081157),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a87",
Addresses: []string{
"ectest:pqjxv4dah42v0erh6r4zxa0gdcxm9w8cpg55qt4qtq",
},
},
},
},
}
}
func Test_UnpackTx(t *testing.T) {
mainParser, _, testParser, _ := setupParsers(t)
type args struct {
packedTx string
parser *ECashParser
}
tests := []struct {
name string
args args
want *bchain.Tx
want1 uint32
wantErr bool
}{
{
name: "ecash-1",
args: args{
packedTx: testTxPacked1,
parser: mainParser,
},
want: &testTx1,
want1: 123456,
wantErr: false,
},
{
name: "testnet-1",
args: args{
packedTx: testTxPacked2,
parser: testParser,
},
want: &testTx2,
want1: 510234,
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)
}
})
}
}

View File

@ -0,0 +1,207 @@
package ecash
import (
"encoding/hex"
"encoding/json"
"math/big"
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/pirk/ecashutil"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/btc"
)
// ECashRPC is an interface to JSON-RPC bitcoind service.
type ECashRPC struct {
*btc.BitcoinRPC
}
// NewECashRPC returns new ECashRPC instance.
func NewECashRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
b, err := btc.NewBitcoinRPC(config, pushHandler)
if err != nil {
return nil, err
}
s := &ECashRPC{
b.(*btc.BitcoinRPC),
}
s.ChainConfig.SupportsEstimateSmartFee = false
return s, nil
}
// Initialize initializes ECashRPC instance.
func (b *ECashRPC) Initialize() error {
ci, err := b.GetChainInfo()
if err != nil {
return err
}
chainName := ci.Chain
params := GetChainParams(chainName)
// always create parser
b.Parser, err = NewECashParser(params, b.ChainConfig)
if err != nil {
return err
}
// parameters for getInfo request
if params.Net == ecashutil.MainnetMagic {
b.Testnet = false
b.Network = "livenet"
} else {
b.Testnet = true
b.Network = "testnet"
}
glog.Info("rpc: block chain ", params.Name)
return nil
}
// getblock
type cmdGetBlock struct {
Method string `json:"method"`
Params struct {
BlockHash string `json:"blockhash"`
Verbose bool `json:"verbose"`
} `json:"params"`
}
// estimatesmartfee
type cmdEstimateSmartFee struct {
Method string `json:"method"`
Params struct {
Blocks int `json:"nblocks"`
} `json:"params"`
}
// GetBlock returns block with given hash.
func (b *ECashRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
var err error
if hash == "" && height > 0 {
hash, err = b.GetBlockHash(height)
if err != nil {
return nil, err
}
}
header, err := b.GetBlockHeader(hash)
if err != nil {
return nil, err
}
data, err := b.GetBlockBytes(hash)
if err != nil {
return nil, err
}
block, err := b.Parser.ParseBlock(data)
if err != nil {
return nil, errors.Annotatef(err, "hash %v", hash)
}
// size is not returned by GetBlockHeader and would be overwritten
size := block.Size
block.BlockHeader = *header
block.Size = size
return block, nil
}
// GetBlockRaw returns block with given hash as bytes.
func (b *ECashRPC) GetBlockRaw(hash string) (string, error) {
glog.V(1).Info("rpc: getblock (verbose=0) ", hash)
res := btc.ResGetBlockRaw{}
req := cmdGetBlock{Method: "getblock"}
req.Params.BlockHash = hash
req.Params.Verbose = false
err := b.Call(&req, &res)
if err != nil {
return "", errors.Annotatef(err, "hash %v", hash)
}
if res.Error != nil {
if isErrBlockNotFound(res.Error) {
return "", bchain.ErrBlockNotFound
}
return "", errors.Annotatef(res.Error, "hash %v", hash)
}
return res.Result, nil
}
// GetBlockBytes returns block with given hash as bytes
func (b *ECashRPC) GetBlockBytes(hash string) ([]byte, error) {
block, err := b.GetBlockRaw(hash)
if err != nil {
return nil, err
}
return hex.DecodeString(block)
}
// GetBlockInfo returns extended header (more info than in bchain.BlockHeader) with a list of txids
func (b *ECashRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
glog.V(1).Info("rpc: getblock (verbosity=1) ", hash)
res := btc.ResGetBlockInfo{}
req := cmdGetBlock{Method: "getblock"}
req.Params.BlockHash = hash
req.Params.Verbose = true
err := b.Call(&req, &res)
if err != nil {
return nil, errors.Annotatef(err, "hash %v", hash)
}
if res.Error != nil {
if isErrBlockNotFound(res.Error) {
return nil, bchain.ErrBlockNotFound
}
return nil, errors.Annotatef(res.Error, "hash %v", hash)
}
return &res.Result, nil
}
// GetBlockFull returns block with given hash.
func (b *ECashRPC) GetBlockFull(hash string) (*bchain.Block, error) {
return nil, errors.New("Not implemented")
}
func isErrBlockNotFound(err *bchain.RPCError) bool {
return err.Message == "Block not found" ||
err.Message == "Block height out of range"
}
// EstimateFee returns fee estimation
func (b *ECashRPC) EstimateFee(blocks int) (big.Int, error) {
glog.V(1).Info("rpc: estimatefee ", blocks)
res := btc.ResEstimateFee{}
req := struct {
Method string `json:"method"`
}{
Method: "estimatefee",
}
err := b.Call(&req, &res)
var r big.Int
if err != nil {
return r, err
}
if res.Error != nil {
return r, res.Error
}
r, err = b.Parser.AmountToBigInt(res.Result)
if err != nil {
return r, err
}
return r, nil
}
// EstimateSmartFee returns fee estimation
func (b *ECashRPC) EstimateSmartFee(blocks int, conservative bool) (big.Int, error) {
// EstimateSmartFee is not supported by ecash
return b.EstimateFee(blocks)
}

69
configs/coins/ecash.json Normal file
View File

@ -0,0 +1,69 @@
{
"coin": {
"name": "ECash",
"shortcut": "XEC",
"label": "eCash",
"alias": "ecash"
},
"ports": {
"backend_rpc": 8097,
"backend_message_queue": 38397,
"blockbook_internal": 9097,
"blockbook_public": 9197
},
"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-ecash",
"package_revision": "satoshilabs-1",
"system_user": "ecash",
"version": "0.25.1",
"binary_url": "https://download.bitcoinabc.org/0.25.1/linux/bitcoin-abc-0.25.1-x86_64-linux-gnu.tar.gz",
"verification_type": "sha256",
"verification_source": "295183578ce67444fd6a504d2dcb85d07345454881ba4db5f52d82dd3a659bed",
"extract_command": "tar -C backend --strip 1 -xf",
"exclude_files": [
"bin/bitcoin-qt"
],
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/bitcoind -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": "bcash.conf",
"client_config_file": "bitcoin_like_client.conf"
},
"blockbook": {
"package_name": "blockbook-ecash",
"system_user": "blockbook-ecash",
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
"explorer_url": "",
"additional_params": "",
"block_chain": {
"parse": true,
"subversion": "/Bitcoin ABC:0.24.9(EB32.0)/",
"address_format": "cashaddr",
"mempool_workers": 8,
"mempool_sub_workers": 2,
"block_addresses_to_keep": 300,
"xpub_magic": 76067358,
"slip44": 899,
"additional_params": {
"fiat_rates": "coingecko",
"fiat_rates_params": "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"ecash\", \"periodSeconds\": 60}"
}
}
},
"meta": {
"package_maintainer": "eCash",
"package_maintainer_email": "contact@e.cash"
}
}

View File

@ -45,6 +45,7 @@
| Omotenashicoin | 9094 | 9194 | 8094 | 38394 |
| BitZeny | 9095 | 9195 | 8095 | 38395 |
| Trezarcoin | 9096 | 9196 | 8096 | 38396 |
| eCash | 9097 | 9197 | 8097 | 38397 |
| Bitcoin Signet | 19020 | 19120 | 18020 | 48320 |
| Bitcoin Regtest | 19021 | 19121 | 18021 | 48321 |
| Ethereum Goerli | 19026 | 19126 | 18026 | 48326 p2p |
@ -55,7 +56,7 @@
| Litecoin Testnet | 19034 | 19134 | 18034 | 48334 |
| Bitcoin Gold Testnet | 19035 | 19135 | 18035 | 48335 |
| Ethereum Ropsten | 19036 | 19136 | 18036 | 48336 p2p |
| Dogecoin Testnet | 19038 | 19138 | 18038 | 48338
| Dogecoin Testnet | 19038 | 19138 | 18038 | 48338 |
| Vertcoin Testnet | 19040 | 19140 | 18040 | 48340 |
| Monacoin Testnet | 19041 | 19141 | 18041 | 48341 |
| DigiByte Testnet | 19042 | 19142 | 18042 | 48342 |

3
go.mod
View File

@ -33,6 +33,8 @@ require (
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pebbe/zmq4 v1.2.1
github.com/pirk/ecashaddr-converter v0.0.0-20220121162910-c6cb45163b29
github.com/pirk/ecashutil v0.0.0-20220124103933-d37f548d249e
github.com/prometheus/client_golang v1.8.0
github.com/schancel/cashaddr-converter v0.0.0-20181111022653-4769e7add95a
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
@ -41,6 +43,7 @@ require (
)
require (
github.com/PiRK/cashaddr-converter v0.0.0-20220121162910-c6cb45163b29 // indirect
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
github.com/beorn7/perks v1.0.1 // indirect

6
go.sum
View File

@ -38,6 +38,8 @@ github.com/Groestlcoin/go-groestl-hash v0.0.0-20181012171753-790653ac190c h1:8bY
github.com/Groestlcoin/go-groestl-hash v0.0.0-20181012171753-790653ac190c/go.mod h1:DwgC62sAn4RgH4L+O8REgcE7f0XplHPNeRYFy+ffy1M=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PiRK/cashaddr-converter v0.0.0-20220121162910-c6cb45163b29 h1:B11BryeZQ1LrAzzM0lCpblwleB7SyxPfvN2AsNbyvQc=
github.com/PiRK/cashaddr-converter v0.0.0-20220121162910-c6cb45163b29/go.mod h1:+39XiGr9m9TPY49sG4XIH5CVaRxHGFWT0U4MOY6dy3o=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
@ -499,6 +501,10 @@ github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssy
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pirk/ecashaddr-converter v0.0.0-20220121162910-c6cb45163b29 h1:awILOeL107zIYvPB1zhkz6ZTp0AaMpLGMoV16DMairA=
github.com/pirk/ecashaddr-converter v0.0.0-20220121162910-c6cb45163b29/go.mod h1:ATZjpmb9u55Kcrd5M/ca/40H73BZLhduMzCmGwpfWw0=
github.com/pirk/ecashutil v0.0.0-20220124103933-d37f548d249e h1:WrnL52yXO0jNpHC7UbthJl9mnHPHY7bW3xzmWIuWzh8=
github.com/pirk/ecashutil v0.0.0-20220124103933-d37f548d249e/go.mod h1:y/B3gomTdd1s23RvcBij/X738fcTobeupT30EhV6nPE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

92
tests/rpc/testdata/ecash.json vendored Normal file
View File

@ -0,0 +1,92 @@
{
"blockHeight": 723621,
"blockHash": "0000000000000000016ee40672952698db9a72054014077e8065d0ed3843be38",
"blockTime": 1643027028,
"blockTxs": [
"79a716de966042dedb1294e662c4340fcc121f31fc67d4f37734b6838f7309c4",
"1568e2fcf08ad3eaa0a004f2cb8ca2456ea4c624652843a04f727d984c1c5ea6",
"6ddcf32bdc26f12200a3cc41d9d660bf0afc39ee3f1c94706e202373bcd782d6",
"9057bdf099646b3f28498dd33302a28db5c3556e80593d506f45dfa240206c4b",
"d19abd0ea6b2dfa745c1a194d87b0d621f3d55aa7e1bc53d9d2d7fe44f0e1226",
"d864b206afccff0a37ce6a1bb697a6c6217c537760b291d832ad526a7d94b270",
"ff7cdcf1f3bd5bf7551133309cc466d32caa0cb11860e2ffea5bee8372240b9f"
],
"txDetails": {
"d864b206afccff0a37ce6a1bb697a6c6217c537760b291d832ad526a7d94b270": {
"hex": "0200000001e37114f0c54cb6c6eac13140f38f356784082a289812540e8dc2d5fa81321bbf010000006a473044022064d48cd0549b3c64e4fe012b2a6303856ba44a711c4aa39fd991e071b1e9e46c0220485fde649603a0e1f963d106aa6a34bd2a96756397cee5475ff451385f17f1f441210244810e359356866bfd28729dcc252314f760d6b46c5b430a0f47d805fab44507ffffffff023447de31010000001976a9146e233ca966c8616981bb556999ebe48c39e742a988acb838740f040000001976a914e330f03a2bf6afc5a0e5819f28fde1671d017e8a88ac00000000",
"txid": "d864b206afccff0a37ce6a1bb697a6c6217c537760b291d832ad526a7d94b270",
"blocktime":1643027028,
"time":1643027028,
"locktime": 0,
"version": 2,
"vin": [
{
"txid": "bf1b3281fad5c28d0e541298282a088467358ff34031c1eac6b64cc5f01471e3",
"vout": 1,
"sequence": 4294967295,
"scriptSig": {
"hex": "473044022064d48cd0549b3c64e4fe012b2a6303856ba44a711c4aa39fd991e071b1e9e46c0220485fde649603a0e1f963d106aa6a34bd2a96756397cee5475ff451385f17f1f441210244810e359356866bfd28729dcc252314f760d6b46c5b430a0f47d805fab44507"
}
}
],
"vout": [
{
"value": 51316181,
"n": 0,
"scriptPubKey": {
"hex": "76a9146e233ca966c8616981bb556999ebe48c39e742a988ac"
}
},
{
"value": 174391441.2,
"n": 1,
"scriptPubKey": {
"hex": "76a914e330f03a2bf6afc5a0e5819f28fde1671d017e8a88ac"
}
}
]
},
"ff7cdcf1f3bd5bf7551133309cc466d32caa0cb11860e2ffea5bee8372240b9f": {
"hex": "020000000234a3e9790ac787d2c7276a8e952f25ef76e8c048a56a8effc804363c7708e2e7000000006a4730440220305bcd24adaa24843558fbaed56db3c64d3afab6be533ce92736dcc606de7ade022067f1469cdf17395d2cc30e98b5cc9d448c803ae3d4c121eacefca5698eec5fe5412103398deb450f13c10234d6c5b74d2cdf8dc7c3ce46731815cba3d845facf44e037feffffff67260c8e7f40362980cf491831c0a1753cc263cf9bdad1f689eb2570be592106010000006a47304402203ae38828d2568f1fecd1f2b19e4220e318d0e70c48bf0282538628a4ddea8bdc02200358499ce2e077ae699ecf4fd91bf5878774d1f935eac730d55a19921847e874412103fc530a380acfed725bec8ebc2c686104f0be4e5ba0e64bc8d78bd57580ea3fa8feffffff02a8391400000000001976a914fd14b9272106691a47b8a9c0b661355ffd3f4eaa88acab2a070f000000001976a9145994e1c4b207d0503525e943702ffd820b332f5288aca40a0b00",
"txid": "ff7cdcf1f3bd5bf7551133309cc466d32caa0cb11860e2ffea5bee8372240b9f",
"blocktime":1643027028,
"time":1643027028,
"locktime": 723620,
"version": 2,
"vin": [
{
"txid": "e7e208773c3604c8ff8e6aa548c0e876ef252f958e6a27c7d287c70a79e9a334",
"vout": 0,
"sequence": 4294967294,
"scriptSig": {
"hex": "4730440220305bcd24adaa24843558fbaed56db3c64d3afab6be533ce92736dcc606de7ade022067f1469cdf17395d2cc30e98b5cc9d448c803ae3d4c121eacefca5698eec5fe5412103398deb450f13c10234d6c5b74d2cdf8dc7c3ce46731815cba3d845facf44e037"
}
},
{
"txid": "062159be7025eb89f6d1da9bcf63c23c75a1c0311849cf802936407f8e0c2667",
"vout": 1,
"sequence": 4294967294,
"scriptSig": {
"hex": "47304402203ae38828d2568f1fecd1f2b19e4220e318d0e70c48bf0282538628a4ddea8bdc02200358499ce2e077ae699ecf4fd91bf5878774d1f935eac730d55a19921847e874412103fc530a380acfed725bec8ebc2c686104f0be4e5ba0e64bc8d78bd57580ea3fa8"
}
}
],
"vout": [
{
"value": 13254.8,
"n": 0,
"scriptPubKey": {
"hex": "76a914fd14b9272106691a47b8a9c0b661355ffd3f4eaa88ac"
}
},
{
"value": 2521279.15,
"n": 1,
"scriptPubKey": {
"hex": "76a9145994e1c4b207d0503525e943702ffd820b332f5288ac"
}
}
]
}
}
}

247
tests/sync/testdata/ecash.json vendored Normal file
View File

@ -0,0 +1,247 @@
{
"connectBlocks": {
"syncRanges": [
{"lower": 550716, "upper": 550736}
],
"blocks": {
"550736": {
"height": 550736,
"hash": "00000000000000000181e327d1165480db82d915d46b9d39232526309072e014",
"noTxs": 6,
"txDetails": [
{
"hex": "020000000118a6b44b981cab21e486ee56c8bc74c58d907649842a0088bb0a80f2faa22263010000006b483045022100dea77aa13dcdd457c7bad51e7ee310046a8f8e3c370c25217010db57a60335ca022024937a8c0c179fc8ef9923694b2f7e276904ae859010dd12b46e356ce6d76147412102619a1e932ef161c58f0d8c24fbf6b5b709f8e996aa8caa7a26130240a3416176feffffff0582efe71f000000001976a914ab4c29c2e271a5378ffedfdb1a4bedd4cd571cde88ace0dced27000000001976a914cf5d4c7955cdf8bb3e516db1eb76efe538a448a588aca0910203000000001976a9148d0e5abd1c82e99670d332582ba20d423fa4323288acc4ba0800000000001976a91419f529fccd87142620546e1bbefdbc30a2a93a6188ac18841300000000001976a9149c90ec9c987a451961ea29a29e265c4db0466a2788ac4e670800",
"txid": "c100893fc0fb74c38277978a78433aa92df5473d94e1651962fff0e55c5762fc",
"version": 2,
"vin": [
{
"txid": "6322a2faf2800abb88002a844976908dc574bcc856ee86e421ab1c984bb4a618",
"vout": 1,
"scriptSig": {
"hex": "483045022100dea77aa13dcdd457c7bad51e7ee310046a8f8e3c370c25217010db57a60335ca022024937a8c0c179fc8ef9923694b2f7e276904ae859010dd12b46e356ce6d76147412102619a1e932ef161c58f0d8c24fbf6b5b709f8e996aa8caa7a26130240a3416176"
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 5352938.26,
"n": 0,
"scriptPubKey": {
"hex": "76a914ab4c29c2e271a5378ffedfdb1a4bedd4cd571cde88ac"
}
},
{
"value": 6699000.00,
"n": 1,
"scriptPubKey": {
"hex": "76a914cf5d4c7955cdf8bb3e516db1eb76efe538a448a588ac"
}
},
{
"value": 505000.00,
"n": 2,
"scriptPubKey": {
"hex": "76a9148d0e5abd1c82e99670d332582ba20d423fa4323288ac"
}
},
{
"value": 5721.00,
"n": 3,
"scriptPubKey": {
"hex": "76a91419f529fccd87142620546e1bbefdbc30a2a93a6188ac"
}
},
{
"value": 12790.00,
"n": 4,
"scriptPubKey": {
"hex": "76a9149c90ec9c987a451961ea29a29e265c4db0466a2788ac"
}
}
],
"time": 1538669466,
"blocktime": 1538669466
},
{
"hex": "020000000e34620707fc49a213e57c18880360c465c51b3e8709e26829229bf6e0499cf1d9010000006a473044022057269d92e28fc3956075172173ef67a1f8e8e81bfe3a94e139373b5d8bfbace402202e6d80dcf22ce50ced02df68161c8af3f95476c498cc36f0b8450934fcf6387441210209bd24ca51b659d8950af12363513af576e776131eaad2baf72cf2d5ed2db4d0feffffff6991b494656029ed424f149c7fce99089a02dd534cc4b657312ac61e07691845010000006a4730440220773b5faf496664b9da746853148b9f4e65d7901b9e775f0d304f60bb45b6bce702207c725522f19c2ab1e40012ba76443368005ab45e50faff706b8a9f4e4f1ade294121029f5115229faf57ec14b710bbbb71cea99663f1987b0642095d957f4365ae8189feffffff922caf594105198fef72665241286caceba276ccd4f25de230d0154d01d20bf4010000006a4730440220232a37b6f939395d4acb5ea6deb95894833a08eceb7b47cd26f54f9b6ea0c0630220284837d62429c2d919e5371e461436a8b2f8364e5a391d2620c3da943f6da7734121034032e450981630d01d6f7f67b2f0984a4f8b447b8c17da16d448f3b911fb6e31feffffff1b663b64fa1d070e1c557bf51f9f9bb3ff1d57e7bb6699487fe6465e6124d357000000006b483045022100d1b020e2d6b54ee90bada53872669921b5dc532863a0d4195958248ac74e7233022025f89661164946dc4318b7f2a21aa034847cee15b1597ece4399931f8b8ebe724121035fa81b02f2a72f9e8a35ed2f4fc1913a3aa74a1991d4b125e895168f015fe399feffffff5b3306f9d512292ae2644af096ab1529b6caff7cc1a0d233fc3a7d3850165073010000006a47304402202014a66e2a6c27f9eda4e87f1495764995507e9b7379f7cea58ba8c344e1ab770220446218231005a000e8f20abfba75e964ebe4cef5d3e4f60bc6be46a548ad7c71412102c384cca7a64cb48f7dc3a8ded4ee0ac07146108799fcb6020c07a7b166661699feffffff63049d8a5b57abf73f080d38d28ea14d159589993910ffa1c1d4a566fe0a4bfe010000006b483045022100b3584a86c1dc3481af9d9a75ebc421d78c35f2818c4b4366d8be383732d7aa4c022029c09ec4c4fc181b3cbebe4634a4fded19288559972e551d8382a4140f44a1794121024c066efd26424849d0a15910d0a49ced61cd7b2c311d50ac0f95bd5a9d609a83feffffff27e91003f5c59999d0c78e278b6eca1ee1a6fed82bb60e92a5946443cd73a3ba010000006a47304402200b88b727cf75ade32a1cf6915bc6cfa1e9102813c4d69db5fac613170a205f22022016bebf2825c288d24732772fff1376936502dc79789ee5cf3879e2bf2564fe58412102a5e690c5f8218ac5521a0ea3b1f0e59d6ba1c17d938659affa585a9d81799cbafeffffffa37670dd96e4814d30487edb4b647d48dcd2fd81ab3f1f9f3c669ef93fa3f9fe010000006a473044022064f2ed5f821b0e98fb556eadf5a5636e36e98f965796baf2ff0ad0080f4e68e7022010891d52d74f1dc55d861ad4898ec18318345ed2b358c698213944b381ab900e412102beb30e14403c4a03277d559019b60cd8fb877872896565fc0cdebb843797accdfeffffff1c7bb2fa455084c1447914819004365df5500a2fc32d9e6250fd74c795082590010000006b483045022100a73951625dc0635ec373851730b5d268c60b36fcbbcda85228452176024a1db30220332ddb3940c0d05c215a41bb751a77d1969e240a3dd3612e7b2ec49913907761412103cf972121caef0095019ae80fc3a91cc3aa3590f57ad5751319b1a5bde03549bcfeffffff50540eee49c962f60790966073658688b74a6fc1c7dbd846f114405143ab9267010000006b483045022100d2487d304222d511d3c2645315f4821486f250c2edba85c1aec5ce5604ab6f0b0220275d210b5c97c90f275be2193413792511bfaa6d3338ea418fc01cbba42f96334121037cff19a246685228edd8df2c7dd5ed1efa1d779e8ce9ae99274c20912922bd59feffffff999e5c78b01055b92f36e277c8fda3f0253cecf8b9a7640fb85b0ebd79b58dc5000000006a473044022010e90626ae890f8d9ac5be7b780f93269794f897732d4ca78b45797994b88ab402200fe4f787e4b5cf66a29b7a8f0a07b6a85d7a9ea18b89f216e3211b53641032bd4121030803961c4606e6cacba6b1ddd615a35a3abaaec945f60245da9e777d23975fdcfefffffff27534af3a65ee1b60692cead34519e798bf01bd108a6e5ec6f6422bfe605820010000006b483045022100ae8a1a285a324544e588215e878c02d0db4853bb4064dbb7babde6f9d403738202201caab0d5afdbda4ee6a27f9e10fec2045717ac63b55ac647a5c2a5440c7c00c6412102ade72a40797ce9bf5662169d3317c1bd31455b086ecddbdc1bcb4cdf8ba6fc89feffffff40c16f37c67b80f53cf6fd906c3c53922bc21c050d560464258e45993bc20e92000000006a47304402205acc6b45d4c3e330a45dcd4ef69840edcd2b31da247151e741c0468f8e65ae98022032da991edacd2b5437a44bd2463a5f93ef1b32f3467d5748ceed5c70aa5eac1041210221099010e3629434851ceb0c5992388b815e9290b78aef55de30a08f73c29716feffffff4b7ebd29cb82e8cef3f7ebb275edf7f8604ae67821f137a4a3a309920431bd24000000006a47304402207a0f2ad56df4bb879fd645c2cf07d034079ff0574cbe54bf51234968c19f526802207b25da2a8304a4e1f8d4a78f0c7902e9eef647a856c6f5193bed10d1fa26b338412102aa396f2b3bdbc39134b4e1f52d02ec83d0cee811d35ae78a539c8428781f3876feffffff02dea0446d000000001976a914d1e5cdc2076e9e4890d5f5d0356dc4543b86e85d88ac033b0f00000000001976a91418195caf282889538a9ed9958bcc47a6bf7326b388ac00000000",
"txid": "28abbf7f1360142b11534051aac3fb05a26815cef4a8a726feb761a6e24bdf34",
"version": 2,
"vin": [
{
"txid": "d9f19c49e0f69b222968e209873e1bc565c4600388187ce513a249fc07076234",
"vout": 1,
"scriptSig": {
"hex": "473044022057269d92e28fc3956075172173ef67a1f8e8e81bfe3a94e139373b5d8bfbace402202e6d80dcf22ce50ced02df68161c8af3f95476c498cc36f0b8450934fcf6387441210209bd24ca51b659d8950af12363513af576e776131eaad2baf72cf2d5ed2db4d0"
},
"sequence": 4294967294
},
{
"txid": "451869071ec62a3157b6c44c53dd029a0899ce7f9c144f42ed29606594b49169",
"vout": 1,
"scriptSig": {
"hex": "4730440220773b5faf496664b9da746853148b9f4e65d7901b9e775f0d304f60bb45b6bce702207c725522f19c2ab1e40012ba76443368005ab45e50faff706b8a9f4e4f1ade294121029f5115229faf57ec14b710bbbb71cea99663f1987b0642095d957f4365ae8189"
},
"sequence": 4294967294
},
{
"txid": "f40bd2014d15d030e25df2d4cc76a2ebac6c2841526672ef8f19054159af2c92",
"vout": 1,
"scriptSig": {
"hex": "4730440220232a37b6f939395d4acb5ea6deb95894833a08eceb7b47cd26f54f9b6ea0c0630220284837d62429c2d919e5371e461436a8b2f8364e5a391d2620c3da943f6da7734121034032e450981630d01d6f7f67b2f0984a4f8b447b8c17da16d448f3b911fb6e31"
},
"sequence": 4294967294
},
{
"txid": "57d324615e46e67f489966bbe7571dffb39b9f1ff57b551c0e071dfa643b661b",
"vout": 0,
"scriptSig": {
"hex": "483045022100d1b020e2d6b54ee90bada53872669921b5dc532863a0d4195958248ac74e7233022025f89661164946dc4318b7f2a21aa034847cee15b1597ece4399931f8b8ebe724121035fa81b02f2a72f9e8a35ed2f4fc1913a3aa74a1991d4b125e895168f015fe399"
},
"sequence": 4294967294
},
{
"txid": "73501650387d3afc33d2a0c17cffcab62915ab96f04a64e22a2912d5f906335b",
"vout": 1,
"scriptSig": {
"hex": "47304402202014a66e2a6c27f9eda4e87f1495764995507e9b7379f7cea58ba8c344e1ab770220446218231005a000e8f20abfba75e964ebe4cef5d3e4f60bc6be46a548ad7c71412102c384cca7a64cb48f7dc3a8ded4ee0ac07146108799fcb6020c07a7b166661699"
},
"sequence": 4294967294
},
{
"txid": "fe4b0afe66a5d4c1a1ff1039998995154da18ed2380d083ff7ab575b8a9d0463",
"vout": 1,
"scriptSig": {
"hex": "483045022100b3584a86c1dc3481af9d9a75ebc421d78c35f2818c4b4366d8be383732d7aa4c022029c09ec4c4fc181b3cbebe4634a4fded19288559972e551d8382a4140f44a1794121024c066efd26424849d0a15910d0a49ced61cd7b2c311d50ac0f95bd5a9d609a83"
},
"sequence": 4294967294
},
{
"txid": "baa373cd436494a5920eb62bd8fea6e11eca6e8b278ec7d09999c5f50310e927",
"vout": 1,
"scriptSig": {
"hex": "47304402200b88b727cf75ade32a1cf6915bc6cfa1e9102813c4d69db5fac613170a205f22022016bebf2825c288d24732772fff1376936502dc79789ee5cf3879e2bf2564fe58412102a5e690c5f8218ac5521a0ea3b1f0e59d6ba1c17d938659affa585a9d81799cba"
},
"sequence": 4294967294
},
{
"txid": "fef9a33ff99e663c9f1f3fab81fdd2dc487d644bdb7e48304d81e496dd7076a3",
"vout": 1,
"scriptSig": {
"hex": "473044022064f2ed5f821b0e98fb556eadf5a5636e36e98f965796baf2ff0ad0080f4e68e7022010891d52d74f1dc55d861ad4898ec18318345ed2b358c698213944b381ab900e412102beb30e14403c4a03277d559019b60cd8fb877872896565fc0cdebb843797accd"
},
"sequence": 4294967294
},
{
"txid": "90250895c774fd50629e2dc32f0a50f55d36049081147944c1845045fab27b1c",
"vout": 1,
"scriptSig": {
"hex": "483045022100a73951625dc0635ec373851730b5d268c60b36fcbbcda85228452176024a1db30220332ddb3940c0d05c215a41bb751a77d1969e240a3dd3612e7b2ec49913907761412103cf972121caef0095019ae80fc3a91cc3aa3590f57ad5751319b1a5bde03549bc"
},
"sequence": 4294967294
},
{
"txid": "6792ab43514014f146d8dbc7c16f4ab78886657360969007f662c949ee0e5450",
"vout": 1,
"scriptSig": {
"hex": "483045022100d2487d304222d511d3c2645315f4821486f250c2edba85c1aec5ce5604ab6f0b0220275d210b5c97c90f275be2193413792511bfaa6d3338ea418fc01cbba42f96334121037cff19a246685228edd8df2c7dd5ed1efa1d779e8ce9ae99274c20912922bd59"
},
"sequence": 4294967294
},
{
"txid": "c58db579bd0e5bb80f64a7b9f8ec3c25f0a3fdc877e2362fb95510b0785c9e99",
"vout": 0,
"scriptSig": {
"hex": "473044022010e90626ae890f8d9ac5be7b780f93269794f897732d4ca78b45797994b88ab402200fe4f787e4b5cf66a29b7a8f0a07b6a85d7a9ea18b89f216e3211b53641032bd4121030803961c4606e6cacba6b1ddd615a35a3abaaec945f60245da9e777d23975fdc"
},
"sequence": 4294967294
},
{
"txid": "205860fe2b42f6c65e6e8a10bd01bf98e71945d3ea2c69601bee653aaf3475f2",
"vout": 1,
"scriptSig": {
"hex": "483045022100ae8a1a285a324544e588215e878c02d0db4853bb4064dbb7babde6f9d403738202201caab0d5afdbda4ee6a27f9e10fec2045717ac63b55ac647a5c2a5440c7c00c6412102ade72a40797ce9bf5662169d3317c1bd31455b086ecddbdc1bcb4cdf8ba6fc89"
},
"sequence": 4294967294
},
{
"txid": "920ec23b99458e256404560d051cc22b92533c6c90fdf63cf5807bc6376fc140",
"vout": 0,
"scriptSig": {
"hex": "47304402205acc6b45d4c3e330a45dcd4ef69840edcd2b31da247151e741c0468f8e65ae98022032da991edacd2b5437a44bd2463a5f93ef1b32f3467d5748ceed5c70aa5eac1041210221099010e3629434851ceb0c5992388b815e9290b78aef55de30a08f73c29716"
},
"sequence": 4294967294
},
{
"txid": "24bd31049209a3a3a437f12178e64a60f8f7ed75b2ebf7f3cee882cb29bd7e4b",
"vout": 0,
"scriptSig": {
"hex": "47304402207a0f2ad56df4bb879fd645c2cf07d034079ff0574cbe54bf51234968c19f526802207b25da2a8304a4e1f8d4a78f0c7902e9eef647a856c6f5193bed10d1fa26b338412102aa396f2b3bdbc39134b4e1f52d02ec83d0cee811d35ae78a539c8428781f3876"
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 18332141.74,
"scriptPubKey": {
"hex": "76a914d1e5cdc2076e9e4890d5f5d0356dc4543b86e85d88ac"
}
},
{
"value": 9981.47,
"n": 1,
"scriptPubKey": {
"hex": "76a91418195caf282889538a9ed9958bcc47a6bf7326b388ac"
}
}
],
"time": 1538669466,
"blocktime": 1538669466
}
]
}
}
},
"handleFork": {
"syncRanges": [
{"lower": 550716, "upper": 550736}
],
"fakeBlocks": {
"550733": {
"height": 550733,
"hash": "000000000000000000a517d8c6f3073e6872d9f3333314de7456687b228a6358"
},
"550734": {
"height": 550734,
"hash": "000000000000000001afb0d221f7e4d62937a8aa60fd9e2ecadb74554c7033f6"
},
"550735": {
"height": 550735,
"hash": "00000000000000000003b4357ac6904a5985f5175dafa31ff7e6ec4fcafec310"
},
"550736": {
"height": 550736,
"hash": "000000000000000001d21a5f91bf04b1bc68b0bee17b02763547192b8deda84b"
}
},
"realBlocks": {
"550733": {
"height": 550733,
"hash": "000000000000000000555800282da8751765b6ae1d4979c0d024fe025d9a32da"
},
"550734": {
"height": 550734,
"hash": "0000000000000000013f343250868b23037c84082725c5ec317e1e09bf4a2dcf"
},
"550735": {
"height": 550735,
"hash": "000000000000000000cfe8d66f1f8d2f155b61425ebc2daf5d10b133edc93af5"
},
"550736": {
"height": 550736,
"hash": "00000000000000000181e327d1165480db82d915d46b9d39232526309072e014"
}
}
}
}

View File

@ -89,6 +89,11 @@
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync"],
"sync": ["ConnectBlocksParallel", "ConnectBlocks"]
},
"ecash": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync",
"GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"],
"sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"]
},
"ethereum_testnet_ropsten": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight",
"GetBlockHeader"]