From 2e37cbb97473aaa1ff26ca64f84516917bee3362 Mon Sep 17 00:00:00 2001 From: Martin Boehm Date: Sun, 9 Feb 2020 11:46:13 +0100 Subject: [PATCH] Insert utxos in the right order in disconnect block --- db/rocksdb.go | 47 ++++++- db/rocksdb_test.go | 229 +++++++++++++++++++++++++++++++-- server/public_test.go | 16 +-- tests/dbtestdata/dbtestdata.go | 32 +++-- 4 files changed, 292 insertions(+), 32 deletions(-) diff --git a/db/rocksdb.go b/db/rocksdb.go index fc48e42e..6b38dd5e 100644 --- a/db/rocksdb.go +++ b/db/rocksdb.go @@ -564,6 +564,10 @@ func (ab *AddrBalance) ReceivedSat() *big.Int { // addUtxo func (ab *AddrBalance) addUtxo(u *Utxo) { ab.Utxos = append(ab.Utxos, *u) + ab.manageUtxoMap(u) +} + +func (ab *AddrBalance) manageUtxoMap(u *Utxo) { l := len(ab.Utxos) if l >= 16 { if len(ab.utxosMap) == 0 { @@ -583,9 +587,45 @@ func (ab *AddrBalance) addUtxo(u *Utxo) { } } +// on disconnect, the added utxos must be inserted in the right position so that utxosMap index works +func (ab *AddrBalance) addUtxoInDisconnect(u *Utxo) { + insert := -1 + if len(ab.utxosMap) > 0 { + if i, e := ab.utxosMap[string(u.BtxID)]; e { + insert = i + } + } else { + for i := range ab.Utxos { + utxo := &ab.Utxos[i] + if *(*int)(unsafe.Pointer(&utxo.BtxID[0])) == *(*int)(unsafe.Pointer(&u.BtxID[0])) && bytes.Equal(utxo.BtxID, u.BtxID) { + insert = i + break + } + } + } + if insert > -1 { + // check if it is necessary to insert the utxo into the array + for i := insert; i < len(ab.Utxos); i++ { + utxo := &ab.Utxos[i] + // either the vout is greater than the inserted vout or it is a different tx + if utxo.Vout > u.Vout || *(*int)(unsafe.Pointer(&utxo.BtxID[0])) != *(*int)(unsafe.Pointer(&u.BtxID[0])) || !bytes.Equal(utxo.BtxID, u.BtxID) { + // found the right place, insert the utxo + ab.Utxos = append(ab.Utxos, *u) + copy(ab.Utxos[i+1:], ab.Utxos[i:]) + ab.Utxos[i] = *u + // reset utxosMap after insert, the index will have to be rebuilt if needed + ab.utxosMap = nil + return + } + } + } + ab.Utxos = append(ab.Utxos, *u) + ab.manageUtxoMap(u) +} + // markUtxoAsSpent finds outpoint btxID:vout in utxos and marks it as spent // for small number of utxos the linear search is done, for larger number there is a hashmap index -// it is much faster than removing the utxo from the slice as it would cause in memory copy operations +// it is much faster than removing the utxo from the slice as it would cause in memory reallocations func (ab *AddrBalance) markUtxoAsSpent(btxID []byte, vout int32) { if len(ab.utxosMap) == 0 { for i := range ab.Utxos { @@ -1360,7 +1400,7 @@ func (d *RocksDB) disconnectTxAddressesInputs(wb *gorocksdb.WriteBatch, btxID [] d.resetValueSatToZero(&balance.SentSat, t.AddrDesc, "sent amount") } balance.BalanceSat.Add(&balance.BalanceSat, &t.ValueSat) - balance.Utxos = append(balance.Utxos, Utxo{ + balance.addUtxoInDisconnect(&Utxo{ BtxID: input.btxID, Vout: input.index, Height: inputHeight, @@ -1420,8 +1460,7 @@ func (d *RocksDB) disconnectBlock(height uint32, blockTxs []blockTxs) error { s := string(addrDesc) b, fb := balances[s] if !fb { - // do not use addressBalanceDetailUTXOIndexed as the utxo may be in wrong order for the helper map - b, err = d.GetAddrDescBalance(addrDesc, AddressBalanceDetailUTXO) + b, err = d.GetAddrDescBalance(addrDesc, addressBalanceDetailUTXOIndexed) if err != nil { return nil, err } diff --git a/db/rocksdb_test.go b/db/rocksdb_test.go index 7326ea80..2f932120 100644 --- a/db/rocksdb_test.go +++ b/db/rocksdb_test.go @@ -192,7 +192,7 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool // the vout is encoded as signed varint, i.e. value * 2 for non negative values if err := checkColumn(d, cfAddresses, []keyPair{ {addressKeyHex(dbtestdata.Addr1, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{0}), nil}, - {addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1, 2}), nil}, {addressKeyHex(dbtestdata.Addr3, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{0}), nil}, {addressKeyHex(dbtestdata.Addr4, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{1}), nil}, {addressKeyHex(dbtestdata.Addr5, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{2}), nil}, @@ -206,8 +206,9 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool dbtestdata.TxidB1T1, varuintToHex(225493) + "00" + - "02" + + "03" + addressToPubKeyHexWithLength(dbtestdata.Addr1, t, d) + bigintToHex(dbtestdata.SatB1T1A1) + + addressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2) + addressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2), nil, }, @@ -235,8 +236,9 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool }, { dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), - "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A2) + - dbtestdata.TxidB1T1 + varuintToHex(1) + varuintToHex(225493) + bigintToHex(dbtestdata.SatB1T1A2), + "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A2Double) + + dbtestdata.TxidB1T1 + varuintToHex(1) + varuintToHex(225493) + bigintToHex(dbtestdata.SatB1T1A2) + + dbtestdata.TxidB1T1 + varuintToHex(2) + varuintToHex(225493) + bigintToHex(dbtestdata.SatB1T1A2), nil, }, { @@ -302,7 +304,7 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { } if err := checkColumn(d, cfAddresses, []keyPair{ {addressKeyHex(dbtestdata.Addr1, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{0}), nil}, - {addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1, 2}), nil}, {addressKeyHex(dbtestdata.Addr3, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{0}), nil}, {addressKeyHex(dbtestdata.Addr4, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{1}), nil}, {addressKeyHex(dbtestdata.Addr5, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{2}), nil}, @@ -325,9 +327,10 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { dbtestdata.TxidB1T1, varuintToHex(225493) + "00" + - "02" + + "03" + addressToPubKeyHexWithLength(dbtestdata.Addr1, t, d) + bigintToHex(dbtestdata.SatB1T1A1) + - spentAddressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2), + spentAddressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2) + + addressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2), nil, }, { @@ -395,7 +398,8 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { }, { dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), - "02" + bigintToHex(dbtestdata.SatB1T1A2) + bigintToHex(dbtestdata.SatZero), + "02" + bigintToHex(dbtestdata.SatB1T1A2) + bigintToHex(dbtestdata.SatB1T1A2) + + dbtestdata.TxidB1T1 + varuintToHex(2) + varuintToHex(225493) + bigintToHex(dbtestdata.SatB1T1A2), nil, }, { @@ -563,9 +567,11 @@ func TestRocksDB_Index_BitcoinType(t *testing.T) { verifyGetTransactions(t, d, dbtestdata.Addr2, 0, 1000000, []txidIndex{ {dbtestdata.TxidB2T1, ^1}, {dbtestdata.TxidB1T1, 1}, + {dbtestdata.TxidB1T1, 2}, }, nil) verifyGetTransactions(t, d, dbtestdata.Addr2, 225493, 225493, []txidIndex{ {dbtestdata.TxidB1T1, 1}, + {dbtestdata.TxidB1T1, 2}, }, nil) verifyGetTransactions(t, d, dbtestdata.Addr2, 225494, 1000000, []txidIndex{ {dbtestdata.TxidB2T1, ^1}, @@ -1101,6 +1107,213 @@ func Test_packAddrBalance_unpackAddrBalance(t *testing.T) { } } +func createUtxoMap(ab *AddrBalance) { + l := len(ab.Utxos) + ab.utxosMap = make(map[string]int, 32) + for i := 0; i < l; i++ { + s := string(ab.Utxos[i].BtxID) + if _, e := ab.utxosMap[s]; !e { + ab.utxosMap[s] = i + } + } +} +func TestAddrBalance_utxo_methods(t *testing.T) { + ab := &AddrBalance{ + Txs: 10, + SentSat: *big.NewInt(10000), + BalanceSat: *big.NewInt(1000), + } + + // addUtxo + ab.addUtxo(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 1, + Height: 5000, + ValueSat: *big.NewInt(100), + }) + ab.addUtxo(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 4, + Height: 5000, + ValueSat: *big.NewInt(100), + }) + ab.addUtxo(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T2), + Vout: 0, + Height: 5001, + ValueSat: *big.NewInt(800), + }) + want := &AddrBalance{ + Txs: 10, + SentSat: *big.NewInt(10000), + BalanceSat: *big.NewInt(1000), + Utxos: []Utxo{ + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 1, + Height: 5000, + ValueSat: *big.NewInt(100), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 4, + Height: 5000, + ValueSat: *big.NewInt(100), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T2), + Vout: 0, + Height: 5001, + ValueSat: *big.NewInt(800), + }, + }, + } + if !reflect.DeepEqual(ab, want) { + t.Errorf("addUtxo, got %+v, want %+v", ab, want) + } + + // addUtxoInDisconnect + ab.addUtxoInDisconnect(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB2T1), + Vout: 0, + Height: 5003, + ValueSat: *big.NewInt(800), + }) + ab.addUtxoInDisconnect(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB2T1), + Vout: 1, + Height: 5003, + ValueSat: *big.NewInt(800), + }) + ab.addUtxoInDisconnect(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 10, + Height: 5000, + ValueSat: *big.NewInt(100), + }) + ab.addUtxoInDisconnect(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 2, + Height: 5000, + ValueSat: *big.NewInt(100), + }) + ab.addUtxoInDisconnect(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 0, + Height: 5000, + ValueSat: *big.NewInt(100), + }) + want = &AddrBalance{ + Txs: 10, + SentSat: *big.NewInt(10000), + BalanceSat: *big.NewInt(1000), + Utxos: []Utxo{ + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 0, + Height: 5000, + ValueSat: *big.NewInt(100), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 1, + Height: 5000, + ValueSat: *big.NewInt(100), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 2, + Height: 5000, + ValueSat: *big.NewInt(100), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 4, + Height: 5000, + ValueSat: *big.NewInt(100), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 10, + Height: 5000, + ValueSat: *big.NewInt(100), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T2), + Vout: 0, + Height: 5001, + ValueSat: *big.NewInt(800), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB2T1), + Vout: 0, + Height: 5003, + ValueSat: *big.NewInt(800), + }, + Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB2T1), + Vout: 1, + Height: 5003, + ValueSat: *big.NewInt(800), + }, + }, + } + if !reflect.DeepEqual(ab, want) { + t.Errorf("addUtxoInDisconnect, got %+v, want %+v", ab, want) + } + + // markUtxoAsSpent + ab.markUtxoAsSpent(hexToBytes(dbtestdata.TxidB2T1), 0) + want.Utxos[6].Vout = -1 + if !reflect.DeepEqual(ab, want) { + t.Errorf("markUtxoAsSpent, got %+v, want %+v", ab, want) + } + + // addUtxo with utxosMap + for i := 0; i < 20; i += 2 { + utxo := Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB2T2), + Vout: int32(i), + Height: 5009, + ValueSat: *big.NewInt(800), + } + ab.addUtxo(&utxo) + want.Utxos = append(want.Utxos, utxo) + } + createUtxoMap(want) + if !reflect.DeepEqual(ab, want) { + t.Errorf("addUtxo with utxosMap, got %+v, want %+v", ab, want) + } + + // markUtxoAsSpent with utxosMap + ab.markUtxoAsSpent(hexToBytes(dbtestdata.TxidB2T1), 1) + want.Utxos[7].Vout = -1 + if !reflect.DeepEqual(ab, want) { + t.Errorf("markUtxoAsSpent with utxosMap, got %+v, want %+v", ab, want) + } + + // addUtxoInDisconnect with utxosMap + ab.addUtxoInDisconnect(&Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 3, + Height: 5000, + ValueSat: *big.NewInt(100), + }) + want.Utxos = append(want.Utxos, Utxo{}) + copy(want.Utxos[3+1:], want.Utxos[3:]) + want.Utxos[3] = Utxo{ + BtxID: hexToBytes(dbtestdata.TxidB1T1), + Vout: 3, + Height: 5000, + ValueSat: *big.NewInt(100), + } + want.utxosMap = nil + if !reflect.DeepEqual(ab, want) { + t.Errorf("addUtxoInDisconnect with utxosMap, got %+v, want %+v", ab, want) + } + +} + func TestRocksTickers(t *testing.T) { d := setupRocksDB(t, &testBitcoinParser{ BitcoinParser: bitcoinTestnetParser(), diff --git a/server/public_test.go b/server/public_test.go index 0730d08f..6a58947d 100644 --- a/server/public_test.go +++ b/server/public_test.go @@ -236,7 +236,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) { body: []string{ `Fake Coin Explorer`, `

Address`, - `0 FAKE`, + `0.00012345 FAKE`, `mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz`, `0.00012345 FAKE`, `7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25`, @@ -375,7 +375,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) { body: []string{ `Fake Coin Explorer`, `

Address`, - `0 FAKE`, + `0.00012345 FAKE`, `mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz`, `0.00012345 FAKE`, `7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25`, @@ -506,7 +506,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) { status: http.StatusOK, contentType: "application/json; charset=utf-8", body: []string{ - `{"hex":"","txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","version":0,"locktime":0,"vin":[],"vout":[{"ValueSat":100000000,"value":0,"n":0,"scriptPubKey":{"hex":"76a914010d39800f86122416e28f485029acf77507169288ac","addresses":null}},{"ValueSat":12345,"value":0,"n":1,"scriptPubKey":{"hex":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","addresses":null}}],"confirmations":2,"time":1521515026,"blocktime":1521515026}`, + `{"hex":"","txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","version":0,"locktime":0,"vin":[],"vout":[{"ValueSat":100000000,"value":0,"n":0,"scriptPubKey":{"hex":"76a914010d39800f86122416e28f485029acf77507169288ac","addresses":null}},{"ValueSat":12345,"value":0,"n":1,"scriptPubKey":{"hex":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","addresses":null}},{"ValueSat":12345,"value":0,"n":2,"scriptPubKey":{"hex":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","addresses":null}}],"confirmations":2,"time":1521515026,"blocktime":1521515026}`, }, }, { @@ -776,7 +776,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) { status: http.StatusOK, contentType: "application/json; charset=utf-8", body: []string{ - `[{"time":1521514800,"txs":1,"received":"12345","sent":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","rates":{"eur":1303,"usd":2003}}]`, + `[{"time":1521514800,"txs":1,"received":"24690","sent":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","rates":{"eur":1303,"usd":2003}}]`, }, }, { @@ -803,7 +803,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) { status: http.StatusOK, contentType: "application/json; charset=utf-8", body: []string{ - `[{"time":1521514800,"txs":1,"received":"12345","sent":"0","rates":{"eur":1301,"usd":2001}}]`, + `[{"time":1521514800,"txs":1,"received":"24690","sent":"0","rates":{"eur":1301,"usd":2001}}]`, }, }, { @@ -884,7 +884,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) { status: http.StatusOK, contentType: "application/json; charset=utf-8", body: []string{ - `{"page":1,"totalPages":1,"itemsOnPage":1000,"hash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","nextBlockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","height":225493,"confirmations":2,"size":1234567,"time":1521515026,"version":0,"merkleRoot":"","nonce":"","bits":"","difficulty":"","txCount":2,"txs":[{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vin":[],"vout":[{"value":"100000000","n":0,"addresses":["mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"],"isAddress":true},{"value":"12345","n":1,"spent":true,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"100012345","valueIn":"0","fees":"0"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true},{"value":"1","n":1,"spent":true,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true},{"value":"9876","n":2,"spent":true,"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}]}`, + `{"page":1,"totalPages":1,"itemsOnPage":1000,"hash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","nextBlockHash":"00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6","height":225493,"confirmations":2,"size":1234567,"time":1521515026,"version":0,"merkleRoot":"","nonce":"","bits":"","difficulty":"","txCount":2,"txs":[{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","vin":[],"vout":[{"value":"100000000","n":0,"addresses":["mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"],"isAddress":true},{"value":"12345","n":1,"spent":true,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true},{"value":"12345","n":2,"addresses":["mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"100024690","valueIn":"0","fees":"0"},{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","vin":[],"vout":[{"value":"1234567890123","n":0,"spent":true,"addresses":["mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw"],"isAddress":true},{"value":"1","n":1,"spent":true,"addresses":["2MzmAKayJmja784jyHvRUW1bXPget1csRRG"],"isAddress":true},{"value":"9876","n":2,"spent":true,"addresses":["2NEVv9LJmAnY99W1pFoc5UJjVdypBqdnvu1"],"isAddress":true}],"blockHash":"0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997","blockHeight":225493,"confirmations":2,"blockTime":1521515026,"value":"1234567900000","valueIn":"0","fees":"0"}]}`, }, }, } @@ -986,7 +986,7 @@ func socketioTestsBitcoinType(t *testing.T, ts *httptest.Server) { "to": 5, }, }}, - want: `{"result":{"totalCount":2,"items":[{"addresses":{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz":{"inputIndexes":[1],"outputIndexes":[]}},"satoshis":-12345,"confirmations":1,"tx":{"hex":"","height":225494,"blockTimestamp":1521595678,"version":0,"hash":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","inputs":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","outputIndex":0,"script":"","sequence":0,"address":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","satoshis":1234567890123},{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","outputIndex":1,"script":"","sequence":0,"address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz","satoshis":12345}],"inputSatoshis":1234567902468,"outputs":[{"satoshis":317283951061,"script":"76a914ccaaaf374e1b06cb83118453d102587b4273d09588ac","address":"mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"},{"satoshis":917283951061,"script":"76a9148d802c045445df49613f6a70ddd2e48526f3701f88ac","address":"mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"},{"satoshis":0,"script":"6a072020f1686f6a20","address":"OP_RETURN 2020f1686f6a20"}],"outputSatoshis":1234567902122,"feeSatoshis":346}},{"addresses":{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz":{"inputIndexes":[],"outputIndexes":[1]}},"satoshis":12345,"confirmations":2,"tx":{"hex":"","height":225493,"blockTimestamp":1521515026,"version":0,"hash":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","inputs":[],"outputs":[{"satoshis":100000000,"script":"76a914010d39800f86122416e28f485029acf77507169288ac","address":"mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"},{"satoshis":12345,"script":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"}],"outputSatoshis":100012345}}]}}`, + want: `{"result":{"totalCount":2,"items":[{"addresses":{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz":{"inputIndexes":[1],"outputIndexes":[]}},"satoshis":-12345,"confirmations":1,"tx":{"hex":"","height":225494,"blockTimestamp":1521595678,"version":0,"hash":"7c3be24063f268aaa1ed81b64776798f56088757641a34fb156c4f51ed2e9d25","inputs":[{"txid":"effd9ef509383d536b1c8af5bf434c8efbf521a4f2befd4022bbd68694b4ac75","outputIndex":0,"script":"","sequence":0,"address":"mv9uLThosiEnGRbVPS7Vhyw6VssbVRsiAw","satoshis":1234567890123},{"txid":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","outputIndex":1,"script":"","sequence":0,"address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz","satoshis":12345}],"inputSatoshis":1234567902468,"outputs":[{"satoshis":317283951061,"script":"76a914ccaaaf374e1b06cb83118453d102587b4273d09588ac","address":"mzB8cYrfRwFRFAGTDzV8LkUQy5BQicxGhX"},{"satoshis":917283951061,"script":"76a9148d802c045445df49613f6a70ddd2e48526f3701f88ac","address":"mtR97eM2HPWVM6c8FGLGcukgaHHQv7THoL"},{"satoshis":0,"script":"6a072020f1686f6a20","address":"OP_RETURN 2020f1686f6a20"}],"outputSatoshis":1234567902122,"feeSatoshis":346}},{"addresses":{"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz":{"inputIndexes":[],"outputIndexes":[1,2]}},"satoshis":24690,"confirmations":2,"tx":{"hex":"","height":225493,"blockTimestamp":1521515026,"version":0,"hash":"00b2c06055e5e90e9c82bd4181fde310104391a7fa4f289b1704e5d90caa3840","inputs":[],"outputs":[{"satoshis":100000000,"script":"76a914010d39800f86122416e28f485029acf77507169288ac","address":"mfcWp7DB6NuaZsExybTTXpVgWz559Np4Ti"},{"satoshis":12345,"script":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"},{"satoshis":12345,"script":"76a9148bdf0aa3c567aa5975c2e61321b8bebbe7293df688ac","address":"mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz"}],"outputSatoshis":100024690}}]}}`, }, { name: "socketio getBlockHeader", @@ -1370,7 +1370,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) { "descriptor": "mtGXQvBowMkBpnhLckhxhbwYK44Gs9eEtz", }, }, - want: `{"id":"32","data":[{"time":1521514800,"txs":1,"received":"12345","sent":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","rates":{"eur":1303,"usd":2003}}]}`, + want: `{"id":"32","data":[{"time":1521514800,"txs":1,"received":"24690","sent":"0","rates":{"eur":1301,"usd":2001}},{"time":1521594000,"txs":1,"received":"0","sent":"12345","rates":{"eur":1303,"usd":2003}}]}`, }, { name: "websocket getBalanceHistory xpub", diff --git a/tests/dbtestdata/dbtestdata.go b/tests/dbtestdata/dbtestdata.go index 8f853df0..c3d764a7 100644 --- a/tests/dbtestdata/dbtestdata.go +++ b/tests/dbtestdata/dbtestdata.go @@ -35,18 +35,19 @@ const ( // Amounts in satoshis var ( - SatZero = big.NewInt(0) - SatB1T1A1 = big.NewInt(100000000) - SatB1T1A2 = big.NewInt(12345) - SatB1T2A3 = big.NewInt(1234567890123) - SatB1T2A4 = big.NewInt(1) - SatB1T2A5 = big.NewInt(9876) - SatB2T1A6 = big.NewInt(317283951061) - SatB2T1A7 = big.NewInt(917283951061) - SatB2T2A8 = big.NewInt(118641975500) - SatB2T2A9 = big.NewInt(198641975500) - SatB2T3A5 = big.NewInt(9000) - SatB2T4AA = big.NewInt(1360030331) + SatZero = big.NewInt(0) + SatB1T1A1 = big.NewInt(100000000) + SatB1T1A2 = big.NewInt(12345) + SatB1T1A2Double = big.NewInt(12345 * 2) + SatB1T2A3 = big.NewInt(1234567890123) + SatB1T2A4 = big.NewInt(1) + SatB1T2A5 = big.NewInt(9876) + SatB2T1A6 = big.NewInt(317283951061) + SatB2T1A7 = big.NewInt(917283951061) + SatB2T2A8 = big.NewInt(118641975500) + SatB2T2A9 = big.NewInt(198641975500) + SatB2T3A5 = big.NewInt(9000) + SatB2T4AA = big.NewInt(1360030331) ) // AddressToPubKeyHex is a utility conversion function @@ -90,6 +91,13 @@ func GetTestBitcoinTypeBlock1(parser bchain.BlockChainParser) *bchain.Block { }, ValueSat: *SatB1T1A2, }, + { + N: 2, + ScriptPubKey: bchain.ScriptPubKey{ + Hex: AddressToPubKeyHex(Addr2, parser), + }, + ValueSat: *SatB1T1A2, + }, }, Blocktime: 1521515026, Time: 1521515026,