Add coinbase flag (boolean) to UTXO response #236

pull/244/head
Martin Boehm 2019-07-23 12:52:18 +02:00
parent 45f5d115d6
commit 39f2c73f3e
7 changed files with 60 additions and 12 deletions

View File

@ -266,6 +266,7 @@ type Utxo struct {
Address string `json:"address,omitempty"`
Path string `json:"path,omitempty"`
Locktime uint32 `json:"lockTime,omitempty"`
Coinbase bool `json:"coinbase,omitempty"`
}
// Utxos is array of Utxo

View File

@ -843,11 +843,16 @@ func (w *Worker) getAddrDescUtxo(addrDesc bchain.AddressDescriptor, ba *db.AddrB
// report only outpoints that are not spent in mempool
_, e := spentInMempool[bchainTx.Txid+strconv.Itoa(i)]
if !e {
coinbase := false
if len(bchainTx.Vin) == 1 && len(bchainTx.Vin[0].Coinbase) > 0 {
coinbase = true
}
r = append(r, Utxo{
Txid: bchainTx.Txid,
Vout: int32(i),
AmountSat: (*Amount)(&vout.ValueSat),
Locktime: bchainTx.LockTime,
Coinbase: coinbase,
})
}
}
@ -882,12 +887,25 @@ func (w *Worker) getAddrDescUtxo(addrDesc bchain.AddressDescriptor, ba *db.AddrB
}
_, e := spentInMempool[txid+strconv.Itoa(int(utxo.Vout))]
if !e {
confirmations := bestheight - int(utxo.Height) + 1
coinbase := false
// for performance reasons, check coinbase transactions only in minimim confirmantion range
if confirmations < w.chainParser.MinimumCoinbaseConfirmations() {
ta, err := w.db.GetTxAddresses(txid)
if err != nil {
return nil, err
}
if len(ta.Inputs) == 1 && len(ta.Inputs[0].AddrDesc) == 0 && IsZeroBigInt(&ta.Inputs[0].ValueSat) {
coinbase = true
}
}
r = append(r, Utxo{
Txid: txid,
Vout: utxo.Vout,
AmountSat: (*Amount)(&utxo.ValueSat),
Height: int(utxo.Height),
Confirmations: bestheight - int(utxo.Height) + 1,
Confirmations: confirmations,
Coinbase: coinbase,
})
}
checksum.Sub(&checksum, &utxo.ValueSat)

View File

@ -161,6 +161,11 @@ func (p *BaseParser) GetChainType() ChainType {
return ChainBitcoinType
}
// MinimumCoinbaseConfirmations returns minimum number of confirmations a coinbase transaction must have before it can be spent
func (p *BaseParser) MinimumCoinbaseConfirmations() int {
return 0
}
// PackTx packs transaction to byte array using protobuf
func (p *BaseParser) PackTx(tx *Tx, height uint32, blockTime int64) ([]byte, error) {
var err error

View File

@ -24,12 +24,13 @@ type OutputScriptToAddressesFunc func(script []byte) ([]string, bool, error)
// BitcoinParser handle
type BitcoinParser struct {
*bchain.BaseParser
Params *chaincfg.Params
OutputScriptToAddressesFunc OutputScriptToAddressesFunc
XPubMagic uint32
XPubMagicSegwitP2sh uint32
XPubMagicSegwitNative uint32
Slip44 uint32
Params *chaincfg.Params
OutputScriptToAddressesFunc OutputScriptToAddressesFunc
XPubMagic uint32
XPubMagicSegwitP2sh uint32
XPubMagicSegwitNative uint32
Slip44 uint32
minimumCoinbaseConfirmations int
}
// NewBitcoinParser returns new BitcoinParser instance
@ -39,11 +40,12 @@ func NewBitcoinParser(params *chaincfg.Params, c *Configuration) *BitcoinParser
BlockAddressesToKeep: c.BlockAddressesToKeep,
AmountDecimalPoint: 8,
},
Params: params,
XPubMagic: c.XPubMagic,
XPubMagicSegwitP2sh: c.XPubMagicSegwitP2sh,
XPubMagicSegwitNative: c.XPubMagicSegwitNative,
Slip44: c.Slip44,
Params: params,
XPubMagic: c.XPubMagic,
XPubMagicSegwitP2sh: c.XPubMagicSegwitP2sh,
XPubMagicSegwitNative: c.XPubMagicSegwitNative,
Slip44: c.Slip44,
minimumCoinbaseConfirmations: c.MinimumCoinbaseConfirmations,
}
p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
return p
@ -326,6 +328,11 @@ func (p *BitcoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
return tx, height, nil
}
// MinimumCoinbaseConfirmations returns minimum number of confirmations a coinbase transaction must have before it can be spent
func (p *BitcoinParser) MinimumCoinbaseConfirmations() int {
return p.minimumCoinbaseConfirmations
}
func (p *BitcoinParser) addrDescFromExtKey(extKey *hdkeychain.ExtendedKey) (bchain.AddressDescriptor, error) {
var a btcutil.Address
var err error

View File

@ -57,6 +57,7 @@ type Configuration struct {
Slip44 uint32 `json:"slip44,omitempty"`
AlternativeEstimateFee string `json:"alternativeEstimateFee,omitempty"`
AlternativeEstimateFeeParams string `json:"alternativeEstimateFeeParams,omitempty"`
MinimumCoinbaseConfirmations int `json:"minimumCoinbaseConfirmations,omitempty"`
}
// NewBitcoinRPC returns new BitcoinRPC instance.
@ -71,6 +72,10 @@ func NewBitcoinRPC(config json.RawMessage, pushHandler func(bchain.NotificationT
if c.BlockAddressesToKeep < 100 {
c.BlockAddressesToKeep = 100
}
// default MinimumCoinbaseConfirmations is 100
if c.MinimumCoinbaseConfirmations == 0 {
c.MinimumCoinbaseConfirmations = 100
}
// at least 1 mempool worker/subworker for synchronous mempool synchronization
if c.MempoolWorkers < 1 {
c.MempoolWorkers = 1

View File

@ -254,6 +254,8 @@ type BlockChainParser interface {
KeepBlockAddresses() int
// AmountDecimals returns number of decimal places in coin amounts
AmountDecimals() int
// MinimumCoinbaseConfirmations returns minimum number of confirmations a coinbase transaction must have before it can be spent
MinimumCoinbaseConfirmations() int
// AmountToDecimalString converts amount in big.Int to string with decimal point in the correct place
AmountToDecimalString(a *big.Int) string
// AmountToBigInt converts amount in json.Number (string) to big.Int

View File

@ -407,6 +407,8 @@ Returns array of unspent transaction outputs of address or xpub, applicable only
Unconfirmed utxos do not have field *height*, the field *confirmations* has value *0* and may contain field *lockTime*, if not zero.
Coinbase utxos do have field *coinbase* set to true, however due to performance reasons only up to minimum coinbase confirmations limit (100). After this limit, utxos are not detected as coinbase.
```
GET /api/v2/utxo/<address|xpub>[?confirmed=true]
```
@ -422,6 +424,14 @@ Response:
"confirmations": 0,
"lockTime": 2648100
},
{
"txid": "a79e396a32e10856c97b95f43da7e9d2b9a11d446f7638dbd75e5e7603128cac",
"vout": 1,
"value": "39748685",
"height": 2648043,
"confirmations": 47,
"coinbase": true
},
{
"txid": "de4f379fdc3ea9be063e60340461a014f372a018d70c3db35701654e7066b3ef",
"vout": 0,