Merge branch 'integration-tests-upgrade' into v0.0.7
This commit is contained in:
commit
f171fe8362
@ -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,29 +27,29 @@ import (
|
||||
|
||||
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() {
|
||||
blockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
|
||||
blockChainFactories["Testnet"] = btc.NewBitcoinRPC
|
||||
blockChainFactories["Zcash"] = zec.NewZCashRPC
|
||||
blockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
|
||||
blockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
||||
blockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
|
||||
blockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
||||
blockChainFactories["Bcash"] = bch.NewBCashRPC
|
||||
blockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
||||
blockChainFactories["Bgold"] = btg.NewBGoldRPC
|
||||
blockChainFactories["Dash"] = dash.NewDashRPC
|
||||
blockChainFactories["Dash Testnet"] = dash.NewDashRPC
|
||||
blockChainFactories["Litecoin"] = litecoin.NewLitecoinRPC
|
||||
blockChainFactories["Litecoin Testnet"] = litecoin.NewLitecoinRPC
|
||||
blockChainFactories["Dogecoin"] = dogecoin.NewDogecoinRPC
|
||||
blockChainFactories["Vertcoin"] = vertcoin.NewVertcoinRPC
|
||||
blockChainFactories["Vertcoin Testnet"] = vertcoin.NewVertcoinRPC
|
||||
blockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC
|
||||
blockChainFactories["Monacoin"] = monacoin.NewMonacoinRPC
|
||||
blockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
|
||||
BlockChainFactories["Bitcoin"] = btc.NewBitcoinRPC
|
||||
BlockChainFactories["Testnet"] = btc.NewBitcoinRPC
|
||||
BlockChainFactories["Zcash"] = zec.NewZCashRPC
|
||||
BlockChainFactories["Zcash Testnet"] = zec.NewZCashRPC
|
||||
BlockChainFactories["Ethereum"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Classic"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Ethereum Testnet Ropsten"] = eth.NewEthereumRPC
|
||||
BlockChainFactories["Bcash"] = bch.NewBCashRPC
|
||||
BlockChainFactories["Bcash Testnet"] = bch.NewBCashRPC
|
||||
BlockChainFactories["Bgold"] = btg.NewBGoldRPC
|
||||
BlockChainFactories["Dash"] = dash.NewDashRPC
|
||||
BlockChainFactories["Dash Testnet"] = dash.NewDashRPC
|
||||
BlockChainFactories["Litecoin"] = litecoin.NewLitecoinRPC
|
||||
BlockChainFactories["Litecoin Testnet"] = litecoin.NewLitecoinRPC
|
||||
BlockChainFactories["Dogecoin"] = dogecoin.NewDogecoinRPC
|
||||
BlockChainFactories["Vertcoin"] = vertcoin.NewVertcoinRPC
|
||||
BlockChainFactories["Vertcoin Testnet"] = vertcoin.NewVertcoinRPC
|
||||
BlockChainFactories["Namecoin"] = namecoin.NewNamecoinRPC
|
||||
BlockChainFactories["Monacoin"] = monacoin.NewMonacoinRPC
|
||||
BlockChainFactories["Monacoin Testnet"] = monacoin.NewMonacoinRPC
|
||||
}
|
||||
|
||||
// GetCoinNameFromConfig gets coin name and coin shortcut from config file
|
||||
@ -80,9 +80,9 @@ func NewBlockChain(coin string, configfile string, pushHandler func(bchain.Notif
|
||||
if err != nil {
|
||||
return nil, errors.Annotatef(err, "Error parsing file %v", configfile)
|
||||
}
|
||||
bcf, ok := blockChainFactories[coin]
|
||||
bcf, ok := BlockChainFactories[coin]
|
||||
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)
|
||||
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"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"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) {
|
||||
idx := strings.IndexRune(p2, filepath.Separator)
|
||||
if idx <= 0 {
|
||||
@ -42,46 +49,6 @@ func readDataFile(dir, relDir, filename string) ([]byte, error) {
|
||||
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) {
|
||||
b, err := readDataFile(".", "bchain/tests/rpc/testdata", coin+".json")
|
||||
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.GetChainInfo()
|
||||
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)
|
||||
}
|
||||
}
|
||||
492
bchain/tests/rpc/rpc_test.go
Normal file
492
bchain/tests/rpc/rpc_test.go
Normal file
@ -0,0 +1,492 @@
|
||||
// +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 due to connection issues: %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 {
|
||||
if isSearchableAddr(a) {
|
||||
addrs = append(addrs, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, vout := range tx.Vout {
|
||||
for _, a := range vout.ScriptPubKey.Addresses {
|
||||
if isSearchableAddr(a) {
|
||||
addrs = append(addrs, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(addrs) > 0 {
|
||||
txid2addrs[tx.Txid] = addrs
|
||||
}
|
||||
}
|
||||
return txid2addrs
|
||||
}
|
||||
|
||||
func isSearchableAddr(addr string) bool {
|
||||
return len(addr) > 3 && addr[:3] != "OP_"
|
||||
}
|
||||
|
||||
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)
|
||||
BUILDTIME = $(shell date --iso-8601=seconds)
|
||||
LDFLAGS := -X blockbook/common.version=$(VERSION) -X blockbook/common.gitcommit=$(GITCOMMIT) -X blockbook/common.buildtime=$(BUILDTIME)
|
||||
BLOCKBOOK_SRC := $(GOPATH)/src/blockbook
|
||||
ARGS ?=
|
||||
|
||||
export BLOCKBOOK_SRC
|
||||
|
||||
all: build tools
|
||||
|
||||
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
|
||||
chown $(PACKAGER) /out/blockbook
|
||||
|
||||
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
|
||||
chown $(PACKAGER) /out/blockbook
|
||||
|
||||
@ -23,20 +26,20 @@ tools:
|
||||
chown $(PACKAGER) /out/{ldb,sst_dump}
|
||||
|
||||
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
|
||||
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:
|
||||
@ [ -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
|
||||
|
||||
prepare-vendor:
|
||||
@ if [ "$(UPDATE_VENDOR)" -eq 1 ]; then \
|
||||
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 \
|
||||
echo "Update of vendor not demanded, keeping version from src" ; \
|
||||
fi
|
||||
|
||||
@ -1,126 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"blockbook/build/tools"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
configsDir = "configs"
|
||||
inputDir = "build/templates"
|
||||
outputDir = "build/pkg-defs"
|
||||
configsDir = "configs"
|
||||
templateDir = "build/templates"
|
||||
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() {
|
||||
if len(os.Args) < 2 {
|
||||
var coins []string
|
||||
@ -136,171 +29,12 @@ func main() {
|
||||
}
|
||||
|
||||
coin := os.Args[1]
|
||||
config := loadConfig(coin)
|
||||
generatePackageDefinitions(config)
|
||||
config, err := build.LoadConfig(configsDir, coin)
|
||||
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)
|
||||
}
|
||||
|
||||
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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||
},
|
||||
"integration_tests": {
|
||||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
"block_chain": {
|
||||
"parse": true,
|
||||
"subversion": "/Bitcoin ABC:0.17.1/",
|
||||
"address_format": "legacy",
|
||||
"address_format": "cashaddr",
|
||||
"mempool_workers": 8,
|
||||
"mempool_sub_workers": 2,
|
||||
"block_addresses_to_keep": 300,
|
||||
@ -59,5 +59,9 @@
|
||||
"meta": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||
},
|
||||
"integration_tests": {
|
||||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,5 +53,8 @@
|
||||
"meta": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||
},
|
||||
"integration_tests": {
|
||||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,5 +60,9 @@
|
||||
"meta": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||
},
|
||||
"integration_tests": {
|
||||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||
"EstimateFee"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,5 +60,9 @@
|
||||
"meta": {
|
||||
"package_maintainer": "wakiyamap",
|
||||
"package_maintainer_email": "wakiyamap@gmail.com"
|
||||
},
|
||||
"integration_tests": {
|
||||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
|
||||
"EstimateFee"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,5 +67,9 @@
|
||||
"meta": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"package_maintainer_email": "jakub.matys@satoshilabs.com"
|
||||
},
|
||||
"integration_tests": {
|
||||
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "MempoolSync", "EstimateSmartFee",
|
||||
"EstimateFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"]
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,5 +58,9 @@
|
||||
"meta": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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": {
|
||||
"package_maintainer": "Jakub Matys",
|
||||
"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