Refactor names in interface BlockChainParser, added method IsUTXOChain

This commit is contained in:
Martin Boehm 2018-03-23 11:03:41 +01:00
parent f0552ec4ad
commit dda80bd074
5 changed files with 54 additions and 42 deletions

View File

@ -33,19 +33,19 @@ func GetChainParams(chain string) *chaincfg.Params {
return &chaincfg.MainNetParams return &chaincfg.MainNetParams
} }
func (p *BitcoinBlockParser) GetUIDFromVout(output *bchain.Vout) string { func (p *BitcoinBlockParser) GetAddrIDFromVout(output *bchain.Vout) string {
return output.ScriptPubKey.Hex return output.ScriptPubKey.Hex
} }
func (p *BitcoinBlockParser) GetUIDFromAddress(address string) ([]byte, error) { func (p *BitcoinBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) {
return p.AddressToOutputScript(address) return p.AddressToOutputScript(address)
} }
func (p *BitcoinBlockParser) PackUID(str string) ([]byte, error) { func (p *BitcoinBlockParser) PackAddrID(str string) ([]byte, error) {
return hex.DecodeString(str) return hex.DecodeString(str)
} }
func (p *BitcoinBlockParser) UnpackUID(buf []byte) string { func (p *BitcoinBlockParser) UnpackAddrID(buf []byte) string {
return hex.EncodeToString(buf) return hex.EncodeToString(buf)
} }
@ -177,3 +177,7 @@ func (p *BitcoinBlockParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
tx.Blocktime = bt tx.Blocktime = bt
return tx, height, nil return tx, height, nil
} }
func (p *BitcoinBlockParser) IsUTXOChain() bool {
return true
}

View File

@ -26,21 +26,21 @@ func GetChainParams(chain string) *chaincfg.Params {
return &chaincfg.MainNetParams return &chaincfg.MainNetParams
} }
func (p *ZCashBlockParser) GetUIDFromVout(output *bchain.Vout) string { func (p *ZCashBlockParser) GetAddrIDFromVout(output *bchain.Vout) string {
if len(output.ScriptPubKey.Addresses) != 1 { if len(output.ScriptPubKey.Addresses) != 1 {
return "" return ""
} }
return output.ScriptPubKey.Addresses[0] return output.ScriptPubKey.Addresses[0]
} }
func (p *ZCashBlockParser) GetUIDFromAddress(address string) ([]byte, error) { func (p *ZCashBlockParser) GetAddrIDFromAddress(address string) ([]byte, error) {
return p.PackUID(address) return p.PackAddrID(address)
} }
func (p *ZCashBlockParser) PackUID(str string) ([]byte, error) { func (p *ZCashBlockParser) PackAddrID(str string) ([]byte, error) {
return []byte(str), nil return []byte(str), nil
} }
func (p *ZCashBlockParser) UnpackUID(buf []byte) string { func (p *ZCashBlockParser) UnpackAddrID(buf []byte) string {
return string(buf) return string(buf)
} }

View File

