Introduce BitcoinType and EthereumType distinction of blockchains

This commit is contained in:
Martin Boehm 2018-11-06 18:41:13 +01:00
parent 28b3a4d1b4
commit 4448c57ba8
15 changed files with 112 additions and 99 deletions

View File

@ -125,9 +125,9 @@ func (p *BaseParser) UnpackBlockHash(buf []byte) (string, error) {
return hex.EncodeToString(buf), nil return hex.EncodeToString(buf), nil
} }
// IsUTXOChain returns true if the block chain is UTXO type, otherwise false // GetChainType is type of the blockchain, default is ChainBitcoinType
func (p *BaseParser) IsUTXOChain() bool { func (p *BaseParser) GetChainType() ChainType {
return true return ChainBitcoinType
} }
// PackTx packs transaction to byte array using protobuf // PackTx packs transaction to byte array using protobuf

View File

@ -27,7 +27,7 @@ type BitcoinRPC struct {
Parser bchain.BlockChainParser Parser bchain.BlockChainParser
Testnet bool Testnet bool
Network string Network string
Mempool *bchain.UTXOMempool Mempool *bchain.MempoolBitcoinType
ParseBlocks bool ParseBlocks bool
pushHandler func(bchain.NotificationType) pushHandler func(bchain.NotificationType)
mq *bchain.MQ mq *bchain.MQ
@ -115,7 +115,7 @@ func (b *BitcoinRPC) GetChainInfoAndInitializeMempool(bc bchain.BlockChain) (str
} }
b.mq = mq b.mq = mq
b.Mempool = bchain.NewUTXOMempool(bc, b.ChainConfig.MempoolWorkers, b.ChainConfig.MempoolSubWorkers) b.Mempool = bchain.NewMempoolBitcoinType(bc, b.ChainConfig.MempoolWorkers, b.ChainConfig.MempoolSubWorkers)
return chainName, nil return chainName, nil
} }

View File

@ -7,12 +7,10 @@ import (
"math/big" "math/big"
"strconv" "strconv"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/juju/errors" "github.com/juju/errors"
ethcommon "github.com/ethereum/go-ethereum/common"
) )
// EthereumParser handle // EthereumParser handle
@ -293,7 +291,7 @@ func (p *EthereumParser) UnpackBlockHash(buf []byte) (string, error) {
return hexutil.Encode(buf), nil return hexutil.Encode(buf), nil
} }
// IsUTXOChain returns true if the block chain is UTXO type, otherwise false // GetChainType returns TypeEthereum
func (p *EthereumParser) IsUTXOChain() bool { func (p *EthereumParser) GetChainType() bchain.ChainType {
return false return bchain.ChainEthereumType
} }

View File

@ -45,7 +45,7 @@ type EthereumRPC struct {
Parser *EthereumParser Parser *EthereumParser
Testnet bool Testnet bool
Network string Network string
Mempool *bchain.NonUTXOMempool Mempool *bchain.MempoolEthereumType
bestHeaderMu sync.Mutex bestHeaderMu sync.Mutex
bestHeader *ethtypes.Header bestHeader *ethtypes.Header
bestHeaderTime time.Time bestHeaderTime time.Time
@ -185,7 +185,7 @@ func (b *EthereumRPC) Initialize() error {
} }
// create mempool // create mempool
b.Mempool = bchain.NewNonUTXOMempool(b) b.Mempool = bchain.NewMempoolEthereumType(b)
return nil return nil
} }

View File

