Merge branch 'integration-tests-upgrade' into v0.0.7

This commit is contained in:
Jakub Matys 2018-10-01 12:48:32 +02:00
commit f171fe8362
46 changed files with 886 additions and 1868 deletions

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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)
}
}

View 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
}

View File

@ -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

View File

@ -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
View 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
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -63,5 +63,8 @@
"meta": {
"package_maintainer": "Jakub Matys",
"package_maintainer_email": "jakub.matys@satoshilabs.com"
},
"integration_tests": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -60,5 +60,9 @@
"meta": {
"package_maintainer": "wakiyamap",
"package_maintainer_email": "wakiyamap@gmail.com"
},
"integration_tests": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync", "EstimateSmartFee",
"EstimateFee"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}

View File

@ -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"]
}
}