@ -28,7 +28,7 @@ type Mempool struct {
chain BlockChain chain BlockChain
mux sync.Mutex mux sync.Mutex
txToInputOutput map[string]inputOutput txToInputOutput map[string]inputOutput
scriptToTx map[string][]outpoint // TODO rename all occurences addrIDToTx map[string][]outpoint
inputs map[outpoint]string inputs map[outpoint]string
} }
@ -42,12 +42,12 @@ func (m *Mempool) GetTransactions(address string) ([]string, error) {
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
parser := m.chain.GetChainParser() parser := m.chain.GetChainParser()
buf, err := parser.GetUIDFromAddress(address) buf, err := parser.GetAddrIDFromAddress(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
outid := parser.UnpackUID(buf) addrID := parser.UnpackAddrID(buf)
outpoints := m.scriptToTx[outid] outpoints := m.addrIDToTx[addrID]
txs := make([]string, 0, len(outpoints)+len(outpoints)/2) txs := make([]string, 0, len(outpoints)+len(outpoints)/2)
for _, o := range outpoints { for _, o := range outpoints {
txs = append(txs, o.txid) txs = append(txs, o.txid)
@ -69,7 +69,7 @@ func (m *Mempool) updateMappings(newTxToInputOutput map[string]inputOutput, newS
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
m.txToInputOutput = newTxToInputOutput m.txToInputOutput = newTxToInputOutput
m.scriptToTx = newScriptToTx m.addrIDToTx = newScriptToTx
m.inputs = newInputs m.inputs = newInputs
} }
@ -85,7 +85,7 @@ func (m *Mempool) Resync(onNewTxAddr func(txid string, addr string)) error {
} }
parser := m.chain.GetChainParser() parser := m.chain.GetChainParser()
newTxToInputOutput := make(map[string]inputOutput, len(m.txToInputOutput)+1) newTxToInputOutput := make(map[string]inputOutput, len(m.txToInputOutput)+1)
newScriptToTx := make(map[string][]outpoint, len(m.scriptToTx)+1) newAddrIDToTx := make(map[string][]outpoint, len(m.addrIDToTx)+1)
newInputs := make(map[outpoint]string, len(m.inputs)+1) newInputs := make(map[outpoint]string, len(m.inputs)+1)
for _, txid := range txs { for _, txid := range txs {
io, exists := m.txToInputOutput[txid] io, exists := m.txToInputOutput[txid]
@ -97,9 +97,9 @@ func (m *Mempool) Resync(onNewTxAddr func(txid string, addr string)) error {
} }
io.outputs = make([]scriptIndex, 0, len(tx.Vout)) io.outputs = make([]scriptIndex, 0, len(tx.Vout))
for _, output := range tx.Vout { for _, output := range tx.Vout {
outid := parser.GetUIDFromVout(&output) addrID := parser.GetAddrIDFromVout(&output)
if outid != "" { if addrID != "" {
io.outputs = append(io.outputs, scriptIndex{outid, output.N}) io.outputs = append(io.outputs, scriptIndex{addrID, output.N})
} }
if onNewTxAddr != nil && len(output.ScriptPubKey.Addresses) == 1 { if onNewTxAddr != nil && len(output.ScriptPubKey.Addresses) == 1 {
onNewTxAddr(tx.Txid, output.ScriptPubKey.Addresses[0]) onNewTxAddr(tx.Txid, output.ScriptPubKey.Addresses[0])
@ -115,13 +115,13 @@ func (m *Mempool) Resync(onNewTxAddr func(txid string, addr string)) error {
} }
newTxToInputOutput[txid] = io newTxToInputOutput[txid] = io
for _, si := range io.outputs { for _, si := range io.outputs {
newScriptToTx[si.script] = append(newScriptToTx[si.script], outpoint{txid, si.n}) newAddrIDToTx[si.script] = append(newAddrIDToTx[si.script], outpoint{txid, si.n})
} }
for _, i := range io.inputs { for _, i := range io.inputs {
newInputs[i] = txid newInputs[i] = txid
} }
} }
m.updateMappings(newTxToInputOutput, newScriptToTx, newInputs) m.updateMappings(newTxToInputOutput, newAddrIDToTx, newInputs)
glog.Info("Mempool: resync finished in ", time.Since(start), ", ", len(m.txToInputOutput), " transactions in mempool") glog.Info("Mempool: resync finished in ", time.Since(start), ", ", len(m.txToInputOutput), " transactions in mempool")
return nil return nil
} }

View File

@ -112,14 +112,22 @@ type BlockChain interface {
} }
type BlockChainParser interface { type BlockChainParser interface {
GetUIDFromVout(output *Vout) string // self description
GetUIDFromAddress(address string) ([]byte, error) // UTXO chains need "inputs" column in db, that map transactions to transactions that spend them
PackUID(script string) ([]byte, error) // non UTXO chains have mapping of address to input and output transactions directly in "outputs" column in db
UnpackUID(buf []byte) string IsUTXOChain() bool
// address id conversions
GetAddrIDFromVout(output *Vout) string
GetAddrIDFromAddress(address string) ([]byte, error)
PackAddrID(addrID string) ([]byte, error)
UnpackAddrID(buf []byte) string
// address to output script conversions
AddressToOutputScript(address string) ([]byte, error) AddressToOutputScript(address string) ([]byte, error)
OutputScriptToAddresses(script []byte) ([]string, error) OutputScriptToAddresses(script []byte) ([]string, error)
// transactions
ParseTx(b []byte) (*Tx, error) ParseTx(b []byte) (*Tx, error)
ParseBlock(b []byte) (*Block, error)
PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error) PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error)
UnpackTx(buf []byte) (*Tx, uint32, error) UnpackTx(buf []byte) (*Tx, uint32, error)
// blocks
ParseBlock(b []byte) (*Block, error)
} }