@ -23,8 +23,8 @@ type txidio struct {
io []addrIndex io []addrIndex
} }
// UTXOMempool is mempool handle. // MempoolBitcoinType is mempool handle.
type UTXOMempool struct { type MempoolBitcoinType struct {
chain BlockChain chain BlockChain
mux sync.Mutex mux sync.Mutex
txToInputOutput map[string][]addrIndex txToInputOutput map[string][]addrIndex
@ -34,10 +34,10 @@ type UTXOMempool struct {
onNewTxAddr OnNewTxAddrFunc onNewTxAddr OnNewTxAddrFunc
} }
// NewUTXOMempool creates new mempool handler. // NewMempoolBitcoinType creates new mempool handler.
// For now there is no cleanup of sync routines, the expectation is that the mempool is created only once per process // For now there is no cleanup of sync routines, the expectation is that the mempool is created only once per process
func NewUTXOMempool(chain BlockChain, workers int, subworkers int) *UTXOMempool { func NewMempoolBitcoinType(chain BlockChain, workers int, subworkers int) *MempoolBitcoinType {
m := &UTXOMempool{ m := &MempoolBitcoinType{
chain: chain, chain: chain,
chanTxid: make(chan string, 1), chanTxid: make(chan string, 1),
chanAddrIndex: make(chan txidio, 1), chanAddrIndex: make(chan txidio, 1),
@ -68,7 +68,7 @@ func NewUTXOMempool(chain BlockChain, workers int, subworkers int) *UTXOMempool
} }
// GetTransactions returns slice of mempool transactions for given address // GetTransactions returns slice of mempool transactions for given address
func (m *UTXOMempool) GetTransactions(address string) ([]string, error) { func (m *MempoolBitcoinType) GetTransactions(address string) ([]string, error) {
parser := m.chain.GetChainParser() parser := m.chain.GetChainParser()
addrDesc, err := parser.GetAddrDescFromAddress(address) addrDesc, err := parser.GetAddrDescFromAddress(address)
if err != nil { if err != nil {
@ -78,7 +78,7 @@ func (m *UTXOMempool) GetTransactions(address string) ([]string, error) {
} }
// GetAddrDescTransactions returns slice of mempool transactions for given address descriptor // GetAddrDescTransactions returns slice of mempool transactions for given address descriptor
func (m *UTXOMempool) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]string, error) { func (m *MempoolBitcoinType) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]string, error) {
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
outpoints := m.addrDescToTx[string(addrDesc)] outpoints := m.addrDescToTx[string(addrDesc)]
@ -89,14 +89,14 @@ func (m *UTXOMempool) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]str
return txs, nil return txs, nil
} }
func (m *UTXOMempool) updateMappings(newTxToInputOutput map[string][]addrIndex, newAddrDescToTx map[string][]outpoint) { func (m *MempoolBitcoinType) updateMappings(newTxToInputOutput map[string][]addrIndex, newAddrDescToTx map[string][]outpoint) {
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
m.txToInputOutput = newTxToInputOutput m.txToInputOutput = newTxToInputOutput
m.addrDescToTx = newAddrDescToTx m.addrDescToTx = newAddrDescToTx
} }
func (m *UTXOMempool) getInputAddress(input outpoint) *addrIndex { func (m *MempoolBitcoinType) getInputAddress(input outpoint) *addrIndex {
itx, err := m.chain.GetTransactionForMempool(input.txid) itx, err := m.chain.GetTransactionForMempool(input.txid)
if err != nil { if err != nil {
glog.Error("cannot get transaction ", input.txid, ": ", err) glog.Error("cannot get transaction ", input.txid, ": ", err)
@ -115,7 +115,7 @@ func (m *UTXOMempool) getInputAddress(input outpoint) *addrIndex {
} }
func (m *UTXOMempool) getTxAddrs(txid string, chanInput chan outpoint, chanResult chan *addrIndex) ([]addrIndex, bool) { func (m *MempoolBitcoinType) getTxAddrs(txid string, chanInput chan outpoint, chanResult chan *addrIndex) ([]addrIndex, bool) {
tx, err := m.chain.GetTransactionForMempool(txid) tx, err := m.chain.GetTransactionForMempool(txid)
if err != nil { if err != nil {
glog.Error("cannot get transaction ", txid, ": ", err) glog.Error("cannot get transaction ", txid, ": ", err)
@ -170,7 +170,7 @@ func (m *UTXOMempool) getTxAddrs(txid string, chanInput chan outpoint, chanResul
// Resync gets mempool transactions and maps outputs to transactions. // Resync gets mempool transactions and maps outputs to transactions.
// Resync is not reentrant, it should be called from a single thread. // Resync is not reentrant, it should be called from a single thread.
// Read operations (GetTransactions) are safe. // Read operations (GetTransactions) are safe.
func (m *UTXOMempool) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) { func (m *MempoolBitcoinType) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) {
start := time.Now() start := time.Now()
glog.V(1).Info("mempool: resync") glog.V(1).Info("mempool: resync")
m.onNewTxAddr = onNewTxAddr m.onNewTxAddr = onNewTxAddr

View File

@ -7,21 +7,21 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
) )
// NonUTXOMempool is mempool handle of non UTXO chains // MempoolEthereumType is mempool handle of EthereumType chains
type NonUTXOMempool struct { type MempoolEthereumType struct {
chain BlockChain chain BlockChain
mux sync.Mutex mux sync.Mutex
txToInputOutput map[string][]addrIndex txToInputOutput map[string][]addrIndex
addrDescToTx map[string][]outpoint addrDescToTx map[string][]outpoint
} }
// NewNonUTXOMempool creates new mempool handler. // NewMempoolEthereumType creates new mempool handler.
func NewNonUTXOMempool(chain BlockChain) *NonUTXOMempool { func NewMempoolEthereumType(chain BlockChain) *MempoolEthereumType {
return &NonUTXOMempool{chain: chain} return &MempoolEthereumType{chain: chain}
} }
// GetTransactions returns slice of mempool transactions for given address // GetTransactions returns slice of mempool transactions for given address
func (m *NonUTXOMempool) GetTransactions(address string) ([]string, error) { func (m *MempoolEthereumType) GetTransactions(address string) ([]string, error) {
parser := m.chain.GetChainParser() parser := m.chain.GetChainParser()
addrDesc, err := parser.GetAddrDescFromAddress(address) addrDesc, err := parser.GetAddrDescFromAddress(address)
if err != nil { if err != nil {
@ -31,7 +31,7 @@ func (m *NonUTXOMempool) GetTransactions(address string) ([]string, error) {
} }
// GetAddrDescTransactions returns slice of mempool transactions for given address descriptor // GetAddrDescTransactions returns slice of mempool transactions for given address descriptor
func (m *NonUTXOMempool) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]string, error) { func (m *MempoolEthereumType) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]string, error) {
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
outpoints := m.addrDescToTx[string(addrDesc)] outpoints := m.addrDescToTx[string(addrDesc)]
@ -42,7 +42,7 @@ func (m *NonUTXOMempool) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]
return txs, nil return txs, nil
} }
func (m *NonUTXOMempool) updateMappings(newTxToInputOutput map[string][]addrIndex, newAddrDescToTx map[string][]outpoint) { func (m *MempoolEthereumType) updateMappings(newTxToInputOutput map[string][]addrIndex, newAddrDescToTx map[string][]outpoint) {
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
m.txToInputOutput = newTxToInputOutput m.txToInputOutput = newTxToInputOutput
@ -52,7 +52,7 @@ func (m *NonUTXOMempool) updateMappings(newTxToInputOutput map[string][]addrInde
// Resync gets mempool transactions and maps outputs to transactions. // Resync gets mempool transactions and maps outputs to transactions.
// Resync is not reentrant, it should be called from a single thread. // Resync is not reentrant, it should be called from a single thread.
// Read operations (GetTransactions) are safe. // Read operations (GetTransactions) are safe.
func (m *NonUTXOMempool) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) { func (m *MempoolEthereumType) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) {
start := time.Now() start := time.Now()
glog.V(1).Info("Mempool: resync") glog.V(1).Info("Mempool: resync")
txs, err := m.chain.GetMempool() txs, err := m.chain.GetMempool()

View File

@ -9,6 +9,16 @@ import (
"math/big" "math/big"
) )
// ChainType is type of the blockchain
type ChainType int
const (
// ChainBitcoinType is blockchain derived from bitcoin
ChainBitcoinType = ChainType(iota)
// TypeEthereum is blockchain derived from ethereum
ChainEthereumType
)
// errors with specific meaning returned by blockchain rpc // errors with specific meaning returned by blockchain rpc
var ( var (
// ErrBlockNotFound is returned when block is not found // ErrBlockNotFound is returned when block is not found
@ -23,11 +33,13 @@ var (
ErrTxidMissing = errors.New("Txid missing") ErrTxidMissing = errors.New("Txid missing")
) )
// ScriptSig contains data about input script
type ScriptSig struct { type ScriptSig struct {
// Asm string `json:"asm"` // Asm string `json:"asm"`
Hex string `json:"hex"` Hex string `json:"hex"`
} }
// Vin contains data about tx output
type Vin struct { type Vin struct {
Coinbase string `json:"coinbase"` Coinbase string `json:"coinbase"`
Txid string `json:"txid"` Txid string `json:"txid"`
@ -37,6 +49,7 @@ type Vin struct {
Addresses []string `json:"addresses"` Addresses []string `json:"addresses"`
} }
// ScriptPubKey contains data about output script
type ScriptPubKey struct { type ScriptPubKey struct {
// Asm string `json:"asm"` // Asm string `json:"asm"`
Hex string `json:"hex,omitempty"` Hex string `json:"hex,omitempty"`
@ -44,6 +57,7 @@ type ScriptPubKey struct {
Addresses []string `json:"addresses"` Addresses []string `json:"addresses"`
} }
// Vout contains data about tx output
type Vout struct { type Vout struct {
ValueSat big.Int ValueSat big.Int
JsonValue json.Number `json:"value"` JsonValue json.Number `json:"value"`
@ -66,6 +80,7 @@ type Tx struct {
Blocktime int64 `json:"blocktime,omitempty"` Blocktime int64 `json:"blocktime,omitempty"`
} }
// Block is block header and list of transactions
type Block struct { type Block struct {
BlockHeader BlockHeader
Txs []Tx `json:"tx"` Txs []Tx `json:"tx"`
@ -93,6 +108,7 @@ type BlockInfo struct {
Txids []string `json:"tx,omitempty"` Txids []string `json:"tx,omitempty"`
} }
// MempoolEntry is used to get data about mempool entry
type MempoolEntry struct { type MempoolEntry struct {
Size uint32 `json:"size"` Size uint32 `json:"size"`
FeeSat big.Int FeeSat big.Int
@ -110,6 +126,7 @@ type MempoolEntry struct {
Depends []string `json:"depends"` Depends []string `json:"depends"`
} }
// ChainInfo is used to get information about blockchain
type ChainInfo struct { type ChainInfo struct {
Chain string `json:"chain"` Chain string `json:"chain"`
Blocks int `json:"blocks"` Blocks int `json:"blocks"`
@ -124,6 +141,7 @@ type ChainInfo struct {
Warnings string `json:"warnings"` Warnings string `json:"warnings"`
} }
// RPCError defines rpc error returned by backend
type RPCError struct { type RPCError struct {
Code int `json:"code"` Code int `json:"code"`
Message string `json:"message"` Message string `json:"message"`
@ -182,13 +200,10 @@ type BlockChain interface {
// BlockChainParser defines common interface to parsing and conversions of block chain data // BlockChainParser defines common interface to parsing and conversions of block chain data
type BlockChainParser interface { type BlockChainParser interface {
// chain configuration description // type of the blockchain
// UTXO chains need "inputs" column in db, that map transactions to transactions that spend them GetChainType() ChainType
// non UTXO chains have mapping of address to input and output transactions directly in "outputs" column in db // KeepBlockAddresses returns number of blocks which are to be kept in blockTxs column
IsUTXOChain() bool // to be used for rollbacks
// KeepBlockAddresses returns number of blocks which are to be kept in blockaddresses column
// and used in case of fork
// if 0 the blockaddresses column is not used at all (usually non UTXO chains)
KeepBlockAddresses() int KeepBlockAddresses() int
// AmountToDecimalString converts amount in big.Int to string with decimal point in the correct place // AmountToDecimalString converts amount in big.Int to string with decimal point in the correct place
AmountToDecimalString(a *big.Int) string AmountToDecimalString(a *big.Int) string

View File

@ -22,7 +22,7 @@ type bulkAddresses struct {
// BulkConnect is used to connect blocks in bulk, faster but if interrupted inconsistent way // BulkConnect is used to connect blocks in bulk, faster but if interrupted inconsistent way
type BulkConnect struct { type BulkConnect struct {
d *RocksDB d *RocksDB
isUTXO bool chainType bchain.ChainType
bulkAddresses []bulkAddresses bulkAddresses []bulkAddresses
bulkAddressesCount int bulkAddressesCount int
txAddressesMap map[string]*TxAddresses txAddressesMap map[string]*TxAddresses
@ -42,7 +42,7 @@ const (
func (d *RocksDB) InitBulkConnect() (*BulkConnect, error) { func (d *RocksDB) InitBulkConnect() (*BulkConnect, error) {
bc := &BulkConnect{ bc := &BulkConnect{
d: d, d: d,
isUTXO: d.chainParser.IsUTXOChain(), chainType: d.chainParser.GetChainType(),
txAddressesMap: make(map[string]*TxAddresses), txAddressesMap: make(map[string]*TxAddresses),
balances: make(map[string]*AddrBalance), balances: make(map[string]*AddrBalance),
} }
@ -168,11 +168,12 @@ func (b *BulkConnect) storeBulkAddresses(wb *gorocksdb.WriteBatch) error {
// ConnectBlock connects block in bulk mode // ConnectBlock connects block in bulk mode
func (b *BulkConnect) ConnectBlock(block *bchain.Block, storeBlockTxs bool) error { func (b *BulkConnect) ConnectBlock(block *bchain.Block, storeBlockTxs bool) error {
b.height = block.Height b.height = block.Height
if !b.isUTXO { // for non bitcoin types connect blocks in non bulk mode
if b.chainType != bchain.ChainBitcoinType {
return b.d.ConnectBlock(block) return b.d.ConnectBlock(block)
} }
addresses := make(map[string][]outpoint) addresses := make(map[string][]outpoint)
if err := b.d.processAddressesUTXO(block, addresses, b.txAddressesMap, b.balances); err != nil { if err := b.d.processAddressesBitcoinType(block, addresses, b.txAddressesMap, b.balances); err != nil {
return err return err
} }
var storeAddressesChan, storeBalancesChan chan error var storeAddressesChan, storeBalancesChan chan error

View File

@ -271,21 +271,21 @@ func (d *RocksDB) writeBlock(block *bchain.Block, op int) error {
} }
} }
isUTXO := d.chainParser.IsUTXOChain() chainType := d.chainParser.GetChainType()
if err := d.writeHeightFromBlock(wb, block, op); err != nil { if err := d.writeHeightFromBlock(wb, block, op); err != nil {
return err return err
} }
if isUTXO { if chainType == bchain.ChainBitcoinType {
if op == opDelete { if op == opDelete {
// block does not contain mapping tx-> input address, which is necessary to recreate // block does not contain mapping tx-> input address, which is necessary to recreate
// unspentTxs; therefore it is not possible to DisconnectBlocks this way // unspentTxs; therefore it is not possible to DisconnectBlocks this way
return errors.New("DisconnectBlock is not supported for UTXO chains") return errors.New("DisconnectBlock is not supported for BitcoinType chains")
} }
addresses := make(map[string][]outpoint) addresses := make(map[string][]outpoint)
txAddressesMap := make(map[string]*TxAddresses) txAddressesMap := make(map[string]*TxAddresses)
balances := make(map[string]*AddrBalance) balances := make(map[string]*AddrBalance)
if err := d.processAddressesUTXO(block, addresses, txAddressesMap, balances); err != nil { if err := d.processAddressesBitcoinType(block, addresses, txAddressesMap, balances); err != nil {
return err return err
} }
if err := d.storeAddresses(wb, block.Height, addresses); err != nil { if err := d.storeAddresses(wb, block.Height, addresses); err != nil {
@ -300,8 +300,8 @@ func (d *RocksDB) writeBlock(block *bchain.Block, op int) error {
if err := d.storeAndCleanupBlockTxs(wb, block); err != nil { if err := d.storeAndCleanupBlockTxs(wb, block); err != nil {
return err return err
} }
} else { } else if chainType == bchain.ChainEthereumType {
if err := d.writeAddressesNonUTXO(wb, block, op); err != nil { if err := d.writeAddressesTypeEthereum(wb, block, op); err != nil {
return err return err
} }
} }
@ -375,7 +375,7 @@ func (d *RocksDB) GetAndResetConnectBlockStats() string {
return s return s
} }
func (d *RocksDB) processAddressesUTXO(block *bchain.Block, addresses map[string][]outpoint, txAddressesMap map[string]*TxAddresses, balances map[string]*AddrBalance) error { func (d *RocksDB) processAddressesBitcoinType(block *bchain.Block, addresses map[string][]outpoint, txAddressesMap map[string]*TxAddresses, balances map[string]*AddrBalance) error {
blockTxIDs := make([][]byte, len(block.Txs)) blockTxIDs := make([][]byte, len(block.Txs))
blockTxAddresses := make([]*TxAddresses, len(block.Txs)) blockTxAddresses := make([]*TxAddresses, len(block.Txs))
// first process all outputs so that inputs can point to txs in this block // first process all outputs so that inputs can point to txs in this block
@ -861,7 +861,7 @@ func (d *RocksDB) addAddrDescToRecords(op int, wb *gorocksdb.WriteBatch, records
return nil return nil
} }
func (d *RocksDB) writeAddressesNonUTXO(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error { func (d *RocksDB) writeAddressesTypeEthereum(wb *gorocksdb.WriteBatch, block *bchain.Block, op int) error {
addresses := make(map[string][]outpoint) addresses := make(map[string][]outpoint)
for _, tx := range block.Txs { for _, tx := range block.Txs {
btxID, err := d.chainParser.PackTxid(tx.Txid) btxID, err := d.chainParser.PackTxid(tx.Txid)
@ -1166,9 +1166,9 @@ func (d *RocksDB) disconnectTxAddresses(wb *gorocksdb.WriteBatch, height uint32,
return nil return nil
} }
// DisconnectBlockRangeUTXO removes all data belonging to blocks in range lower-higher // DisconnectBlockRangeBitcoinType removes all data belonging to blocks in range lower-higher
// if they are in the range kept in the cfBlockTxids column // if they are in the range kept in the cfBlockTxids column
func (d *RocksDB) DisconnectBlockRangeUTXO(lower uint32, higher uint32) error { func (d *RocksDB) DisconnectBlockRangeBitcoinType(lower uint32, higher uint32) error {
glog.Infof("db: disconnecting blocks %d-%d", lower, higher) glog.Infof("db: disconnecting blocks %d-%d", lower, higher)
blocks := make([][]blockTxs, higher-lower+1) blocks := make([][]blockTxs, higher-lower+1)
for height := lower; height <= higher; height++ { for height := lower; height <= higher; height++ {

View File

@ -1,4 +1,4 @@
// +build unittest // build unittest
package db package db
@ -151,7 +151,7 @@ func checkColumn(d *RocksDB, col int, kp []keyPair) error {
return nil return nil
} }
func verifyAfterUTXOBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) { func verifyAfterBitcoinTypeOBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) {
if err := checkColumn(d, cfHeight, []keyPair{ if err := checkColumn(d, cfHeight, []keyPair{
keyPair{ keyPair{
"000370d5", "000370d5",
@ -232,7 +232,7 @@ func verifyAfterUTXOBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) {
} }
} }
func verifyAfterUTXOBlock2(t *testing.T, d *RocksDB) { func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) {
if err := checkColumn(d, cfHeight, []keyPair{ if err := checkColumn(d, cfHeight, []keyPair{
keyPair{ keyPair{
"000370d5", "000370d5",
@ -423,7 +423,7 @@ func testTxCache(t *testing.T, d *RocksDB, b *bchain.Block, tx *bchain.Tx) {
} }
} }
// TestRocksDB_Index_UTXO is an integration test probing the whole indexing functionality for UTXO chains // TestRocksDB_Index_BitcoinType is an integration test probing the whole indexing functionality for BitcoinType chains
// It does the following: // It does the following:
// 1) Connect two blocks (inputs from 2nd block are spending some outputs from the 1st block) // 1) Connect two blocks (inputs from 2nd block are spending some outputs from the 1st block)
// 2) GetTransactions for various addresses / low-high ranges // 2) GetTransactions for various addresses / low-high ranges
@ -433,25 +433,25 @@ func testTxCache(t *testing.T, d *RocksDB, b *bchain.Block, tx *bchain.Tx) {
// 6) Disconnect the block 2 using BlockTxs column // 6) Disconnect the block 2 using BlockTxs column
// 7) Reconnect block 2 and check // 7) Reconnect block 2 and check
// After each step, the content of DB is examined and any difference against expected state is regarded as failure // After each step, the content of DB is examined and any difference against expected state is regarded as failure
func TestRocksDB_Index_UTXO(t *testing.T) { func TestRocksDB_Index_BitcoinType(t *testing.T) {
d := setupRocksDB(t, &testBitcoinParser{ d := setupRocksDB(t, &testBitcoinParser{
BitcoinParser: bitcoinTestnetParser(), BitcoinParser: bitcoinTestnetParser(),
}) })
defer closeAndDestroyRocksDB(t, d) defer closeAndDestroyRocksDB(t, d)
// connect 1st block - will log warnings about missing UTXO transactions in txAddresses column // connect 1st block - will log warnings about missing UTXO transactions in txAddresses column
block1 := dbtestdata.GetTestUTXOBlock1(d.chainParser) block1 := dbtestdata.GetTestBitcoinTypeBlock1(d.chainParser)
if err := d.ConnectBlock(block1); err != nil { if err := d.ConnectBlock(block1); err != nil {
t.Fatal(err) t.Fatal(err)
} }
verifyAfterUTXOBlock1(t, d, false) verifyAfterBitcoinTypeOBlock1(t, d, false)
// connect 2nd block - use some outputs from the 1st block as the inputs and 1 input uses tx from the same block // connect 2nd block - use some outputs from the 1st block as the inputs and 1 input uses tx from the same block
block2 := dbtestdata.GetTestUTXOBlock2(d.chainParser) block2 := dbtestdata.GetTestBitcoinTypeBlock2(d.chainParser)
if err := d.ConnectBlock(block2); err != nil { if err := d.ConnectBlock(block2); err != nil {
t.Fatal(err) t.Fatal(err)
} }
verifyAfterUTXOBlock2(t, d) verifyAfterBitcoinTypeBlock2(t, d)
// get transactions for various addresses / low-high ranges // get transactions for various addresses / low-high ranges
verifyGetTransactions(t, d, dbtestdata.Addr2, 0, 1000000, []txidVoutOutput{ verifyGetTransactions(t, d, dbtestdata.Addr2, 0, 1000000, []txidVoutOutput{
@ -532,27 +532,27 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
} }
} }
// DisconnectBlock for UTXO chains is not possible // DisconnectBlock for BitcoinType chains is not possible
err = d.DisconnectBlock(block2) err = d.DisconnectBlock(block2)
if err == nil || err.Error() != "DisconnectBlock is not supported for UTXO chains" { if err == nil || err.Error() != "DisconnectBlock is not supported for BitcoinType chains" {
t.Fatal(err) t.Fatal(err)
} }
verifyAfterUTXOBlock2(t, d) verifyAfterBitcoinTypeBlock2(t, d)
// try to disconnect both blocks, however only the last one is kept, it is not possible // try to disconnect both blocks, however only the last one is kept, it is not possible
err = d.DisconnectBlockRangeUTXO(225493, 225494) err = d.DisconnectBlockRangeBitcoinType(225493, 225494)
if err == nil || err.Error() != "Cannot disconnect blocks with height 225493 and lower. It is necessary to rebuild index." { if err == nil || err.Error() != "Cannot disconnect blocks with height 225493 and lower. It is necessary to rebuild index." {
t.Fatal(err) t.Fatal(err)
} }
verifyAfterUTXOBlock2(t, d) verifyAfterBitcoinTypeBlock2(t, d)
// disconnect the 2nd block, verify that the db contains only data from the 1st block with restored unspentTxs // disconnect the 2nd block, verify that the db contains only data from the 1st block with restored unspentTxs
// and that the cached tx is removed // and that the cached tx is removed
err = d.DisconnectBlockRangeUTXO(225494, 225494) err = d.DisconnectBlockRangeBitcoinType(225494, 225494)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
verifyAfterUTXOBlock1(t, d, true) verifyAfterBitcoinTypeOBlock1(t, d, true)
if err := checkColumn(d, cfTransactions, []keyPair{}); err != nil { if err := checkColumn(d, cfTransactions, []keyPair{}); err != nil {
{ {
t.Fatal(err) t.Fatal(err)
@ -563,7 +563,7 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
if err := d.ConnectBlock(block2); err != nil { if err := d.ConnectBlock(block2); err != nil {
t.Fatal(err) t.Fatal(err)
} }
verifyAfterUTXOBlock2(t, d) verifyAfterBitcoinTypeBlock2(t, d)
// test public methods for address balance and tx addresses // test public methods for address balance and tx addresses
@ -627,7 +627,7 @@ func TestRocksDB_Index_UTXO(t *testing.T) {
} }
func Test_BulkConnect_UTXO(t *testing.T) { func Test_BulkConnect_BitcoinType(t *testing.T) {
d := setupRocksDB(t, &testBitcoinParser{ d := setupRocksDB(t, &testBitcoinParser{
BitcoinParser: bitcoinTestnetParser(), BitcoinParser: bitcoinTestnetParser(),
}) })
@ -642,7 +642,7 @@ func Test_BulkConnect_UTXO(t *testing.T) {
t.Fatal("DB not in DbStateInconsistent") t.Fatal("DB not in DbStateInconsistent")
} }
if err := bc.ConnectBlock(dbtestdata.GetTestUTXOBlock1(d.chainParser), false); err != nil { if err := bc.ConnectBlock(dbtestdata.GetTestBitcoinTypeBlock1(d.chainParser), false); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := checkColumn(d, cfBlockTxs, []keyPair{}); err != nil { if err := checkColumn(d, cfBlockTxs, []keyPair{}); err != nil {
@ -651,7 +651,7 @@ func Test_BulkConnect_UTXO(t *testing.T) {
} }
} }
if err := bc.ConnectBlock(dbtestdata.GetTestUTXOBlock2(d.chainParser), true); err != nil { if err := bc.ConnectBlock(dbtestdata.GetTestBitcoinTypeBlock2(d.chainParser), true); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -663,7 +663,7 @@ func Test_BulkConnect_UTXO(t *testing.T) {
t.Fatal("DB not in DbStateOpen") t.Fatal("DB not in DbStateOpen")
} }
verifyAfterUTXOBlock2(t, d) verifyAfterBitcoinTypeBlock2(t, d)
} }
func Test_packBigint_unpackBigint(t *testing.T) { func Test_packBigint_unpackBigint(t *testing.T) {

View File

@ -393,9 +393,9 @@ func (w *SyncWorker) getBlockChain(out chan blockResult, done chan struct{}) {
// DisconnectBlocks removes all data belonging to blocks in range lower-higher, // DisconnectBlocks removes all data belonging to blocks in range lower-higher,
func (w *SyncWorker) DisconnectBlocks(lower uint32, higher uint32, hashes []string) error { func (w *SyncWorker) DisconnectBlocks(lower uint32, higher uint32, hashes []string) error {
glog.Infof("sync: disconnecting blocks %d-%d", lower, higher) glog.Infof("sync: disconnecting blocks %d-%d", lower, higher)
// if the chain is UTXO, always use DisconnectBlockRange // if the chain is ChainBitcoinType, always use DisconnectBlockRange
if w.chain.GetChainParser().IsUTXOChain() { if w.chain.GetChainParser().GetChainType() == bchain.ChainBitcoinType {
return w.db.DisconnectBlockRangeUTXO(lower, higher) return w.db.DisconnectBlockRangeBitcoinType(lower, higher)
} }
blocks := make([]*bchain.Block, len(hashes)) blocks := make([]*bchain.Block, len(hashes))
var err error var err error

View File

@ -86,8 +86,8 @@ Good examples of coin configuration are
* `parse` Use binary parser for block decoding if *true* else call verbose back-end RPC method that returns * `parse` Use binary parser for block decoding if *true* else call verbose back-end RPC method that returns
JSON. Note that verbose method is slow and not every coin support it. However there are coin implementations JSON. Note that verbose method is slow and not every coin support it. However there are coin implementations
that don't support binary parsing (e.g. ZCash). that don't support binary parsing (e.g. ZCash).
* `mempool_workers` Number of workers for UTXO mempool. * `mempool_workers` Number of workers for BitcoinType mempool.
* `mempool_sub_workers` Number of subworkers for UTXO mempool. * `mempool_sub_workers` Number of subworkers for BitcoinType mempool.
* `block_addresses_to_keep` Number of blocks that are to be kept in blockaddresses column. * `block_addresses_to_keep` Number of blocks that are to be kept in blockaddresses column.
* `additional_params` Object of coin-specific params. * `additional_params` Object of coin-specific params.

View File

@ -48,10 +48,10 @@ func setupRocksDB(t *testing.T, parser bchain.BlockChainParser) (*db.RocksDB, *c
} }
d.SetInternalState(is) d.SetInternalState(is)
// import data // import data
if err := d.ConnectBlock(dbtestdata.GetTestUTXOBlock1(parser)); err != nil { if err := d.ConnectBlock(dbtestdata.GetTestBitcoinTypeBlock1(parser)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := d.ConnectBlock(dbtestdata.GetTestUTXOBlock2(parser)); err != nil { if err := d.ConnectBlock(dbtestdata.GetTestBitcoinTypeBlock2(parser)); err != nil {
t.Fatal(err) t.Fatal(err)
} }
return d, is, tmp return d, is, tmp
@ -584,7 +584,7 @@ func socketioTests(t *testing.T, ts *httptest.Server) {
} }
} }
func Test_PublicServer_UTXO(t *testing.T) { func Test_PublicServer_BitcoinType(t *testing.T) {
s, dbpath := setupPublicHTTPServer(t) s, dbpath := setupPublicHTTPServer(t)
defer closeAndDestroyPublicServer(t, s, dbpath) defer closeAndDestroyPublicServer(t, s, dbpath)
s.ConnectFullPublicInterface() s.ConnectFullPublicInterface()
@ -594,5 +594,4 @@ func Test_PublicServer_UTXO(t *testing.T) {
httpTests(t, ts) httpTests(t, ts)
socketioTests(t, ts) socketioTests(t, ts)
} }

View File

@ -54,7 +54,7 @@ func AddressToPubKeyHex(addr string, parser bchain.BlockChainParser) string {
return hex.EncodeToString(b) return hex.EncodeToString(b)
} }
func GetTestUTXOBlock1(parser bchain.BlockChainParser) *bchain.Block { func GetTestBitcoinTypeBlock1(parser bchain.BlockChainParser) *bchain.Block {
return &bchain.Block{ return &bchain.Block{
BlockHeader: bchain.BlockHeader{ BlockHeader: bchain.BlockHeader{
Height: 225493, Height: 225493,
@ -119,7 +119,7 @@ func GetTestUTXOBlock1(parser bchain.BlockChainParser) *bchain.Block {
} }
} }
func GetTestUTXOBlock2(parser bchain.BlockChainParser) *bchain.Block { func GetTestBitcoinTypeBlock2(parser bchain.BlockChainParser) *bchain.Block {
return &bchain.Block{ return &bchain.Block{
BlockHeader: bchain.BlockHeader{ BlockHeader: bchain.BlockHeader{
Height: 225494, Height: 225494,

View File

@ -45,26 +45,26 @@ func (c *fakeBlockChain) GetChainInfo() (v *bchain.ChainInfo, err error) {
Chain: c.GetNetworkName(), Chain: c.GetNetworkName(),
Blocks: 2, Blocks: 2,
Headers: 2, Headers: 2,
Bestblockhash: GetTestUTXOBlock2(c.parser).BlockHeader.Hash, Bestblockhash: GetTestBitcoinTypeBlock2(c.parser).BlockHeader.Hash,
Version: "001001", Version: "001001",
Subversion: c.GetSubversion(), Subversion: c.GetSubversion(),
}, nil }, nil
} }
func (c *fakeBlockChain) GetBestBlockHash() (v string, err error) { func (c *fakeBlockChain) GetBestBlockHash() (v string, err error) {
return GetTestUTXOBlock2(c.parser).BlockHeader.Hash, nil return GetTestBitcoinTypeBlock2(c.parser).BlockHeader.Hash, nil
} }
func (c *fakeBlockChain) GetBestBlockHeight() (v uint32, err error) { func (c *fakeBlockChain) GetBestBlockHeight() (v uint32, err error) {
return GetTestUTXOBlock2(c.parser).BlockHeader.Height, nil return GetTestBitcoinTypeBlock2(c.parser).BlockHeader.Height, nil
} }
func (c *fakeBlockChain) GetBlockHash(height uint32) (v string, err error) { func (c *fakeBlockChain) GetBlockHash(height uint32) (v string, err error) {
b1 := GetTestUTXOBlock1(c.parser) b1 := GetTestBitcoinTypeBlock1(c.parser)
if height == b1.BlockHeader.Height { if height == b1.BlockHeader.Height {
return b1.BlockHeader.Hash, nil return b1.BlockHeader.Hash, nil
} }
b2 := GetTestUTXOBlock2(c.parser) b2 := GetTestBitcoinTypeBlock2(c.parser)
if height == b2.BlockHeader.Height { if height == b2.BlockHeader.Height {
return b2.BlockHeader.Hash, nil return b2.BlockHeader.Hash, nil
} }
@ -72,11 +72,11 @@ func (c *fakeBlockChain) GetBlockHash(height uint32) (v string, err error) {
} }
func (c *fakeBlockChain) GetBlockHeader(hash string) (v *bchain.BlockHeader, err error) { func (c *fakeBlockChain) GetBlockHeader(hash string) (v *bchain.BlockHeader, err error) {
b1 := GetTestUTXOBlock1(c.parser) b1 := GetTestBitcoinTypeBlock1(c.parser)
if hash == b1.BlockHeader.Hash { if hash == b1.BlockHeader.Hash {
return &b1.BlockHeader, nil return &b1.BlockHeader, nil
} }
b2 := GetTestUTXOBlock2(c.parser) b2 := GetTestBitcoinTypeBlock2(c.parser)
if hash == b2.BlockHeader.Hash { if hash == b2.BlockHeader.Hash {
return &b2.BlockHeader, nil return &b2.BlockHeader, nil
} }
@ -84,11 +84,11 @@ func (c *fakeBlockChain) GetBlockHeader(hash string) (v *bchain.BlockHeader, err
} }
func (c *fakeBlockChain) GetBlock(hash string, height uint32) (v *bchain.Block, err error) { func (c *fakeBlockChain) GetBlock(hash string, height uint32) (v *bchain.Block, err error) {
b1 := GetTestUTXOBlock1(c.parser) b1 := GetTestBitcoinTypeBlock1(c.parser)
if hash == b1.BlockHeader.Hash || height == b1.BlockHeader.Height { if hash == b1.BlockHeader.Hash || height == b1.BlockHeader.Height {
return b1, nil return b1, nil
} }
b2 := GetTestUTXOBlock2(c.parser) b2 := GetTestBitcoinTypeBlock2(c.parser)
if hash == b2.BlockHeader.Hash || height == b2.BlockHeader.Height { if hash == b2.BlockHeader.Hash || height == b2.BlockHeader.Height {
return b2, nil return b2, nil
} }
@ -106,11 +106,11 @@ func getBlockInfo(b *bchain.Block) *bchain.BlockInfo {
} }
func (c *fakeBlockChain) GetBlockInfo(hash string) (v *bchain.BlockInfo, err error) { func (c *fakeBlockChain) GetBlockInfo(hash string) (v *bchain.BlockInfo, err error) {
b1 := GetTestUTXOBlock1(c.parser) b1 := GetTestBitcoinTypeBlock1(c.parser)
if hash == b1.BlockHeader.Hash { if hash == b1.BlockHeader.Hash {
return getBlockInfo(b1), nil return getBlockInfo(b1), nil
} }
b2 := GetTestUTXOBlock2(c.parser) b2 := GetTestBitcoinTypeBlock2(c.parser)
if hash == b2.BlockHeader.Hash { if hash == b2.BlockHeader.Hash {
return getBlockInfo(b2), nil return getBlockInfo(b2), nil
} }
@ -131,9 +131,9 @@ func getTxInBlock(b *bchain.Block, txid string) *bchain.Tx {
} }
func (c *fakeBlockChain) GetTransaction(txid string) (v *bchain.Tx, err error) { func (c *fakeBlockChain) GetTransaction(txid string) (v *bchain.Tx, err error) {
v = getTxInBlock(GetTestUTXOBlock1(c.parser), txid) v = getTxInBlock(GetTestBitcoinTypeBlock1(c.parser), txid)
if v == nil { if v == nil {
v = getTxInBlock(GetTestUTXOBlock2(c.parser), txid) v = getTxInBlock(GetTestBitcoinTypeBlock2(c.parser), txid)
} }
if v != nil { if v != nil {
return v, nil return v, nil