mirror of
https://github.com/trezor/blockbook.git
synced 2026-02-20 00:51:39 +01:00
209 lines
5.6 KiB
Go
209 lines
5.6 KiB
Go
//go:build unittest
|
|
|
|
package server
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/trezor/blockbook/api"
|
|
"github.com/trezor/blockbook/bchain"
|
|
"github.com/trezor/blockbook/tests/dbtestdata"
|
|
)
|
|
|
|
func TestSetConfirmedBlockTxMetadataSetsConfirmedFields(t *testing.T) {
|
|
tx := bchain.Tx{
|
|
Confirmations: 0,
|
|
Blocktime: 0,
|
|
Time: 0,
|
|
}
|
|
|
|
setConfirmedBlockTxMetadata(&tx, 123456)
|
|
|
|
if tx.Confirmations != 1 {
|
|
t.Fatalf("Confirmations = %d, want 1", tx.Confirmations)
|
|
}
|
|
if tx.Blocktime != 123456 {
|
|
t.Fatalf("Blocktime = %d, want 123456", tx.Blocktime)
|
|
}
|
|
if tx.Time != 123456 {
|
|
t.Fatalf("Time = %d, want 123456", tx.Time)
|
|
}
|
|
}
|
|
|
|
func TestSetConfirmedBlockTxMetadataLeavesConfirmedTxUnchanged(t *testing.T) {
|
|
tx := bchain.Tx{
|
|
Confirmations: 3,
|
|
Blocktime: 100,
|
|
Time: 200,
|
|
}
|
|
|
|
setConfirmedBlockTxMetadata(&tx, 123456)
|
|
|
|
if tx.Confirmations != 3 {
|
|
t.Fatalf("Confirmations = %d, want 3", tx.Confirmations)
|
|
}
|
|
if tx.Blocktime != 100 {
|
|
t.Fatalf("Blocktime = %d, want 100", tx.Blocktime)
|
|
}
|
|
if tx.Time != 200 {
|
|
t.Fatalf("Time = %d, want 200", tx.Time)
|
|
}
|
|
}
|
|
|
|
func TestGetEthereumInternalTransfersMissingData(t *testing.T) {
|
|
tx := bchain.Tx{}
|
|
|
|
transfers := getEthereumInternalTransfers(&tx)
|
|
|
|
if len(transfers) != 0 {
|
|
t.Fatalf("len(transfers) = %d, want 0", len(transfers))
|
|
}
|
|
}
|
|
|
|
func TestGetEthereumInternalTransfersReturnsTransfers(t *testing.T) {
|
|
expected := []bchain.EthereumInternalTransfer{
|
|
{From: "0x111", To: "0x222"},
|
|
}
|
|
tx := bchain.Tx{
|
|
CoinSpecificData: bchain.EthereumSpecificData{
|
|
InternalData: &bchain.EthereumInternalData{
|
|
Transfers: expected,
|
|
},
|
|
},
|
|
}
|
|
|
|
transfers := getEthereumInternalTransfers(&tx)
|
|
|
|
if len(transfers) != len(expected) {
|
|
t.Fatalf("len(transfers) = %d, want %d", len(transfers), len(expected))
|
|
}
|
|
if transfers[0].From != expected[0].From || transfers[0].To != expected[0].To {
|
|
t.Fatalf("transfers[0] = %+v, want %+v", transfers[0], expected[0])
|
|
}
|
|
}
|
|
|
|
func TestSetEthereumReceiptIfAvailableKeepsTxWhenReceiptFails(t *testing.T) {
|
|
tx := bchain.Tx{
|
|
Txid: "0xabc",
|
|
CoinSpecificData: bchain.EthereumSpecificData{
|
|
Tx: &bchain.RpcTransaction{Hash: "0xabc"},
|
|
},
|
|
}
|
|
|
|
setEthereumReceiptIfAvailable(&tx, func(string) (*bchain.RpcReceipt, error) {
|
|
return nil, errors.New("rpc failure")
|
|
})
|
|
|
|
csd, ok := tx.CoinSpecificData.(bchain.EthereumSpecificData)
|
|
if !ok {
|
|
t.Fatal("CoinSpecificData has unexpected type")
|
|
}
|
|
if csd.Receipt != nil {
|
|
t.Fatalf("Receipt = %+v, want nil", csd.Receipt)
|
|
}
|
|
}
|
|
|
|
func TestSetEthereumReceiptIfAvailableSetsReceipt(t *testing.T) {
|
|
tx := bchain.Tx{
|
|
Txid: "0xdef",
|
|
CoinSpecificData: bchain.EthereumSpecificData{
|
|
Tx: &bchain.RpcTransaction{Hash: "0xdef"},
|
|
},
|
|
}
|
|
wantReceipt := &bchain.RpcReceipt{GasUsed: "0x5208"}
|
|
|
|
setEthereumReceiptIfAvailable(&tx, func(string) (*bchain.RpcReceipt, error) {
|
|
return wantReceipt, nil
|
|
})
|
|
|
|
csd, ok := tx.CoinSpecificData.(bchain.EthereumSpecificData)
|
|
if !ok {
|
|
t.Fatal("CoinSpecificData has unexpected type")
|
|
}
|
|
if csd.Receipt != wantReceipt {
|
|
t.Fatalf("Receipt = %+v, want %+v", csd.Receipt, wantReceipt)
|
|
}
|
|
}
|
|
|
|
func TestSendOnNewTxAddrFiltersNewBlockTxSubscriptions(t *testing.T) {
|
|
parser, _ := setupChain(t)
|
|
s := &WebsocketServer{
|
|
chainParser: parser,
|
|
addressSubscriptions: make(map[string]map[*websocketChannel]*addressDetails),
|
|
}
|
|
addrDesc, err := parser.GetAddrDescFromAddress(dbtestdata.Addr1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
stringAddrDesc := string(addrDesc)
|
|
onlyMempool := &websocketChannel{out: make(chan *WsRes, 1), alive: true}
|
|
withNewBlockTxs := &websocketChannel{out: make(chan *WsRes, 1), alive: true}
|
|
s.addressSubscriptions[stringAddrDesc] = map[*websocketChannel]*addressDetails{
|
|
onlyMempool: {
|
|
requestID: "mempool-only",
|
|
publishNewBlockTxs: false,
|
|
},
|
|
withNewBlockTxs: {
|
|
requestID: "with-new-block-txs",
|
|
publishNewBlockTxs: true,
|
|
},
|
|
}
|
|
|
|
s.sendOnNewTxAddr(stringAddrDesc, &api.Tx{Txid: "new-block-tx"}, true)
|
|
|
|
if len(onlyMempool.out) != 0 {
|
|
t.Fatalf("mempool-only subscriber received %d messages, want 0", len(onlyMempool.out))
|
|
}
|
|
if len(withNewBlockTxs.out) != 1 {
|
|
t.Fatalf("newBlockTxs subscriber received %d messages, want 1", len(withNewBlockTxs.out))
|
|
}
|
|
}
|
|
|
|
func TestPopulateBitcoinVinAddrDescsEnablesSenderOnlyMatching(t *testing.T) {
|
|
parser, _ := setupChain(t)
|
|
block := dbtestdata.GetTestBitcoinTypeBlock2(parser)
|
|
tx := block.Txs[0] // spends Addr3/Addr2 and pays Addr6/Addr7
|
|
|
|
vins := make([]bchain.MempoolVin, len(tx.Vin))
|
|
for i := range tx.Vin {
|
|
vins[i] = bchain.MempoolVin{Vin: tx.Vin[i]}
|
|
}
|
|
addr3Desc, err := parser.GetAddrDescFromAddress(dbtestdata.Addr3)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
addr2Desc, err := parser.GetAddrDescFromAddress(dbtestdata.Addr2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dummy := &websocketChannel{}
|
|
s := &WebsocketServer{
|
|
chainParser: parser,
|
|
addressSubscriptions: map[string]map[*websocketChannel]*addressDetails{
|
|
string(addr3Desc): {dummy: {requestID: "sender", publishNewBlockTxs: true}},
|
|
},
|
|
}
|
|
|
|
withoutResolvedVins := s.getNewTxSubscriptions(vins, tx.Vout, nil, nil)
|
|
if _, ok := withoutResolvedVins[string(addr3Desc)]; ok {
|
|
t.Fatal("sender subscription unexpectedly matched before vin descriptor resolution")
|
|
}
|
|
|
|
populateBitcoinVinAddrDescs(vins, func(txid string, vout uint32) (bchain.AddressDescriptor, error) {
|
|
switch {
|
|
case txid == dbtestdata.TxidB1T2 && vout == 0:
|
|
return addr3Desc, nil
|
|
case txid == dbtestdata.TxidB1T1 && vout == 1:
|
|
return addr2Desc, nil
|
|
default:
|
|
return nil, errors.New("not found")
|
|
}
|
|
})
|
|
|
|
withResolvedVins := s.getNewTxSubscriptions(vins, tx.Vout, nil, nil)
|
|
if _, ok := withResolvedVins[string(addr3Desc)]; !ok {
|
|
t.Fatal("sender subscription did not match after vin descriptor resolution")
|
|
}
|
|
}
|