View File

@ -142,13 +142,13 @@ func (d *RocksDB) GetTransactions(address string, lower uint32, higher uint32, f
if glog.V(1) { if glog.V(1) {
glog.Infof("rocksdb: address get %s %d-%d ", address, lower, higher) glog.Infof("rocksdb: address get %s %d-%d ", address, lower, higher)
} }
outid, err := d.chainParser.GetUIDFromAddress(address) addrID, err := d.chainParser.GetAddrIDFromAddress(address)
kstart, err := packOutputKey(outid, lower) kstart, err := packOutputKey(addrID, lower)
if err != nil { if err != nil {
return err return err
} }
kstop, err := packOutputKey(outid, higher) kstop, err := packOutputKey(addrID, higher)
if err != nil { if err != nil {
return err return err
} }
@ -241,12 +241,12 @@ func (d *RocksDB) writeOutputs(wb *gorocksdb.WriteBatch, block *bchain.Block, op
for _, tx := range block.Txs { for _, tx := range block.Txs {
for _, output := range tx.Vout { for _, output := range tx.Vout {
outid := d.chainParser.GetUIDFromVout(&output) addrID := d.chainParser.GetAddrIDFromVout(&output)
if outid != "" { if addrID != "" {
if len(outid) > 1024 { if len(addrID) > 1024 {
glog.Infof("block %d, skipping outid of length %d", block.Height, len(outid)/2) glog.Infof("block %d, skipping addrID of length %d", block.Height, len(addrID)/2)
} else { } else {
records[outid] = append(records[outid], outpoint{ records[addrID] = append(records[addrID], outpoint{
txid: tx.Txid, txid: tx.Txid,
vout: output.N, vout: output.N,
}) })
@ -263,25 +263,25 @@ func (d *RocksDB) writeOutputs(wb *gorocksdb.WriteBatch, block *bchain.Block, op
} }
} }
for outid, outpoints := range records { for addrID, outpoints := range records {
bOutid, err := d.chainParser.PackUID(outid) bOutid, err := d.chainParser.PackAddrID(addrID)
if err != nil { if err != nil {
glog.Warningf("rocksdb: packUID: %v - %d %s", err, block.Height, outid) glog.Warningf("rocksdb: addrID: %v - %d %s", err, block.Height, addrID)
continue continue
} }
key, err := packOutputKey(bOutid, block.Height) key, err := packOutputKey(bOutid, block.Height)
if err != nil { if err != nil {
glog.Warningf("rocksdb: packOutputKey: %v - %d %s", err, block.Height, outid) glog.Warningf("rocksdb: packOutputKey: %v - %d %s", err, block.Height, addrID)
continue
}
val, err := packOutputValue(outpoints)
if err != nil {
glog.Warningf("rocksdb: packOutputValue: %v", err)
continue continue
} }
switch op { switch op {
case opInsert: case opInsert:
val, err := packOutputValue(outpoints)
if err != nil {
glog.Warningf("rocksdb: packOutputValue: %v", err)
continue
}
wb.PutCF(d.cfh[cfOutputs], key, val) wb.PutCF(d.cfh[cfOutputs], key, val)
case opDelete: case opDelete:
wb.DeleteCF(d.cfh[cfOutputs], key) wb.DeleteCF(d.cfh[cfOutputs], key)