github.com/dawnbass68/maddcash@v0.0.0-20201001105353-c91c12cb36e5/tests/sync/handlefork.go (about)

     1  // +build integration
     2  
     3  package sync
     4  
     5  import (
     6  	"blockbook/bchain"
     7  	"blockbook/db"
     8  	"fmt"
     9  	"math/big"
    10  	"os"
    11  	"reflect"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  func testHandleFork(t *testing.T, h *TestHandler) {
    17  	for _, rng := range h.TestData.HandleFork.SyncRanges {
    18  		withRocksDBAndSyncWorker(t, h, rng.Lower, func(d *db.RocksDB, sw *db.SyncWorker, ch chan os.Signal) {
    19  			fakeBlocks := getFakeBlocks(h, rng)
    20  			chain, err := makeFakeChain(h.Chain, fakeBlocks, rng.Upper)
    21  			if err != nil {
    22  				t.Fatal(err)
    23  			}
    24  
    25  			db.SetBlockChain(sw, chain)
    26  
    27  			sw.ConnectBlocksParallel(rng.Lower, rng.Upper)
    28  
    29  			height, _, err := d.GetBestBlock()
    30  			if err != nil {
    31  				t.Fatal(err)
    32  			}
    33  			if height != rng.Upper {
    34  				t.Fatalf("Upper block height mismatch: %d != %d", height, rng.Upper)
    35  			}
    36  
    37  			fakeTxs, err := getTxs(h, d, rng, fakeBlocks)
    38  			if err != nil {
    39  				t.Fatal(err)
    40  			}
    41  			fakeAddr2txs := getAddr2TxsMap(fakeTxs)
    42  
    43  			verifyTransactions2(t, d, rng, fakeAddr2txs, true)
    44  			verifyAddresses2(t, d, h.Chain, fakeBlocks)
    45  
    46  			chain.returnFakes = false
    47  
    48  			upperHash := fakeBlocks[len(fakeBlocks)-1].Hash
    49  			db.HandleFork(sw, rng.Upper, upperHash, func(hash string, height uint32) {
    50  				if hash == upperHash {
    51  					close(ch)
    52  				}
    53  			}, true)
    54  
    55  			realBlocks := getRealBlocks(h, rng)
    56  			realTxs, err := getTxs(h, d, rng, realBlocks)
    57  			if err != nil {
    58  				t.Fatal(err)
    59  			}
    60  			realAddr2txs := getAddr2TxsMap(realTxs)
    61  
    62  			verifyTransactions2(t, d, rng, fakeAddr2txs, false)
    63  			verifyTransactions2(t, d, rng, realAddr2txs, true)
    64  			verifyAddresses2(t, d, h.Chain, realBlocks)
    65  		})
    66  	}
    67  }
    68  
    69  func verifyAddresses2(t *testing.T, d *db.RocksDB, chain bchain.BlockChain, blks []BlockID) {
    70  	parser := chain.GetChainParser()
    71  
    72  	for _, b := range blks {
    73  		txs, err := getBlockTxs(chain, b.Hash)
    74  		if err != nil {
    75  			t.Fatal(err)
    76  		}
    77  
    78  		for _, tx := range txs {
    79  			ta, err := d.GetTxAddresses(tx.Txid)
    80  			if err != nil {
    81  				t.Fatal(err)
    82  			}
    83  			if ta == nil {
    84  				t.Errorf("Tx %s: not found in TxAddresses", tx.Txid)
    85  				continue
    86  			}
    87  
    88  			txInfo := getTxInfo(&tx)
    89  			taInfo, err := getTaInfo(parser, ta)
    90  			if err != nil {
    91  				t.Fatal(err)
    92  			}
    93  
    94  			if ta.Height != b.Height {
    95  				t.Errorf("Tx %s: block height mismatch: %d != %d", tx.Txid, ta.Height, b.Height)
    96  				continue
    97  			}
    98  
    99  			if len(txInfo.inputs) > 0 && !reflect.DeepEqual(taInfo.inputs, txInfo.inputs) {
   100  				t.Errorf("Tx %s: inputs mismatch: got %q, want %q", tx.Txid, taInfo.inputs, txInfo.inputs)
   101  			}
   102  
   103  			if !reflect.DeepEqual(taInfo.outputs, txInfo.outputs) {
   104  				t.Errorf("Tx %s: outputs mismatch: got %q, want %q", tx.Txid, taInfo.outputs, txInfo.outputs)
   105  			}
   106  
   107  			if taInfo.valOutSat.Cmp(&txInfo.valOutSat) != 0 {
   108  				t.Errorf("Tx %s: total output amount mismatch: got %s, want %s",
   109  					tx.Txid, taInfo.valOutSat.String(), txInfo.valOutSat.String())
   110  			}
   111  
   112  			if len(txInfo.inputs) > 0 {
   113  				treshold := "0.0001"
   114  				fee := new(big.Int).Sub(&taInfo.valInSat, &taInfo.valOutSat)
   115  				if strings.Compare(parser.AmountToDecimalString(fee), treshold) > 0 {
   116  					t.Errorf("Tx %s: suspicious amounts: input ∑ [%s] - output ∑ [%s] > %s",
   117  						tx.Txid, taInfo.valInSat.String(), taInfo.valOutSat.String(), treshold)
   118  				}
   119  			}
   120  		}
   121  	}
   122  }
   123  
   124  func verifyTransactions2(t *testing.T, d *db.RocksDB, rng Range, addr2txs map[string][]string, exist bool) {
   125  	noErrs := 0
   126  	for addr, txs := range addr2txs {
   127  		checkMap := make(map[string]bool, len(txs))
   128  		for _, txid := range txs {
   129  			checkMap[txid] = false
   130  		}
   131  
   132  		err := d.GetTransactions(addr, rng.Lower, rng.Upper, func(txid string, height uint32, indexes []int32) error {
   133  			for _, index := range indexes {
   134  				if index >= 0 {
   135  					checkMap[txid] = true
   136  					break
   137  				}
   138  			}
   139  			return nil
   140  		})
   141  		if err != nil {
   142  			t.Fatal(err)
   143  		}
   144  
   145  		for _, txid := range txs {
   146  			if checkMap[txid] != exist {
   147  				auxverb := "wasn't"
   148  				if !exist {
   149  					auxverb = "was"
   150  				}
   151  				t.Errorf("%s: transaction %s %s found [expected = %t]", addr, txid, auxverb, exist)
   152  				noErrs++
   153  				if noErrs >= 10 {
   154  					t.Fatal("Too many errors")
   155  				}
   156  			}
   157  		}
   158  	}
   159  }
   160  
   161  func getFakeBlocks(h *TestHandler, rng Range) []BlockID {
   162  	blks := make([]BlockID, 0, rng.Upper-rng.Lower+1)
   163  	for i := rng.Lower; i <= rng.Upper; i++ {
   164  		if b, found := h.TestData.HandleFork.FakeBlocks[i]; found {
   165  			blks = append(blks, b)
   166  		}
   167  	}
   168  	return blks
   169  }
   170  
   171  func getRealBlocks(h *TestHandler, rng Range) []BlockID {
   172  	blks := make([]BlockID, 0, rng.Upper-rng.Lower+1)
   173  	for _, b := range h.TestData.HandleFork.RealBlocks {
   174  		if b.Height >= rng.Lower && b.Height <= rng.Upper {
   175  			blks = append(blks, b)
   176  		}
   177  	}
   178  	return blks
   179  }
   180  
   181  func makeFakeChain(chain bchain.BlockChain, blks []BlockID, upper uint32) (*fakeBlockChain, error) {
   182  	if blks[len(blks)-1].Height != upper {
   183  		return nil, fmt.Errorf("Range must end with fake block in order to emulate fork [%d != %d]", blks[len(blks)-1].Height, upper)
   184  	}
   185  	mBlks := make(map[uint32]BlockID, len(blks))
   186  	for i := range blks {
   187  		mBlks[blks[i].Height] = blks[i]
   188  	}
   189  	return &fakeBlockChain{
   190  		BlockChain:  chain,
   191  		returnFakes: true,
   192  		fakeBlocks:  mBlks,
   193  		bestHeight:  upper,
   194  	}, nil
   195  }
   196  
   197  func getTxs(h *TestHandler, d *db.RocksDB, rng Range, blks []BlockID) ([]bchain.Tx, error) {
   198  	res := make([]bchain.Tx, 0, (rng.Upper-rng.Lower+1)*2000)
   199  
   200  	for _, b := range blks {
   201  		bi, err := d.GetBlockInfo(b.Height)
   202  		if err != nil {
   203  			return nil, err
   204  		}
   205  		if bi.Hash != b.Hash {
   206  			return nil, fmt.Errorf("Block hash mismatch: %s != %s", bi.Hash, b.Hash)
   207  		}
   208  
   209  		txs, err := getBlockTxs(h.Chain, b.Hash)
   210  		if err != nil {
   211  			return nil, err
   212  		}
   213  		res = append(res, txs...)
   214  	}
   215  
   216  	return res, nil
   217  }
   218  
   219  func getBlockTxs(chain bchain.BlockChain, hash string) ([]bchain.Tx, error) {
   220  	b, err := chain.GetBlock(hash, 0)
   221  	if err != nil {
   222  		return nil, fmt.Errorf("GetBlock: %s", err)
   223  	}
   224  	parser := chain.GetChainParser()
   225  	for i := range b.Txs {
   226  		err := setTxAddresses(parser, &b.Txs[i])
   227  		if err != nil {
   228  			return nil, fmt.Errorf("setTxAddresses [%s]: %s", b.Txs[i].Txid, err)
   229  		}
   230  	}
   231  	return b.Txs, nil
   232  }
   233  
   234  func getAddr2TxsMap(txs []bchain.Tx) map[string][]string {
   235  	addr2txs := make(map[string][]string)
   236  	for i := range txs {
   237  		for j := range txs[i].Vout {
   238  			for k := range txs[i].Vout[j].ScriptPubKey.Addresses {
   239  				addr := txs[i].Vout[j].ScriptPubKey.Addresses[k]
   240  				txid := txs[i].Txid
   241  				addr2txs[addr] = append(addr2txs[addr], txid)
   242  			}
   243  		}
   244  	}
   245  	return addr2txs
   246  }