Added mempool RPC/resync tests
This commit is contained in:
parent
cc29a99401
commit
757b3e39d6
@ -19,6 +19,7 @@ func getRPCClient(cfg json.RawMessage) (bchain.BlockChain, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
cli.Mempool = bchain.NewUTXOMempool(cli, cli.ChainConfig.MempoolWorkers, cli.ChainConfig.MempoolSubWorkers)
|
||||||
return cli, nil
|
return cli, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,3 +44,15 @@ func TestBitcoinRPC_GetBlock(t *testing.T) {
|
|||||||
func TestBitcoinRPC_GetTransaction(t *testing.T) {
|
func TestBitcoinRPC_GetTransaction(t *testing.T) {
|
||||||
rpcTest.TestGetTransaction(t)
|
rpcTest.TestGetTransaction(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBitcoinRPC_TestGetTransactionForMempool(t *testing.T) {
|
||||||
|
rpcTest.TestGetTransactionForMempool(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBitcoinRPC_TestMempoolSync(t *testing.T) {
|
||||||
|
rpcTest.TestMempoolSync(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBitcoinRPC_GetMempoolEntry(t *testing.T) {
|
||||||
|
rpcTest.TestGetMempoolEntry(t)
|
||||||
|
}
|
||||||
|
|||||||
@ -5,8 +5,10 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"blockbook/bchain"
|
"blockbook/bchain"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestConfig struct {
|
type TestConfig struct {
|
||||||
@ -103,6 +105,7 @@ func (rt *Test) TestGetBlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *Test) TestGetTransaction(t *testing.T) {
|
func (rt *Test) TestGetTransaction(t *testing.T) {
|
||||||
for txid, want := range rt.TestData.TxDetails {
|
for txid, want := range rt.TestData.TxDetails {
|
||||||
got, err := rt.Client.GetTransaction(txid)
|
got, err := rt.Client.GetTransaction(txid)
|
||||||
@ -110,7 +113,6 @@ func (rt *Test) TestGetTransaction(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirmations is variable field, we just check if is set and reset it
|
// Confirmations is variable field, we just check if is set and reset it
|
||||||
if got.Confirmations > 0 {
|
if got.Confirmations > 0 {
|
||||||
got.Confirmations = 0
|
got.Confirmations = 0
|
||||||
@ -124,3 +126,161 @@ func (rt *Test) TestGetTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rt *Test) getMempool(t *testing.T) []string {
|
||||||
|
var (
|
||||||
|
txs []string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
// attempts to get transactions for 2 min
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
txs, err = rt.Client.GetMempool()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(txs) == 0 {
|
||||||
|
time.Sleep(15 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(txs) == 0 {
|
||||||
|
t.Skipf("Skipping test, all attempts to get mempool failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return txs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *Test) getMempoolTransaction(t *testing.T, txid string) *bchain.Tx {
|
||||||
|
tx, err := rt.Client.GetTransactionForMempool(txid)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if tx.Confirmations > 0 {
|
||||||
|
t.Skip("Skipping test, transaction moved away from mepool")
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *Test) TestGetTransactionForMempool(t *testing.T) {
|
||||||
|
txs := rt.getMempool(t)
|
||||||
|
txid := txs[rand.Intn(len(txs))]
|
||||||
|
got := rt.getMempoolTransaction(t, txid)
|
||||||
|
|
||||||
|
want, err := rt.Client.GetTransaction(txid)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetTransactionForMempool() got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *Test) getMempoolAddresses(t *testing.T, txs []string) map[string][]string {
|
||||||
|
txid2addrs := map[string][]string{}
|
||||||
|
for i := 0; i < len(txs); i++ {
|
||||||
|
tx := rt.getMempoolTransaction(t, txs[i])
|
||||||
|
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) {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
txs := rt.getMempool(t)
|
||||||
|
txid2addrs := rt.getMempoolAddresses(t, txs)
|
||||||
|
if len(txid2addrs) == 0 {
|
||||||
|
t.Fatal("No transaction in mempool has any address")
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := rt.Client.ResyncMempool(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tmp := rt.getMempool(t); len(txs) != len(tmp) {
|
||||||
|
// mempool reset
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(txs) != n {
|
||||||
|
t.Fatalf("ResyncMempool() returned different number of transactions than backend call")
|
||||||
|
}
|
||||||
|
|
||||||
|
for txid, addrs := range txid2addrs {
|
||||||
|
for _, a := range addrs {
|
||||||
|
txs, err := rt.Client.GetMempoolTransactions(a)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !containsString(txs, 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 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) {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
txs := rt.getMempool(t)
|
||||||
|
h, err := rt.Client.GetBestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx := rt.getMempoolTransaction(t, txs[rand.Intn(len(txs))])
|
||||||
|
e, err := rt.Client.GetMempoolEntry(tx.Txid)
|
||||||
|
if err != nil {
|
||||||
|
if err, ok := err.(*bchain.RPCError); ok && err.Code == -5 {
|
||||||
|
// mempool reset
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Height != h {
|
||||||
|
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.Fee <= 0 {
|
||||||
|
t.Errorf("GetMempoolEntry() got zero or negative fee %f", e.Fee)
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Skip("Skipping test, all attempts to get mempool entry failed due to network state changes")
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user