simplify names and interfaces

pull/1/head
Jan Pochyla 2017-09-06 15:36:55 +02:00
parent cbce18f47e
commit 1c6d622834
3 changed files with 66 additions and 72 deletions

View File

@ -135,8 +135,8 @@ func (b *BitcoinRPC) GetTransaction(txid string) (tx *Tx, err error) {
return return
} }
// GetOutpointAddresses returns all unique addresses from given transaction output. // GetAddresses returns all unique addresses from given transaction output.
func (b *BitcoinRPC) GetOutpointAddresses(txid string, vout uint32) ([]string, error) { func (b *BitcoinRPC) GetAddresses(txid string, vout uint32) ([]string, error) {
tx, err := b.GetTransaction(txid) tx, err := b.GetTransaction(txid)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -11,21 +11,25 @@ type BlockParser interface {
ParseBlock(b []byte) (*Block, error) ParseBlock(b []byte) (*Block, error)
} }
type BlockOracle interface { var (
ErrTxNotFound = errors.New("transaction not found")
)
type Blocks interface {
GetBestBlockHash() (string, error) GetBestBlockHash() (string, error)
GetBlockHash(height uint32) (string, error) GetBlockHash(height uint32) (string, error)
GetBlock(hash string) (*Block, error) GetBlock(hash string) (*Block, error)
} }
type OutpointAddressOracle interface { type Outpoints interface {
GetOutpointAddresses(txid string, vout uint32) ([]string, error) GetAddresses(txid string, vout uint32) ([]string, error)
} }
type AddressTransactionOracle interface { type Addresses interface {
GetAddressTransactions(address string, lower uint32, higher uint32, fn func(txids []string) error) error GetTransactions(address string, lower uint32, higher uint32, fn func(txids []string) error) error
} }
type BlockIndex interface { type Indexer interface {
ConnectBlock(block *Block, txids map[string][]string) error ConnectBlock(block *Block, txids map[string][]string) error
DisconnectBlock(block *Block, txids map[string][]string) error DisconnectBlock(block *Block, txids map[string][]string) error
} }
@ -81,7 +85,7 @@ func main() {
address := *queryAddress address := *queryAddress
if address != "" { if address != "" {
if err = db.GetAddressTransactions(address, height, until, printResult); err != nil { if err = db.GetTransactions(address, height, until, printResult); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} else { } else {
@ -99,15 +103,15 @@ func printResult(txids []string) error {
return nil return nil
} }
func (b *Block) CollectBlockAddresses(o OutpointAddressOracle) (map[string][]string, error) { func (b *Block) GetAllAddresses(outpoints Outpoints) (map[string][]string, error) {
addrs := make(map[string][]string, 0) addrs := make(map[string][]string, 0)
for _, tx := range b.Txs { for _, tx := range b.Txs {
voutAddrs, err := tx.CollectAddresses(o) ta, err := b.GetTxAddresses(outpoints, tx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, addr := range voutAddrs { for _, addr := range ta {
addrs[addr] = append(addrs[addr], tx.Txid) addrs[addr] = append(addrs[addr], tx.Txid)
} }
} }
@ -115,69 +119,62 @@ func (b *Block) CollectBlockAddresses(o OutpointAddressOracle) (map[string][]str
return addrs, nil return addrs, nil
} }
var ( func (b *Block) GetTxAddresses(outpoints Outpoints, tx *Tx) ([]string, error) {
ErrTxNotFound = errors.New("transaction not found") seen := make(map[string]struct{}) // Only unique values.
)
func (b *Block) GetOutpointAddresses(txid string, vout uint32) ([]string, error) { // Process outputs.
for _, o := range tx.Vout {
for _, a := range o.ScriptPubKey.Addresses {
seen[a] = struct{}{}
}
}
// Process inputs. For each input, we need to take a look to the
// outpoint index.
for _, i := range tx.Vin {
if i.Coinbase != "" {
continue
}
// Lookup output in in the outpoint index. In case it's not
// found, take a look in this block.
va, err := outpoints.GetAddresses(i.Txid, i.Vout)
if err == ErrTxNotFound {
va, err = b.GetAddresses(i.Txid, i.Vout)
}
if err != nil {
return nil, err
}
for _, a := range va {
seen[a] = struct{}{}
}
}
// Convert the result set into a slice.
addrs := make([]string, len(seen))
i := 0
for a := range seen {
addrs[i] = a
i++
}
return addrs, nil
}
func (b *Block) GetAddresses(txid string, vout uint32) ([]string, error) {
// TODO: Lookup transaction in constant time.
for _, tx := range b.Txs { for _, tx := range b.Txs {
if tx.Txid == txid { if tx.Txid == txid {
return tx.Vout[vout].ScriptPubKey.Addresses, nil return tx.Vout[vout].ScriptPubKey.Addresses, nil
} }
} }
return nil, ErrTxNotFound return nil, ErrTxNotFound
} }
type JoinedOutpointAddressOracle struct {
outpoints OutpointAddressOracle
block *Block
}
func (o *JoinedOutpointAddressOracle) GetOutpointAddresses(txid string, vout uint32) ([]string, error) {
addrs, err := o.block.GetOutpointAddresses(txid, vout)
if err == nil {
return addrs, err
}
return o.outpoints.GetOutpointAddresses(txid, vout)
}
func (tx *Tx) CollectAddresses(o OutpointAddressOracle) ([]string, error) {
addrs := make([]string, 0)
seen := make(map[string]struct{})
for _, vout := range tx.Vout {
for _, addr := range vout.ScriptPubKey.Addresses {
if _, found := seen[addr]; !found {
addrs = append(addrs, addr)
seen[addr] = struct{}{}
}
}
}
for _, vin := range tx.Vin {
if vin.Coinbase != "" {
continue
}
vinAddrs, err := o.GetOutpointAddresses(vin.Txid, vin.Vout)
if err != nil {
return nil, err
}
for _, addr := range vinAddrs {
if _, found := seen[addr]; !found {
addrs = append(addrs, addr)
seen[addr] = struct{}{}
}
}
}
return addrs, nil
}
func indexBlocks( func indexBlocks(
blocks BlockOracle, blocks Blocks,
outpoints OutpointAddressOracle, outpoints Outpoints,
index BlockIndex, index Indexer,
lower uint32, lower uint32,
higher uint32, higher uint32,
) error { ) error {
@ -185,14 +182,11 @@ func indexBlocks(
go getBlocks(lower, higher, blocks, bch) go getBlocks(lower, higher, blocks, bch)
blouts := JoinedOutpointAddressOracle{outpoints: outpoints}
for res := range bch { for res := range bch {
if res.err != nil { if res.err != nil {
return res.err return res.err
} }
blouts.block = res.block addrs, err := res.block.GetAllAddresses(outpoints)
addrs, err := res.block.CollectBlockAddresses(&blouts)
if err != nil { if err != nil {
return err return err
} }
@ -208,7 +202,7 @@ type blockResult struct {
err error err error
} }
func getBlocks(lower uint32, higher uint32, blocks BlockOracle, results chan<- blockResult) { func getBlocks(lower uint32, higher uint32, blocks Blocks, results chan<- blockResult) {
defer close(results) defer close(results)
height := lower height := lower

View File

@ -55,7 +55,7 @@ func (d *RocksDB) Close() error {
return nil return nil
} }
func (d *RocksDB) GetOutpointAddresses(txid string, vout uint32) ([]string, error) { func (d *RocksDB) GetAddresses(txid string, vout uint32) ([]string, error) {
log.Printf("rocksdb: outpoint get %s:%d", txid, vout) log.Printf("rocksdb: outpoint get %s:%d", txid, vout)
k, err := packOutpointKey(txid, vout) k, err := packOutpointKey(txid, vout)
if err != nil { if err != nil {
@ -69,7 +69,7 @@ func (d *RocksDB) GetOutpointAddresses(txid string, vout uint32) ([]string, erro
return unpackOutpointValue(v.Data()) return unpackOutpointValue(v.Data())
} }
func (d *RocksDB) GetAddressTransactions(address string, lower uint32, higher uint32, fn func(txids []string) error) (err error) { func (d *RocksDB) GetTransactions(address string, lower uint32, higher uint32, fn func(txids []string) error) (err error) {
log.Printf("rocksdb: address get %d:%d %s", lower, higher, address) log.Printf("rocksdb: address get %d:%d %s", lower, higher, address)
kstart, err := packAddressKey(lower, address) kstart, err := packAddressKey(lower, address)