Integration tests are defined declaratively with single implementation
This commit is contained in:
parent
e182554251
commit
b5d1e5c94e
@ -1,141 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package bch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(chain string) func(json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
return func(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewBCashRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*BCashRPC)
|
|
||||||
cli.Parser, err = NewBCashParser(GetChainParams(chain), cli.ChainConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests struct {
|
|
||||||
mainnet *rpc.Test
|
|
||||||
testnet *rpc.Test
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
t, err := rpc.NewTest("Bcash", getRPCClient("main"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.mainnet = t
|
|
||||||
|
|
||||||
t, err = rpc.NewTest("Bcash Testnet", getRPCClient("test"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.testnet = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_MempoolSync(t *testing.T) {
|
|
||||||
tests.mainnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_MempoolSync(t *testing.T) {
|
|
||||||
tests.testnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
tests.testnet.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBCashTestnetRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
@ -27,28 +27,28 @@ import (
|
|||||||
|
|
||||||
type blockChainFactory func(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error)
|
type blockChainFactory func(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error)
|
||||||
|
|
||||||
var blockChainFactories = make(map[string]blockChainFactory)
|
var BlockChainFactories = make(map[string]blockChainFactory)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
blockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
|
BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
|
||||||
blockChainFactories["Testnet"] = btc.NewBitcoinRPC
|
BlockChainFactories["Testnet"] = btc.NewBitcoinRPC
|
||||||
blockChainFactories["Zcash"] = zec.NewZCashRPC
|
BlockChainFactories["Zcash"] = zec.NewZCashRPC
|
||||||
blockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
|
BlockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
|
||||||
blockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
||||||
blockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
||||||
blockChainFactories["Bcash"] = bch.NewBCashRPC
|
BlockChainFactories["Bcash"] = bch.NewBCashRPC
|
||||||
blockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
||||||
blockChainFactories["Bgold"] = btg.NewBGoldRPC
|
BlockChainFactories["Bgold"] = btg.NewBGoldRPC
|
||||||
blockChainFactories["Dash"] = dash.NewDashRPC
|
BlockChainFactories["Dash"] = dash.NewDashRPC
|
||||||
blockChainFactories["Dash Testnet"] = dash.NewDashRPC
|
BlockChainFactories["Dash Testnet"] = dash.NewDashRPC
|
||||||
blockChainFactories["Litecoin"] = litecoin.NewLitecoinRPC
|
BlockChainFactories["Litecoin"] = litecoin.NewLitecoinRPC
|
||||||
blockChainFactories["Litecoin Testnet"] = litecoin.NewLitecoinRPC
|
BlockChainFactories["Litecoin Testnet"] = litecoin.NewLitecoinRPC
|
||||||
blockChainFactories["Dogecoin"] = dogecoin.NewDogecoinRPC
|
BlockChainFactories["Dogecoin"] = dogecoin.NewDogecoinRPC
|
||||||
blockChainFactories["Vertcoin"] = vertcoin.NewVertcoinRPC
|
BlockChainFactories["Vertcoin"] = vertcoin.NewVertcoinRPC
|
||||||
blockChainFactories["Vertcoin Testnet"] = vertcoin.NewVertcoinRPC
|
BlockChainFactories["Vertcoin Testnet"] = vertcoin.NewVertcoinRPC
|
||||||
blockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC
|
BlockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC
|
||||||
blockChainFactories["Monacoin"] = monacoin.NewMonacoinRPC
|
BlockChainFactories["Monacoin"] = monacoin.NewMonacoinRPC
|
||||||
blockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
|
BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
||||||
@ -79,9 +79,9 @@ func NewBlockChain(coin string, configfile string, pushHandler func(bchain.Notif
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Annotatef(err, "Error parsing file %v", configfile)
|
return nil, errors.Annotatef(err, "Error parsing file %v", configfile)
|
||||||
}
|
}
|
||||||
bcf, ok := blockChainFactories[coin]
|
bcf, ok := BlockChainFactories[coin]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New(fmt.Sprint("Unsupported coin '", coin, "'. Must be one of ", reflect.ValueOf(blockChainFactories).MapKeys()))
|
return nil, errors.New(fmt.Sprint("Unsupported coin '", coin, "'. Must be one of ", reflect.ValueOf(BlockChainFactories).MapKeys()))
|
||||||
}
|
}
|
||||||
bc, err := bcf(config, pushHandler)
|
bc, err := bcf(config, pushHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -1,142 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package btc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(chain string) func(json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
return func(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewBitcoinRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*BitcoinRPC)
|
|
||||||
cli.Parser = NewBitcoinParser(GetChainParams(chain), cli.ChainConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests struct {
|
|
||||||
mainnet *rpc.Test
|
|
||||||
testnet *rpc.Test
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Bitcoin", getRPCClient("main"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.mainnet = t
|
|
||||||
|
|
||||||
t, err = rpc.NewTest("Bitcoin Testnet", getRPCClient("test"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.testnet = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
func TestBitcoinRPC_MempoolSync(t *testing.T) {
|
|
||||||
t.Skip("skipping test, run too long")
|
|
||||||
// tests.mainnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_MempoolSync(t *testing.T) {
|
|
||||||
tests.testnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
tests.testnet.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBitcoinTestnetRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
@ -1,129 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package dash
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(chain string) func(json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
return func(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewDashRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*DashRPC)
|
|
||||||
cli.Parser = NewDashParser(GetChainParams(chain), cli.ChainConfig)
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests struct {
|
|
||||||
mainnet *rpc.Test
|
|
||||||
testnet *rpc.Test
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Dash", getRPCClient("main"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.mainnet = t
|
|
||||||
|
|
||||||
t, err = rpc.NewTest("Dash Testnet", getRPCClient("test"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.testnet = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_MempoolSync(t *testing.T) {
|
|
||||||
tests.mainnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_MempoolSync(t *testing.T) {
|
|
||||||
tests.testnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDashTestnetRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package dogecoin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewDogecoinRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*DogecoinRPC)
|
|
||||||
cli.Parser = NewDogecoinParser(GetChainParams("main"), cli.ChainConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpcTest *rpc.Test
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Dogecoin", getRPCClient)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcTest = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDogecoinRPC_GetBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDogecoinRPC_GetBlock(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDogecoinRPC_GetTransaction(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDogecoinRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDogecoinRPC_MempoolSync(t *testing.T) {
|
|
||||||
rpcTest.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDogecoinRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
t.Skip("skipping test, unreliable")
|
|
||||||
// rpcTest.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDogecoinRPC_EstimateFee(t *testing.T) {
|
|
||||||
t.Skip("skipping test, unreliable")
|
|
||||||
// rpcTest.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package eth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewEthereumRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpcTest *rpc.Test
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Ethereum Testnet", getRPCClient)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcTest = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthRPC_GetBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthRPC_GetBlock(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthRPC_GetTransaction(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
rpcTest.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEthRPC_EstimateFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package litecoin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewLitecoinRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*LitecoinRPC)
|
|
||||||
cli.Parser = NewLitecoinParser(GetChainParams("main"), cli.ChainConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpcTest *rpc.Test
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Litecoin", getRPCClient)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcTest = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_GetBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_GetBlock(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_GetTransaction(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_MempoolSync(t *testing.T) {
|
|
||||||
rpcTest.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
rpcTest.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLitecoinRPC_EstimateFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package monacoin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewMonacoinRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*MonacoinRPC)
|
|
||||||
cli.Parser = NewMonacoinParser(GetChainParams("main"), cli.ChainConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpcTest *rpc.Test
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Monacoin", getRPCClient)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcTest = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_GetBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_GetBlock(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_GetTransaction(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_MempoolSync(t *testing.T) {
|
|
||||||
rpcTest.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
rpcTest.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonacoinRPC_EstimateFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package namecoin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewNamecoinRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*NamecoinRPC)
|
|
||||||
cli.Parser = NewNamecoinParser(GetChainParams("main"), cli.ChainConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpcTest *rpc.Test
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Namecoin", getRPCClient)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcTest = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetBlock(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetTransaction(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
// extra opcodes (name_new, name_firstupdate, name_update) aren't supported, so some transactions
|
|
||||||
// in mempool can't be parsed correctly
|
|
||||||
t.Skipf("Skipped because of instability")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_MempoolSync(t *testing.T) {
|
|
||||||
rpcTest.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
rpcTest.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_EstimateFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
rpcTest.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamecoinRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package vertcoin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewVertcoinRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*VertcoinRPC)
|
|
||||||
cli.Parser = NewVertcoinParser(GetChainParams("main"), cli.ChainConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var rpcTest *rpc.Test
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
t, err := rpc.NewTest("Vertcoin", getRPCClient)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcTest = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetBlock(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetTransaction(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
rpcTest.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_MempoolSync(t *testing.T) {
|
|
||||||
rpcTest.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetMempoolEntry(t *testing.T) {
|
|
||||||
rpcTest.TestGetMempoolEntry(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_EstimateFee(t *testing.T) {
|
|
||||||
rpcTest.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
rpcTest.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
rpcTest.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVertcoinRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
rpcTest.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
@ -1,130 +0,0 @@
|
|||||||
// +build integration
|
|
||||||
|
|
||||||
package zec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"blockbook/bchain/tests/rpc"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getRPCClient(chain string) func(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
return func(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|
||||||
c, err := NewZCashRPC(cfg, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cli := c.(*ZCashRPC)
|
|
||||||
cli.Parser = NewZCashParser(GetChainParams(chain), cli.ChainConfig)
|
|
||||||
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
|
||||||
return cli, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests struct {
|
|
||||||
mainnet *rpc.Test
|
|
||||||
testnet *rpc.Test
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
t, err := rpc.NewTest("Zcash", getRPCClient("main"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.mainnet = t
|
|
||||||
|
|
||||||
t, err = rpc.NewTest("Zcash Testnet", getRPCClient("test"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.testnet = t
|
|
||||||
|
|
||||||
os.Exit(m.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_MempoolSync(t *testing.T) {
|
|
||||||
tests.mainnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.mainnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_GetBlockHash(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_GetBlock(t *testing.T) {
|
|
||||||
tests.testnet.TestGetBlock(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_GetTransaction(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransaction(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_GetTransactionForMempool(t *testing.T) {
|
|
||||||
tests.testnet.TestGetTransactionForMempool(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_MempoolSync(t *testing.T) {
|
|
||||||
tests.testnet.TestMempoolSync(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_EstimateSmartFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateSmartFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_EstimateFee(t *testing.T) {
|
|
||||||
tests.testnet.TestEstimateFee(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_GetBestBlockHash(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHash(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_GetBestBlockHeight(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBestBlockHeight(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestZCashTestnetRPC_GetBlockHeader(t *testing.T) {
|
|
||||||
tests.mainnet.TestGetBlockHeader(t)
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"Bitcoin": {
|
|
||||||
"url": "http://localhost:8030",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Bcash": {
|
|
||||||
"url": "http://localhost:8031",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Zcash": {
|
|
||||||
"url": "http://localhost:8032",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Dash": {
|
|
||||||
"url": "http://localhost:8033",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Litecoin": {
|
|
||||||
"url": "http://localhost:8034",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Ethereum": {
|
|
||||||
"url": "ws://localhost:8036",
|
|
||||||
"user": null,
|
|
||||||
"pass": null
|
|
||||||
},
|
|
||||||
"Dogecoin": {
|
|
||||||
"url": "http://localhost:8038",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpcp"
|
|
||||||
},
|
|
||||||
"Namecoin": {
|
|
||||||
"url": "http://localhost:8039",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Vertcoin": {
|
|
||||||
"url": "http://localhost:8040",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Monacoin": {
|
|
||||||
"url": "http://localhost:8041",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Bitcoin Testnet": {
|
|
||||||
"url": "http://localhost:18030",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Bcash Testnet": {
|
|
||||||
"url": "http://localhost:18031",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Zcash Testnet": {
|
|
||||||
"url": "http://localhost:18032",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Dash Testnet": {
|
|
||||||
"url": "http://localhost:18033",
|
|
||||||
"user": "rpc",
|
|
||||||
"pass": "rpc"
|
|
||||||
},
|
|
||||||
"Ethereum Testnet": {
|
|
||||||
"url": "ws://localhost:18036",
|
|
||||||
"user": null,
|
|
||||||
"pass": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,12 +4,19 @@ import (
|
|||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TestData struct {
|
||||||
|
BlockHeight uint32 `json:"blockHeight"`
|
||||||
|
BlockHash string `json:"blockHash"`
|
||||||
|
BlockTime int64 `json:"blockTime"`
|
||||||
|
BlockTxs []string `json:"blockTxs"`
|
||||||
|
TxDetails map[string]*bchain.Tx `json:"txDetails"`
|
||||||
|
}
|
||||||
|
|
||||||
func joinPathsWithCommonElement(p1, p2 string) (string, bool) {
|
func joinPathsWithCommonElement(p1, p2 string) (string, bool) {
|
||||||
idx := strings.IndexRune(p2, filepath.Separator)
|
idx := strings.IndexRune(p2, filepath.Separator)
|
||||||
if idx <= 0 {
|
if idx <= 0 {
|
||||||
@ -42,46 +49,6 @@ func readDataFile(dir, relDir, filename string) ([]byte, error) {
|
|||||||
return ioutil.ReadFile(path)
|
return ioutil.ReadFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
var testConfigRegistry map[string]*TestConfig
|
|
||||||
|
|
||||||
func LoadTestConfig(coin string) (*TestConfig, error) {
|
|
||||||
if testConfigRegistry == nil {
|
|
||||||
b, err := readDataFile(".", "bchain/tests/rpc", "config.json")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var v map[string]*TestConfig
|
|
||||||
err = json.Unmarshal(b, &v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
testConfigRegistry = v
|
|
||||||
}
|
|
||||||
c, found := testConfigRegistry[coin]
|
|
||||||
if !found {
|
|
||||||
return nil, errors.New("Test config not found")
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadRPCConfig(coin string) (json.RawMessage, error) {
|
|
||||||
t := `{
|
|
||||||
"coin_name": "%s",
|
|
||||||
"rpc_url": "%s",
|
|
||||||
"rpc_user": "%s",
|
|
||||||
"rpc_pass": "%s",
|
|
||||||
"rpc_timeout": 25,
|
|
||||||
"parse": true
|
|
||||||
}`
|
|
||||||
|
|
||||||
c, err := LoadTestConfig(coin)
|
|
||||||
if err != nil {
|
|
||||||
return json.RawMessage{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.RawMessage(fmt.Sprintf(t, coin, c.URL, c.User, c.Pass)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadTestData(coin string, parser bchain.BlockChainParser) (*TestData, error) {
|
func LoadTestData(coin string, parser bchain.BlockChainParser) (*TestData, error) {
|
||||||
b, err := readDataFile(".", "bchain/tests/rpc/testdata", coin+".json")
|
b, err := readDataFile(".", "bchain/tests/rpc/testdata", coin+".json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -1,455 +0,0 @@
|
|||||||
package rpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"blockbook/bchain"
|
|
||||||
"encoding/json"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/deckarep/golang-set"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestConfig struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
User string `json:"user"`
|
|
||||||
Pass string `json:"pass"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestData struct {
|
|
||||||
BlockHeight uint32 `json:"blockHeight"`
|
|
||||||
BlockHash string `json:"blockHash"`
|
|
||||||
BlockTime int64 `json:"blockTime"`
|
|
||||||
BlockTxs []string `json:"blockTxs"`
|
|
||||||
TxDetails map[string]*bchain.Tx `json:"txDetails"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Test struct {
|
|
||||||
Client bchain.BlockChain
|
|
||||||
TestData *TestData
|
|
||||||
connected bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestChainFactoryFunc func(json.RawMessage) (bchain.BlockChain, error)
|
|
||||||
|
|
||||||
func NewTest(coin string, factory TestChainFactoryFunc) (*Test, error) {
|
|
||||||
var (
|
|
||||||
connected = true
|
|
||||||
cli bchain.BlockChain
|
|
||||||
cfg json.RawMessage
|
|
||||||
td *TestData
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
cfg, err = LoadRPCConfig(coin)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cli, err = factory(cfg)
|
|
||||||
if err != nil {
|
|
||||||
if isNetError(err) {
|
|
||||||
connected = false
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
td, err = LoadTestData(coin, cli.GetChainParser())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if td.TxDetails != nil {
|
|
||||||
parser := cli.GetChainParser()
|
|
||||||
|
|
||||||
for _, tx := range td.TxDetails {
|
|
||||||
err := setTxAddresses(parser, tx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = cli.GetBlockChainInfo()
|
|
||||||
if err != nil && isNetError(err) {
|
|
||||||
connected = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Test{Client: cli, TestData: td, connected: connected}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNetError(err error) bool {
|
|
||||||
if _, ok := err.(net.Error); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTxAddresses(parser bchain.BlockChainParser, tx *bchain.Tx) error {
|
|
||||||
// pack and unpack transaction in order to get addresses decoded - ugly but works
|
|
||||||
var tmp *bchain.Tx
|
|
||||||
b, err := parser.PackTx(tx, 0, 0)
|
|
||||||
if err == nil {
|
|
||||||
tmp, _, err = parser.UnpackTx(b)
|
|
||||||
if err == nil {
|
|
||||||
for i := 0; i < len(tx.Vout); i++ {
|
|
||||||
tx.Vout[i].ScriptPubKey.Addresses = tmp.Vout[i].ScriptPubKey.Addresses
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) skipUnconnected(t *testing.T) {
|
|
||||||
if !rt.connected {
|
|
||||||
t.Skip("Skipping test, not connected to backend service")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetBlockHash(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
hash, err := rt.Client.GetBlockHash(rt.TestData.BlockHeight)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if hash != rt.TestData.BlockHash {
|
|
||||||
t.Errorf("GetBlockHash() got %q, want %q", hash, rt.TestData.BlockHash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetBlock(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
blk, err := rt.Client.GetBlock(rt.TestData.BlockHash, 0)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(blk.Txs) != len(rt.TestData.BlockTxs) {
|
|
||||||
t.Errorf("GetBlock() number of transactions: got %d, want %d", len(blk.Txs), len(rt.TestData.BlockTxs))
|
|
||||||
}
|
|
||||||
|
|
||||||
for ti, tx := range blk.Txs {
|
|
||||||
if tx.Txid != rt.TestData.BlockTxs[ti] {
|
|
||||||
t.Errorf("GetBlock() transaction %d: got %s, want %s", ti, tx.Txid, rt.TestData.BlockTxs[ti])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetTransaction(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for txid, want := range rt.TestData.TxDetails {
|
|
||||||
got, err := rt.Client.GetTransaction(txid)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Confirmations is variable field, we just check if is set and reset it
|
|
||||||
if got.Confirmations <= 0 {
|
|
||||||
t.Errorf("GetTransaction() got struct with invalid Confirmations field")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
got.Confirmations = 0
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
|
||||||
t.Errorf("GetTransaction() got %+v, want %+v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetTransactionForMempool(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for txid, want := range rt.TestData.TxDetails {
|
|
||||||
// reset fields that are not parsed by BlockChainParser
|
|
||||||
want.Confirmations, want.Blocktime, want.Time = 0, 0, 0
|
|
||||||
|
|
||||||
got, err := rt.Client.GetTransactionForMempool(txid)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
// transactions parsed from JSON may contain additional data
|
|
||||||
got.Confirmations, got.Blocktime, got.Time = 0, 0, 0
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
|
||||||
t.Errorf("GetTransactionForMempool() got %+v, want %+v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) getMempool(t *testing.T) []string {
|
|
||||||
txs, err := rt.Client.GetMempool()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if len(txs) == 0 {
|
|
||||||
t.Skip("Skipping test, mempool is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
return txs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) getMempoolAddresses(t *testing.T, txs []string) map[string][]string {
|
|
||||||
txid2addrs := map[string][]string{}
|
|
||||||
for i := 0; i < len(txs); i++ {
|
|
||||||
tx, err := rt.Client.GetTransactionForMempool(txs[i])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
addrs := []string{}
|
|
||||||
for _, vin := range tx.Vin {
|
|
||||||
for _, a := range vin.Addresses {
|
|
||||||
addrs = append(addrs, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, vout := range tx.Vout {
|
|
||||||
for _, a := range vout.ScriptPubKey.Addresses {
|
|
||||||
addrs = append(addrs, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(addrs) > 0 {
|
|
||||||
txid2addrs[tx.Txid] = addrs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return txid2addrs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestMempoolSync(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
txs := rt.getMempool(t)
|
|
||||||
|
|
||||||
n, err := rt.Client.ResyncMempool(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
// no transactions to test
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
txs = intersect(txs, rt.getMempool(t))
|
|
||||||
if len(txs) == 0 {
|
|
||||||
// no transactions to test
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
txid2addrs := rt.getMempoolAddresses(t, txs)
|
|
||||||
if len(txid2addrs) == 0 {
|
|
||||||
t.Skip("Skipping test, no addresses in mempool")
|
|
||||||
}
|
|
||||||
|
|
||||||
for txid, addrs := range txid2addrs {
|
|
||||||
for _, a := range addrs {
|
|
||||||
got, err := rt.Client.GetMempoolTransactions(a)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !containsString(got, txid) {
|
|
||||||
t.Errorf("ResyncMempool() - for address %s, transaction %s wasn't found in mempool", a, txid)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// done
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.Skip("Skipping test, all attempts to sync mempool failed due to network state changes")
|
|
||||||
}
|
|
||||||
|
|
||||||
func intersect(a, b []string) []string {
|
|
||||||
setA := mapset.NewSet()
|
|
||||||
for _, v := range a {
|
|
||||||
setA.Add(v)
|
|
||||||
}
|
|
||||||
setB := mapset.NewSet()
|
|
||||||
for _, v := range b {
|
|
||||||
setB.Add(v)
|
|
||||||
}
|
|
||||||
inter := setA.Intersect(setB)
|
|
||||||
res := make([]string, 0, inter.Cardinality())
|
|
||||||
for v := range inter.Iter() {
|
|
||||||
res = append(res, v.(string))
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsString(slice []string, s string) bool {
|
|
||||||
for i := 0; i < len(slice); i++ {
|
|
||||||
if slice[i] == s {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetMempoolEntry(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
txs := rt.getMempool(t)
|
|
||||||
h, err := rt.Client.GetBestBlockHeight()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
txid := txs[rand.Intn(len(txs))]
|
|
||||||
tx, err := rt.Client.GetTransactionForMempool(txid)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if tx.Confirmations > 0 {
|
|
||||||
// tx confirmed
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
e, err := rt.Client.GetMempoolEntry(txid)
|
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(*bchain.RPCError); ok && err.Code == -5 {
|
|
||||||
// tx confirmed
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if d := int(e.Height) - int(h); d < -1 || d > 1 {
|
|
||||||
t.Errorf("GetMempoolEntry() got height %d, want %d", e.Height, h)
|
|
||||||
}
|
|
||||||
if e.Size <= 0 {
|
|
||||||
t.Errorf("GetMempoolEntry() got zero or negative size %d", e.Size)
|
|
||||||
}
|
|
||||||
if e.FeeSat.Sign() != 1 {
|
|
||||||
t.Errorf("GetMempoolEntry() got zero or negative fee %v", e.FeeSat.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// done
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.Skip("Skipping test, all attempts to get mempool entry failed due to network state changes")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestEstimateSmartFee(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for _, blocks := range []int{1, 2, 3, 5, 10} {
|
|
||||||
fee, err := rt.Client.EstimateSmartFee(blocks, true)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
if fee.Sign() == -1 {
|
|
||||||
sf := rt.Client.GetChainParser().AmountToDecimalString(&fee)
|
|
||||||
if sf != "-1" {
|
|
||||||
t.Errorf("EstimateSmartFee() returned unexpected fee rate: %v", sf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestEstimateFee(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for _, blocks := range []int{1, 2, 3, 5, 10} {
|
|
||||||
fee, err := rt.Client.EstimateFee(blocks)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
if fee.Sign() == -1 {
|
|
||||||
sf := rt.Client.GetChainParser().AmountToDecimalString(&fee)
|
|
||||||
if sf != "-1" {
|
|
||||||
t.Errorf("EstimateFee() returned unexpected fee rate: %v", sf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetBestBlockHash(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
hash, err := rt.Client.GetBestBlockHash()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
height, err := rt.Client.GetBestBlockHeight()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
hh, err := rt.Client.GetBlockHash(height)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if hash != hh {
|
|
||||||
time.Sleep(time.Millisecond * 100)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// we expect no next block
|
|
||||||
_, err = rt.Client.GetBlock("", height+1)
|
|
||||||
if err != nil {
|
|
||||||
if err != bchain.ErrBlockNotFound {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Error("GetBestBlockHash() didn't get the best hash")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetBestBlockHeight(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
height, err := rt.Client.GetBestBlockHeight()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// we expect no next block
|
|
||||||
_, err = rt.Client.GetBlock("", height+1)
|
|
||||||
if err != nil {
|
|
||||||
if err != bchain.ErrBlockNotFound {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Error("GetBestBlockHeigh() didn't get the the best heigh")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *Test) TestGetBlockHeader(t *testing.T) {
|
|
||||||
rt.skipUnconnected(t)
|
|
||||||
|
|
||||||
want := &bchain.BlockHeader{
|
|
||||||
Hash: rt.TestData.BlockHash,
|
|
||||||
Height: rt.TestData.BlockHeight,
|
|
||||||
Time: rt.TestData.BlockTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
got, err := rt.Client.GetBlockHeader(rt.TestData.BlockHash)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirmations is variable field, we just check if is set and reset it
|
|
||||||
if got.Confirmations <= 0 {
|
|
||||||
t.Fatalf("GetBlockHeader() got struct with invalid Confirmations field")
|
|
||||||
}
|
|
||||||
got.Confirmations = 0
|
|
||||||
|
|
||||||
got.Prev, got.Next = "", ""
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
|
||||||
t.Errorf("GetBlockHeader() got=%+v, want=%+v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
484
bchain/tests/rpc/rpc_test.go
Normal file
484
bchain/tests/rpc/rpc_test.go
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
// +build integration
|
||||||
|
|
||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"blockbook/bchain"
|
||||||
|
"blockbook/bchain/coins"
|
||||||
|
"blockbook/build/tools"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/deckarep/golang-set"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testMap = map[string]func(t *testing.T, th *TestHandler){
|
||||||
|
"GetBlockHash": testGetBlockHash,
|
||||||
|
"GetBlock": testGetBlock,
|
||||||
|
"GetTransaction": testGetTransaction,
|
||||||
|
"GetTransactionForMempool": testGetTransactionForMempool,
|
||||||
|
"MempoolSync": testMempoolSync,
|
||||||
|
"EstimateSmartFee": testEstimateSmartFee,
|
||||||
|
"EstimateFee": testEstimateFee,
|
||||||
|
"GetBestBlockHash": testGetBestBlockHash,
|
||||||
|
"GetBestBlockHeight": testGetBestBlockHeight,
|
||||||
|
"GetBlockHeader": testGetBlockHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestHandler struct {
|
||||||
|
Client bchain.BlockChain
|
||||||
|
TestData *TestData
|
||||||
|
connected bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var notConnectedError = errors.New("Not connected to backend server")
|
||||||
|
|
||||||
|
func TestRPCIntegration(t *testing.T) {
|
||||||
|
src := os.Getenv("BLOCKBOOK_SRC")
|
||||||
|
if src == "" {
|
||||||
|
t.Fatalf("Missing environment variable BLOCKBOOK_SRC")
|
||||||
|
}
|
||||||
|
|
||||||
|
configsDir := filepath.Join(src, "configs")
|
||||||
|
templateDir := filepath.Join(src, "build/templates")
|
||||||
|
|
||||||
|
noTests := 0
|
||||||
|
skippedTests := make([]string, 0, 10)
|
||||||
|
|
||||||
|
err := filepath.Walk(filepath.Join(configsDir, "coins"), func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() || info.Name()[0] == '.' {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n := strings.TrimSuffix(info.Name(), ".json")
|
||||||
|
c, err := build.LoadConfig(configsDir, n)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: cannot load configuration: %s", n, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(c.IntegrationTests["rpc"]) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := makeBlockChainConfig(c, templateDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: cannot make blockchain config: %s", n, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(c.Coin.Alias, func(t *testing.T) {
|
||||||
|
noTests += 1
|
||||||
|
err := runTests(t, c.Coin.Name, c.Coin.Alias, cfg, c.IntegrationTests["rpc"])
|
||||||
|
if err != nil {
|
||||||
|
if err == notConnectedError {
|
||||||
|
skippedTests = append(skippedTests, c.Coin.Alias)
|
||||||
|
t.Skip(err)
|
||||||
|
}
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(skippedTests) > 0 {
|
||||||
|
t.Errorf("Too many skipped tests: %q", skippedTests)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBlockChainConfig(c *build.Config, templateDir string) (json.RawMessage, error) {
|
||||||
|
outputDir, err := ioutil.TempDir("", "rpc_test")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(outputDir)
|
||||||
|
|
||||||
|
err = build.GeneratePackageDefinitions(c, templateDir, outputDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadFile(filepath.Join(outputDir, "blockbook", "blockchaincfg.json"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var v json.RawMessage
|
||||||
|
err = json.Unmarshal(b, &v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTests(t *testing.T, coinName, coinAlias string, cfg json.RawMessage, tests []string) error {
|
||||||
|
cli, err := initBlockChain(coinName, cfg)
|
||||||
|
if err != nil {
|
||||||
|
if err == notConnectedError {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
td, err := LoadTestData(coinAlias, cli.GetChainParser())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test data loading failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if td.TxDetails != nil {
|
||||||
|
parser := cli.GetChainParser()
|
||||||
|
|
||||||
|
for _, tx := range td.TxDetails {
|
||||||
|
err := setTxAddresses(parser, tx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Test data loading failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h := TestHandler{Client: cli, TestData: td}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
if f, found := testMap[test]; found {
|
||||||
|
t.Run(test, func(t *testing.T) { f(t, &h) })
|
||||||
|
} else {
|
||||||
|
t.Errorf("%s: test not found", test)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initBlockChain(coinName string, cfg json.RawMessage) (bchain.BlockChain, error) {
|
||||||
|
factory, found := coins.BlockChainFactories[coinName]
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("Factory function not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
cli, err := factory(cfg, func(_ bchain.NotificationType) {})
|
||||||
|
if err != nil {
|
||||||
|
if isNetError(err) {
|
||||||
|
return nil, notConnectedError
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Factory function failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cli.Initialize()
|
||||||
|
if err != nil {
|
||||||
|
if isNetError(err) {
|
||||||
|
return nil, notConnectedError
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("BlockChain initialization failed: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cli, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNetError(err error) bool {
|
||||||
|
if _, ok := err.(net.Error); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTxAddresses(parser bchain.BlockChainParser, tx *bchain.Tx) error {
|
||||||
|
// pack and unpack transaction in order to get addresses decoded - ugly but works
|
||||||
|
var tmp *bchain.Tx
|
||||||
|
b, err := parser.PackTx(tx, 0, 0)
|
||||||
|
if err == nil {
|
||||||
|
tmp, _, err = parser.UnpackTx(b)
|
||||||
|
if err == nil {
|
||||||
|
for i := 0; i < len(tx.Vout); i++ {
|
||||||
|
tx.Vout[i].ScriptPubKey.Addresses = tmp.Vout[i].ScriptPubKey.Addresses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetBlockHash(t *testing.T, h *TestHandler) {
|
||||||
|
hash, err := h.Client.GetBlockHash(h.TestData.BlockHeight)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if hash != h.TestData.BlockHash {
|
||||||
|
t.Errorf("GetBlockHash() got %q, want %q", hash, h.TestData.BlockHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func testGetBlock(t *testing.T, h *TestHandler) {
|
||||||
|
blk, err := h.Client.GetBlock(h.TestData.BlockHash, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(blk.Txs) != len(h.TestData.BlockTxs) {
|
||||||
|
t.Errorf("GetBlock() number of transactions: got %d, want %d", len(blk.Txs), len(h.TestData.BlockTxs))
|
||||||
|
}
|
||||||
|
|
||||||
|
for ti, tx := range blk.Txs {
|
||||||
|
if tx.Txid != h.TestData.BlockTxs[ti] {
|
||||||
|
t.Errorf("GetBlock() transaction %d: got %s, want %s", ti, tx.Txid, h.TestData.BlockTxs[ti])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func testGetTransaction(t *testing.T, h *TestHandler) {
|
||||||
|
for txid, want := range h.TestData.TxDetails {
|
||||||
|
got, err := h.Client.GetTransaction(txid)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Confirmations is variable field, we just check if is set and reset it
|
||||||
|
if got.Confirmations <= 0 {
|
||||||
|
t.Errorf("GetTransaction() got struct with invalid Confirmations field")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
got.Confirmations = 0
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetTransaction() got %+v, want %+v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func testGetTransactionForMempool(t *testing.T, h *TestHandler) {
|
||||||
|
for txid, want := range h.TestData.TxDetails {
|
||||||
|
// reset fields that are not parsed by BlockChainParser
|
||||||
|
want.Confirmations, want.Blocktime, want.Time = 0, 0, 0
|
||||||
|
|
||||||
|
got, err := h.Client.GetTransactionForMempool(txid)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// transactions parsed from JSON may contain additional data
|
||||||
|
got.Confirmations, got.Blocktime, got.Time = 0, 0, 0
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetTransactionForMempool() got %+v, want %+v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func testMempoolSync(t *testing.T, h *TestHandler) {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
txs := getMempool(t, h)
|
||||||
|
|
||||||
|
n, err := h.Client.ResyncMempool(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
// no transactions to test
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
txs = intersect(txs, getMempool(t, h))
|
||||||
|
if len(txs) == 0 {
|
||||||
|
// no transactions to test
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
txid2addrs := getMempoolAddresses(t, h, txs)
|
||||||
|
if len(txid2addrs) == 0 {
|
||||||
|
t.Skip("Skipping test, no addresses in mempool")
|
||||||
|
}
|
||||||
|
|
||||||
|
for txid, addrs := range txid2addrs {
|
||||||
|
for _, a := range addrs {
|
||||||
|
got, err := h.Client.GetMempoolTransactions(a)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !containsString(got, txid) {
|
||||||
|
t.Errorf("ResyncMempool() - for address %s, transaction %s wasn't found in mempool", a, txid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Skip("Skipping test, all attempts to sync mempool failed due to network state changes")
|
||||||
|
}
|
||||||
|
func testEstimateSmartFee(t *testing.T, h *TestHandler) {
|
||||||
|
for _, blocks := range []int{1, 2, 3, 5, 10} {
|
||||||
|
fee, err := h.Client.EstimateSmartFee(blocks, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if fee.Sign() == -1 {
|
||||||
|
sf := h.Client.GetChainParser().AmountToDecimalString(&fee)
|
||||||
|
if sf != "-1" {
|
||||||
|
t.Errorf("EstimateSmartFee() returned unexpected fee rate: %v", sf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func testEstimateFee(t *testing.T, h *TestHandler) {
|
||||||
|
for _, blocks := range []int{1, 2, 3, 5, 10} {
|
||||||
|
fee, err := h.Client.EstimateFee(blocks)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if fee.Sign() == -1 {
|
||||||
|
sf := h.Client.GetChainParser().AmountToDecimalString(&fee)
|
||||||
|
if sf != "-1" {
|
||||||
|
t.Errorf("EstimateFee() returned unexpected fee rate: %v", sf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func testGetBestBlockHash(t *testing.T, h *TestHandler) {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
hash, err := h.Client.GetBestBlockHash()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
height, err := h.Client.GetBestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hh, err := h.Client.GetBlockHash(height)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if hash != hh {
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// we expect no next block
|
||||||
|
_, err = h.Client.GetBlock("", height+1)
|
||||||
|
if err != nil {
|
||||||
|
if err != bchain.ErrBlockNotFound {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Error("GetBestBlockHash() didn't get the best hash")
|
||||||
|
}
|
||||||
|
func testGetBestBlockHeight(t *testing.T, h *TestHandler) {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
height, err := h.Client.GetBestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we expect no next block
|
||||||
|
_, err = h.Client.GetBlock("", height+1)
|
||||||
|
if err != nil {
|
||||||
|
if err != bchain.ErrBlockNotFound {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Error("GetBestBlockHeigh() didn't get the the best heigh")
|
||||||
|
}
|
||||||
|
func testGetBlockHeader(t *testing.T, h *TestHandler) {
|
||||||
|
want := &bchain.BlockHeader{
|
||||||
|
Hash: h.TestData.BlockHash,
|
||||||
|
Height: h.TestData.BlockHeight,
|
||||||
|
Time: h.TestData.BlockTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := h.Client.GetBlockHeader(h.TestData.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirmations is variable field, we just check if is set and reset it
|
||||||
|
if got.Confirmations <= 0 {
|
||||||
|
t.Fatalf("GetBlockHeader() got struct with invalid Confirmations field")
|
||||||
|
}
|
||||||
|
got.Confirmations = 0
|
||||||
|
|
||||||
|
got.Prev, got.Next = "", ""
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetBlockHeader() got=%+v, want=%+v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMempool(t *testing.T, h *TestHandler) []string {
|
||||||
|
txs, err := h.Client.GetMempool()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(txs) == 0 {
|
||||||
|
t.Skip("Skipping test, mempool is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return txs
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMempoolAddresses(t *testing.T, h *TestHandler, txs []string) map[string][]string {
|
||||||
|
txid2addrs := map[string][]string{}
|
||||||
|
for i := 0; i < len(txs); i++ {
|
||||||
|
tx, err := h.Client.GetTransactionForMempool(txs[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
addrs := []string{}
|
||||||
|
for _, vin := range tx.Vin {
|
||||||
|
for _, a := range vin.Addresses {
|
||||||
|
addrs = append(addrs, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, vout := range tx.Vout {
|
||||||
|
for _, a := range vout.ScriptPubKey.Addresses {
|
||||||
|
addrs = append(addrs, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(addrs) > 0 {
|
||||||
|
txid2addrs[tx.Txid] = addrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return txid2addrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func intersect(a, b []string) []string {
|
||||||
|
setA := mapset.NewSet()
|
||||||
|
for _, v := range a {
|
||||||
|
setA.Add(v)
|
||||||
|
}
|
||||||
|
setB := mapset.NewSet()
|
||||||
|
for _, v := range b {
|
||||||
|
setB.Add(v)
|
||||||
|
}
|
||||||
|
inter := setA.Intersect(setB)
|
||||||
|
res := make([]string, 0, inter.Cardinality())
|
||||||
|
for v := range inter.Iter() {
|
||||||
|
res = append(res, v.(string))
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsString(slice []string, s string) bool {
|
||||||
|
for i := 0; i < len(slice); i++ {
|
||||||
|
if slice[i] == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@ -4,17 +4,20 @@ VERSION ?= devel
|
|||||||
GITCOMMIT = $(shell cd /src && git describe --tags --always --dirty)
|
GITCOMMIT = $(shell cd /src && git describe --tags --always --dirty)
|
||||||
BUILDTIME = $(shell date --iso-8601=seconds)
|
BUILDTIME = $(shell date --iso-8601=seconds)
|
||||||
LDFLAGS := -X blockbook/common.version=$(VERSION) -X blockbook/common.gitcommit=$(GITCOMMIT) -X blockbook/common.buildtime=$(BUILDTIME)
|
LDFLAGS := -X blockbook/common.version=$(VERSION) -X blockbook/common.gitcommit=$(GITCOMMIT) -X blockbook/common.buildtime=$(BUILDTIME)
|
||||||
|
BLOCKBOOK_SRC := $(GOPATH)/src/blockbook
|
||||||
ARGS ?=
|
ARGS ?=
|
||||||
|
|
||||||
|
export BLOCKBOOK_SRC
|
||||||
|
|
||||||
all: build tools
|
all: build tools
|
||||||
|
|
||||||
build: prepare-sources
|
build: prepare-sources
|
||||||
cd $(GOPATH)/src/blockbook && go build -o $(CURDIR)/blockbook -ldflags="-s -w $(LDFLAGS)" $(ARGS)
|
cd $(BLOCKBOOK_SRC) && go build -o $(CURDIR)/blockbook -ldflags="-s -w $(LDFLAGS)" $(ARGS)
|
||||||
cp $(CURDIR)/blockbook /out/blockbook
|
cp $(CURDIR)/blockbook /out/blockbook
|
||||||
chown $(PACKAGER) /out/blockbook
|
chown $(PACKAGER) /out/blockbook
|
||||||
|
|
||||||
build-debug: prepare-sources
|
build-debug: prepare-sources
|
||||||
cd $(GOPATH)/src/blockbook && go build -o $(CURDIR)/blockbook -ldflags="$(LDFLAGS)" $(ARGS)
|
cd $(BLOCKBOOK_SRC) && go build -o $(CURDIR)/blockbook -ldflags="$(LDFLAGS)" $(ARGS)
|
||||||
cp $(CURDIR)/blockbook /out/blockbook
|
cp $(CURDIR)/blockbook /out/blockbook
|
||||||
chown $(PACKAGER) /out/blockbook
|
chown $(PACKAGER) /out/blockbook
|
||||||
|
|
||||||
@ -23,20 +26,20 @@ tools:
|
|||||||
chown $(PACKAGER) /out/{ldb,sst_dump}
|
chown $(PACKAGER) /out/{ldb,sst_dump}
|
||||||
|
|
||||||
test: prepare-sources
|
test: prepare-sources
|
||||||
cd $(GOPATH)/src/blockbook && go test -tags unittest `go list ./... | grep -v '^blockbook/contrib'` $(ARGS)
|
cd $(BLOCKBOOK_SRC) && go test -tags unittest `go list ./... | grep -v '^blockbook/contrib'` $(ARGS)
|
||||||
|
|
||||||
test-all: prepare-sources
|
test-all: prepare-sources
|
||||||
cd $(GOPATH)/src/blockbook && go test -tags 'unittest integration' `go list ./... | grep -v '^blockbook/contrib'` $(ARGS)
|
cd $(BLOCKBOOK_SRC) && go test -tags 'unittest integration' `go list ./... | grep -v '^blockbook/contrib'` $(ARGS)
|
||||||
|
|
||||||
prepare-sources:
|
prepare-sources:
|
||||||
@ [ -n "`ls /src 2> /dev/null`" ] || (echo "/src doesn't exist or is empty" 1>&2 && exit 1)
|
@ [ -n "`ls /src 2> /dev/null`" ] || (echo "/src doesn't exist or is empty" 1>&2 && exit 1)
|
||||||
[ -d $(GOPATH)/src/blockbook ] || cp -r /src $(GOPATH)/src/blockbook
|
[ -d $(BLOCKBOOK_SRC) ] || cp -r /src $(BLOCKBOOK_SRC)
|
||||||
$(MAKE) prepare-vendor
|
$(MAKE) prepare-vendor
|
||||||
|
|
||||||
prepare-vendor:
|
prepare-vendor:
|
||||||
@ if [ "$(UPDATE_VENDOR)" -eq 1 ]; then \
|
@ if [ "$(UPDATE_VENDOR)" -eq 1 ]; then \
|
||||||
echo "Updating vendor"; \
|
echo "Updating vendor"; \
|
||||||
rm -rf $(GOPATH)/src/blockbook/vendor && cd $(GOPATH)/src/blockbook && dep ensure -vendor-only ; \
|
rm -rf $(BLOCKBOOK_SRC)/vendor && cd $(BLOCKBOOK_SRC) && dep ensure -vendor-only ; \
|
||||||
else \
|
else \
|
||||||
echo "Update of vendor not demanded, keeping version from src" ; \
|
echo "Update of vendor not demanded, keeping version from src" ; \
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -1,126 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"blockbook/build/tools"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
configsDir = "configs"
|
configsDir = "configs"
|
||||||
inputDir = "build/templates"
|
templateDir = "build/templates"
|
||||||
outputDir = "build/pkg-defs"
|
outputDir = "build/pkg-defs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Meta struct {
|
|
||||||
BuildDatetime string // generated field
|
|
||||||
PackageMaintainer string `json:"package_maintainer"`
|
|
||||||
PackageMaintainerEmail string `json:"package_maintainer_email"`
|
|
||||||
}
|
|
||||||
Env struct {
|
|
||||||
Version string `json:"version"`
|
|
||||||
BackendInstallPath string `json:"backend_install_path"`
|
|
||||||
BackendDataPath string `json:"backend_data_path"`
|
|
||||||
BlockbookInstallPath string `json:"blockbook_install_path"`
|
|
||||||
BlockbookDataPath string `json:"blockbook_data_path"`
|
|
||||||
} `json:"env"`
|
|
||||||
Coin struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Shortcut string `json:"shortcut"`
|
|
||||||
Label string `json:"label"`
|
|
||||||
Alias string `json:"alias"`
|
|
||||||
} `json:"coin"`
|
|
||||||
Ports struct {
|
|
||||||
BackendRPC int `json:"backend_rpc"`
|
|
||||||
BackendMessageQueue int `json:"backend_message_queue"`
|
|
||||||
BlockbookInternal int `json:"blockbook_internal"`
|
|
||||||
BlockbookPublic int `json:"blockbook_public"`
|
|
||||||
} `json:"ports"`
|
|
||||||
IPC struct {
|
|
||||||
RPCURLTemplate string `json:"rpc_url_template"`
|
|
||||||
RPCUser string `json:"rpc_user"`
|
|
||||||
RPCPass string `json:"rpc_pass"`
|
|
||||||
RPCTimeout int `json:"rpc_timeout"`
|
|
||||||
MessageQueueBindingTemplate string `json:"message_queue_binding_template"`
|
|
||||||
} `json:"ipc"`
|
|
||||||
Backend struct {
|
|
||||||
PackageName string `json:"package_name"`
|
|
||||||
PackageRevision string `json:"package_revision"`
|
|
||||||
SystemUser string `json:"system_user"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
BinaryURL string `json:"binary_url"`
|
|
||||||
VerificationType string `json:"verification_type"`
|
|
||||||
VerificationSource string `json:"verification_source"`
|
|
||||||
ExtractCommand string `json:"extract_command"`
|
|
||||||
ExcludeFiles []string `json:"exclude_files"`
|
|
||||||
ExecCommandTemplate string `json:"exec_command_template"`
|
|
||||||
LogrotateFilesTemplate string `json:"logrotate_files_template"`
|
|
||||||
PostinstScriptTemplate string `json:"postinst_script_template"`
|
|
||||||
ServiceType string `json:"service_type"`
|
|
||||||
ServiceAdditionalParamsTemplate string `json:"service_additional_params_template"`
|
|
||||||
ProtectMemory bool `json:"protect_memory"`
|
|
||||||
Mainnet bool `json:"mainnet"`
|
|
||||||
ConfigFile string `json:"config_file"`
|
|
||||||
AdditionalParams interface{} `json:"additional_params"`
|
|
||||||
} `json:"backend"`
|
|
||||||
Blockbook struct {
|
|
||||||
PackageName string `json:"package_name"`
|
|
||||||
SystemUser string `json:"system_user"`
|
|
||||||
InternalBindingTemplate string `json:"internal_binding_template"`
|
|
||||||
PublicBindingTemplate string `json:"public_binding_template"`
|
|
||||||
ExplorerURL string `json:"explorer_url"`
|
|
||||||
AdditionalParams string `json:"additional_params"`
|
|
||||||
BlockChain struct {
|
|
||||||
Parse bool `json:"parse"`
|
|
||||||
Subversion string `json:"subversion"`
|
|
||||||
AddressFormat string `json:"address_format"`
|
|
||||||
MempoolWorkers int `json:"mempool_workers"`
|
|
||||||
MempoolSubWorkers int `json:"mempool_sub_workers"`
|
|
||||||
BlockAddressesToKeep int `json:"block_addresses_to_keep"`
|
|
||||||
AdditionalParams map[string]json.RawMessage `json:"additional_params"`
|
|
||||||
} `json:"block_chain"`
|
|
||||||
} `json:"blockbook"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsonToString(msg json.RawMessage) (string, error) {
|
|
||||||
d, err := msg.MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(d), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) ParseTemplate() *template.Template {
|
|
||||||
templates := map[string]string{
|
|
||||||
"IPC.RPCURLTemplate": c.IPC.RPCURLTemplate,
|
|
||||||
"IPC.MessageQueueBindingTemplate": c.IPC.MessageQueueBindingTemplate,
|
|
||||||
"Backend.ExecCommandTemplate": c.Backend.ExecCommandTemplate,
|
|
||||||
"Backend.LogrotateFilesTemplate": c.Backend.LogrotateFilesTemplate,
|
|
||||||
"Backend.PostinstScriptTemplate": c.Backend.PostinstScriptTemplate,
|
|
||||||
"Backend.ServiceAdditionalParamsTemplate": c.Backend.ServiceAdditionalParamsTemplate,
|
|
||||||
"Blockbook.InternalBindingTemplate": c.Blockbook.InternalBindingTemplate,
|
|
||||||
"Blockbook.PublicBindingTemplate": c.Blockbook.PublicBindingTemplate,
|
|
||||||
}
|
|
||||||
|
|
||||||
funcMap := template.FuncMap{
|
|
||||||
"jsonToString": jsonToString,
|
|
||||||
}
|
|
||||||
|
|
||||||
t := template.New("").Funcs(funcMap)
|
|
||||||
|
|
||||||
for name, def := range templates {
|
|
||||||
t = template.Must(t.Parse(fmt.Sprintf(`{{define "%s"}}%s{{end}}`, name, def)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
var coins []string
|
var coins []string
|
||||||
@ -136,171 +29,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
coin := os.Args[1]
|
coin := os.Args[1]
|
||||||
config := loadConfig(coin)
|
config, err := build.LoadConfig(configsDir, coin)
|
||||||
generatePackageDefinitions(config)
|
if err == nil {
|
||||||
|
err = build.GeneratePackageDefinitions(config, templateDir, outputDir)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
fmt.Printf("Package files for %v generated to %v\n", coin, outputDir)
|
fmt.Printf("Package files for %v generated to %v\n", coin, outputDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig(coin string) *Config {
|
|
||||||
config := new(Config)
|
|
||||||
|
|
||||||
f, err := os.Open(filepath.Join(configsDir, "coins", coin+".json"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
d := json.NewDecoder(f)
|
|
||||||
err = d.Decode(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err = os.Open(filepath.Join(configsDir, "environ.json"))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
d = json.NewDecoder(f)
|
|
||||||
err = d.Decode(&config.Env)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Meta.BuildDatetime = time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700")
|
|
||||||
|
|
||||||
if !isEmpty(config, "backend") {
|
|
||||||
switch config.Backend.ServiceType {
|
|
||||||
case "forking":
|
|
||||||
case "simple":
|
|
||||||
default:
|
|
||||||
panic("Invalid service type: " + config.Backend.ServiceType)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch config.Backend.VerificationType {
|
|
||||||
case "":
|
|
||||||
case "gpg":
|
|
||||||
case "sha256":
|
|
||||||
case "gpg-sha256":
|
|
||||||
default:
|
|
||||||
panic("Invalid verification type: " + config.Backend.VerificationType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEmpty(config *Config, target string) bool {
|
|
||||||
switch target {
|
|
||||||
case "backend":
|
|
||||||
return config.Backend.PackageName == ""
|
|
||||||
case "blockbook":
|
|
||||||
return config.Blockbook.PackageName == ""
|
|
||||||
default:
|
|
||||||
panic("Invalid target name: " + target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generatePackageDefinitions(config *Config) {
|
|
||||||
templ := config.ParseTemplate()
|
|
||||||
|
|
||||||
makeOutputDir(outputDir)
|
|
||||||
|
|
||||||
for _, subdir := range []string{"backend", "blockbook"} {
|
|
||||||
if isEmpty(config, subdir) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
root := filepath.Join(inputDir, subdir)
|
|
||||||
|
|
||||||
err := os.Mkdir(filepath.Join(outputDir, subdir), 0755)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %s", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if path == root {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if filepath.Base(path)[0] == '.' {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
subpath := path[len(root)-len(subdir):]
|
|
||||||
|
|
||||||
if info.IsDir() {
|
|
||||||
err = os.Mkdir(filepath.Join(outputDir, subpath), info.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %s", path, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
t := template.Must(templ.Clone())
|
|
||||||
t = template.Must(t.ParseFiles(path))
|
|
||||||
|
|
||||||
err = writeTemplate(filepath.Join(outputDir, subpath), info, t, config)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %s", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isEmpty(config, "backend") {
|
|
||||||
writeBackendConfigFile(config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeOutputDir(path string) {
|
|
||||||
err := os.RemoveAll(path)
|
|
||||||
if err == nil {
|
|
||||||
err = os.Mkdir(path, 0755)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTemplate(path string, info os.FileInfo, templ *template.Template, config *Config) error {
|
|
||||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, info.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
err = templ.ExecuteTemplate(f, "main", config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBackendConfigFile(config *Config) {
|
|
||||||
out, err := os.OpenFile(filepath.Join(outputDir, "backend/backend.conf"), os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer out.Close()
|
|
||||||
|
|
||||||
if config.Backend.ConfigFile == "" {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
in, err := os.Open(filepath.Join(outputDir, "backend/config", config.Backend.ConfigFile))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer in.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(out, in)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
288
build/tools/templates.go
Normal file
288
build/tools/templates.go
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
package build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Meta struct {
|
||||||
|
BuildDatetime string // generated field
|
||||||
|
PackageMaintainer string `json:"package_maintainer"`
|
||||||
|
PackageMaintainerEmail string `json:"package_maintainer_email"`
|
||||||
|
}
|
||||||
|
Env struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
BackendInstallPath string `json:"backend_install_path"`
|
||||||
|
BackendDataPath string `json:"backend_data_path"`
|
||||||
|
BlockbookInstallPath string `json:"blockbook_install_path"`
|
||||||
|
BlockbookDataPath string `json:"blockbook_data_path"`
|
||||||
|
} `json:"env"`
|
||||||
|
Coin struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Shortcut string `json:"shortcut"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
} `json:"coin"`
|
||||||
|
Ports struct {
|
||||||
|
BackendRPC int `json:"backend_rpc"`
|
||||||
|
BackendMessageQueue int `json:"backend_message_queue"`
|
||||||
|
BlockbookInternal int `json:"blockbook_internal"`
|
||||||
|
BlockbookPublic int `json:"blockbook_public"`
|
||||||
|
} `json:"ports"`
|
||||||
|
IPC struct {
|
||||||
|
RPCURLTemplate string `json:"rpc_url_template"`
|
||||||
|
RPCUser string `json:"rpc_user"`
|
||||||
|
RPCPass string `json:"rpc_pass"`
|
||||||
|
RPCTimeout int `json:"rpc_timeout"`
|
||||||
|
MessageQueueBindingTemplate string `json:"message_queue_binding_template"`
|
||||||
|
} `json:"ipc"`
|
||||||
|
Backend struct {
|
||||||
|
PackageName string `json:"package_name"`
|
||||||
|
PackageRevision string `json:"package_revision"`
|
||||||
|
SystemUser string `json:"system_user"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
BinaryURL string `json:"binary_url"`
|
||||||
|
VerificationType string `json:"verification_type"`
|
||||||
|
VerificationSource string `json:"verification_source"`
|
||||||
|
ExtractCommand string `json:"extract_command"`
|
||||||
|
ExcludeFiles []string `json:"exclude_files"`
|
||||||
|
ExecCommandTemplate string `json:"exec_command_template"`
|
||||||
|
LogrotateFilesTemplate string `json:"logrotate_files_template"`
|
||||||
|
PostinstScriptTemplate string `json:"postinst_script_template"`
|
||||||
|
ServiceType string `json:"service_type"`
|
||||||
|
ServiceAdditionalParamsTemplate string `json:"service_additional_params_template"`
|
||||||
|
ProtectMemory bool `json:"protect_memory"`
|
||||||
|
Mainnet bool `json:"mainnet"`
|
||||||
|
ConfigFile string `json:"config_file"`
|
||||||
|
AdditionalParams interface{} `json:"additional_params"`
|
||||||
|
} `json:"backend"`
|
||||||
|
Blockbook struct {
|
||||||
|
PackageName string `json:"package_name"`
|
||||||
|
SystemUser string `json:"system_user"`
|
||||||
|
InternalBindingTemplate string `json:"internal_binding_template"`
|
||||||
|
PublicBindingTemplate string `json:"public_binding_template"`
|
||||||
|
ExplorerURL string `json:"explorer_url"`
|
||||||
|
AdditionalParams string `json:"additional_params"`
|
||||||
|
BlockChain struct {
|
||||||
|
Parse bool `json:"parse"`
|
||||||
|
Subversion string `json:"subversion"`
|
||||||
|
AddressFormat string `json:"address_format"`
|
||||||
|
MempoolWorkers int `json:"mempool_workers"`
|
||||||
|
MempoolSubWorkers int `json:"mempool_sub_workers"`
|
||||||
|
BlockAddressesToKeep int `json:"block_addresses_to_keep"`
|
||||||
|
AdditionalParams map[string]json.RawMessage `json:"additional_params"`
|
||||||
|
} `json:"block_chain"`
|
||||||
|
} `json:"blockbook"`
|
||||||
|
IntegrationTests map[string][]string `json:"integration_tests"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonToString(msg json.RawMessage) (string, error) {
|
||||||
|
d, err := msg.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(d), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) ParseTemplate() *template.Template {
|
||||||
|
templates := map[string]string{
|
||||||
|
"IPC.RPCURLTemplate": c.IPC.RPCURLTemplate,
|
||||||
|
"IPC.MessageQueueBindingTemplate": c.IPC.MessageQueueBindingTemplate,
|
||||||
|
"Backend.ExecCommandTemplate": c.Backend.ExecCommandTemplate,
|
||||||
|
"Backend.LogrotateFilesTemplate": c.Backend.LogrotateFilesTemplate,
|
||||||
|
"Backend.PostinstScriptTemplate": c.Backend.PostinstScriptTemplate,
|
||||||
|
"Backend.ServiceAdditionalParamsTemplate": c.Backend.ServiceAdditionalParamsTemplate,
|
||||||
|
"Blockbook.InternalBindingTemplate": c.Blockbook.InternalBindingTemplate,
|
||||||
|
"Blockbook.PublicBindingTemplate": c.Blockbook.PublicBindingTemplate,
|
||||||
|
}
|
||||||
|
|
||||||
|
funcMap := template.FuncMap{
|
||||||
|
"jsonToString": jsonToString,
|
||||||
|
}
|
||||||
|
|
||||||
|
t := template.New("").Funcs(funcMap)
|
||||||
|
|
||||||
|
for name, def := range templates {
|
||||||
|
t = template.Must(t.Parse(fmt.Sprintf(`{{define "%s"}}%s{{end}}`, name, def)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig(configsDir, coin string) (*Config, error) {
|
||||||
|
config := new(Config)
|
||||||
|
|
||||||
|
f, err := os.Open(filepath.Join(configsDir, "coins", coin+".json"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d := json.NewDecoder(f)
|
||||||
|
err = d.Decode(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err = os.Open(filepath.Join(configsDir, "environ.json"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d = json.NewDecoder(f)
|
||||||
|
err = d.Decode(&config.Env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Meta.BuildDatetime = time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700")
|
||||||
|
|
||||||
|
if !isEmpty(config, "backend") {
|
||||||
|
switch config.Backend.ServiceType {
|
||||||
|
case "forking":
|
||||||
|
case "simple":
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Invalid service type: %s", config.Backend.ServiceType)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch config.Backend.VerificationType {
|
||||||
|
case "":
|
||||||
|
case "gpg":
|
||||||
|
case "sha256":
|
||||||
|
case "gpg-sha256":
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Invalid verification type: %s", config.Backend.VerificationType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEmpty(config *Config, target string) bool {
|
||||||
|
switch target {
|
||||||
|
case "backend":
|
||||||
|
return config.Backend.PackageName == ""
|
||||||
|
case "blockbook":
|
||||||
|
return config.Blockbook.PackageName == ""
|
||||||
|
default:
|
||||||
|
panic("Invalid target name: " + target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GeneratePackageDefinitions(config *Config, templateDir, outputDir string) error {
|
||||||
|
templ := config.ParseTemplate()
|
||||||
|
|
||||||
|
err := makeOutputDir(outputDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subdir := range []string{"backend", "blockbook"} {
|
||||||
|
if isEmpty(config, subdir) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
root := filepath.Join(templateDir, subdir)
|
||||||
|
|
||||||
|
err = os.Mkdir(filepath.Join(outputDir, subdir), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %s", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if path == root {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if filepath.Base(path)[0] == '.' {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
subpath := path[len(root)-len(subdir):]
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
err = os.Mkdir(filepath.Join(outputDir, subpath), info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %s", path, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := template.Must(templ.Clone())
|
||||||
|
t = template.Must(t.ParseFiles(path))
|
||||||
|
|
||||||
|
err = writeTemplate(filepath.Join(outputDir, subpath), info, t, config)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %s", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isEmpty(config, "backend") {
|
||||||
|
err = writeBackendConfigFile(config, outputDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeOutputDir(path string) error {
|
||||||
|
err := os.RemoveAll(path)
|
||||||
|
if err == nil {
|
||||||
|
err = os.Mkdir(path, 0755)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeTemplate(path string, info os.FileInfo, templ *template.Template, config *Config) error {
|
||||||
|
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
err = templ.ExecuteTemplate(f, "main", config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeBackendConfigFile(config *Config, outputDir string) error {
|
||||||
|
out, err := os.OpenFile(filepath.Join(outputDir, "backend/backend.conf"), os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
if config.Backend.ConfigFile == "" {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
in, err := os.Open(filepath.Join(outputDir, "backend/config", config.Backend.ConfigFile))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer in.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(out, in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -59,5 +59,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,5 +59,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,5 +60,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,5 +60,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,5 +61,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,5 +61,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,5 +63,8 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,5 +53,8 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,5 +60,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,5 +60,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "wakiyamap",
|
"package_maintainer": "wakiyamap",
|
||||||
"package_maintainer_email": "wakiyamap@gmail.com"
|
"package_maintainer_email": "wakiyamap@gmail.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,5 +67,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,5 +58,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,5 +60,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,5 +60,9 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"package_maintainer": "Jakub Matys",
|
"package_maintainer": "Jakub Matys",
|
||||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||||
|
},
|
||||||
|
"integration_tests": {
|
||||||
|
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||||
|
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user