cb7c24141a
This commit implements a reimagining of the way the btcjson package functions based upon how the project has evolved and lessons learned while using it since it was first written. It therefore contains significant changes to the API. For now, it has been implemented in a v2 subdirectory to prevent breaking existing callers, but the ultimate goal is to update all callers to use the new version and then to replace the old API with the new one. This also removes the need for the btcws completely since those commands have been rolled in. The following is an overview of the changes and some reasoning behind why they were made: - The infrastructure has been completely changed to be reflection based instead of requiring thousands and thousands of lines of manual, and therefore error prone, marshal/unmarshal code - This makes it much easier to add new commands without making marshalling mistakes since it is simply a struct definition and a call to register that new struct (plus a trivial New<foo>Cmd function and tests, of course) - It also makes it much easier to gain a lot of information from simply looking at the struct definition which was previously not possible such as the order of the parameters, which parameters are required versus optional, and what the default values for optional parameters are - Each command now has usage flags associated with them that can be queried which are intended to allow classification of the commands such as for chain server and wallet server and websocket-only - The help infrastructure has been completely redone to provide automatic generation with caller provided description map and result types. This is in contrast to the previous method of providing the help directly which meant it would end up in the binary of anything that imported the package - Many of the structs have been renamed to use the terminology from the JSON-RPC specification: - RawCmd/Message is now only a single struct named Request to reflect the fact it is a JSON-RPC request - Error is now called RPCError to reflect the fact it is specifically an RPC error as opposed to many of the other errors that are possible - All RPC error codes except the standard JSON-RPC 2.0 errors have been converted from full structs to only codes since an audit of the codebase has shown that the messages are overridden the vast majority of the time with specifics (as they should be) and removing them also avoids the temptation to return non-specific, and therefore not as helpful, error messages - There is now an Error which provides a type assertable error with error codes so callers can better ascertain failure reasons programatically - The ID is no longer a part of the command and is instead specified at the time the command is marshalled into a JSON-RPC request. This aligns better with the way JSON-RPC functions since it is the caller who manages the ID that is sent with any given _request_, not the package - All <Foo>Cmd structs now treat non-pointers as required fields and pointers as optional fields - All New<Foo>Cmd functions now accept the exact number of parameters, with pointers to the appropriate type for optional parameters - This is preferrable to the old vararg syntax since it means the code will fail to compile if the optional arguments are changed now which helps prevent errors creep in over time from missed modifications to optional args - All of the connection related code has been completely eliminated since this package is not intended to used a client, rather it is intended to provide the infrastructure needed to marshal/unmarshal Bitcoin-specific JSON-RPC requests and replies from static types - The btcrpcclient package provides a robust client with connection management and higher-level types that in turn uses the primitives provided by this package - Even if the caller does not wish to use btcrpcclient for some reason, they should still be responsible for connection management since they might want to use any number of connection features which the package would not necessarily support - Synced a few of the commands that have added new optional fields that have since been added to Bitcoin Core - Includes all of the commands and notifications that were previously in btcws - Now provides 100% test coverage with parallel tests - The code is completely golint and go vet clean This has the side effect of addressing nearly everything in, and therefore closes #26. Also fixes #18 and closes #19.
338 lines
12 KiB
Go
338 lines
12 KiB
Go
// Copyright (c) 2014 Conformal Systems LLC.
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package btcjson
|
|
|
|
import "encoding/json"
|
|
|
|
// GetBlockVerboseResult models the data from the getblock command when the
|
|
// verbose flag is set. When the verbose flag is not set, getblock returns a
|
|
// hex-encoded string.
|
|
type GetBlockVerboseResult struct {
|
|
Hash string `json:"hash"`
|
|
Confirmations uint64 `json:"confirmations"`
|
|
Size int32 `json:"size"`
|
|
Height int64 `json:"height"`
|
|
Version int32 `json:"version"`
|
|
MerkleRoot string `json:"merkleroot"`
|
|
Tx []string `json:"tx,omitempty"`
|
|
RawTx []TxRawResult `json:"rawtx,omitempty"`
|
|
Time int64 `json:"time"`
|
|
Nonce uint32 `json:"nonce"`
|
|
Bits string `json:"bits"`
|
|
Difficulty float64 `json:"difficulty"`
|
|
PreviousHash string `json:"previousblockhash"`
|
|
NextHash string `json:"nextblockhash"`
|
|
}
|
|
|
|
// CreateMultiSigResult models the data returned from the createmultisig
|
|
// command.
|
|
type CreateMultiSigResult struct {
|
|
Address string `json:"address"`
|
|
RedeemScript string `json:"redeemScript"`
|
|
}
|
|
|
|
// DecodeScriptResult models the data returned from the decodescript command.
|
|
type DecodeScriptResult struct {
|
|
Asm string `json:"asm"`
|
|
ReqSigs int32 `json:"reqSigs,omitempty"`
|
|
Type string `json:"type"`
|
|
Addresses []string `json:"addresses,omitempty"`
|
|
P2sh string `json:"p2sh"`
|
|
}
|
|
|
|
// GetAddedNodeInfoResultAddr models the data of the addresses portion of the
|
|
// getaddednodeinfo command.
|
|
type GetAddedNodeInfoResultAddr struct {
|
|
Address string `json:"address"`
|
|
Connected string `json:"connected"`
|
|
}
|
|
|
|
// GetAddedNodeInfoResult models the data from the getaddednodeinfo command.
|
|
type GetAddedNodeInfoResult struct {
|
|
AddedNode string `json:"addednode"`
|
|
Connected *bool `json:"connected,omitempty"`
|
|
Addresses *[]GetAddedNodeInfoResultAddr `json:"addresses,omitempty"`
|
|
}
|
|
|
|
// GetBlockChainInfoResult models the data returned from the getblockchaininfo
|
|
// command.
|
|
type GetBlockChainInfoResult struct {
|
|
Chain string `json:"chain"`
|
|
Blocks int32 `json:"blocks"`
|
|
Headers int32 `json:"headers"`
|
|
BestBlockHash string `json:"bestblockhash"`
|
|
Difficulty float64 `json:"difficulty"`
|
|
VerificationProgress float64 `json:"verificationprogress"`
|
|
ChainWork string `json:"chainwork"`
|
|
}
|
|
|
|
// GetBlockTemplateResultTx models the transactions field of the
|
|
// getblocktemplate command.
|
|
type GetBlockTemplateResultTx struct {
|
|
Data string `json:"data"`
|
|
Hash string `json:"hash"`
|
|
Depends []int64 `json:"depends"`
|
|
Fee int64 `json:"fee"`
|
|
SigOps int64 `json:"sigops"`
|
|
}
|
|
|
|
// GetBlockTemplateResultAux models the coinbaseaux field of the
|
|
// getblocktemplate command.
|
|
type GetBlockTemplateResultAux struct {
|
|
Flags string `json:"flags"`
|
|
}
|
|
|
|
// GetBlockTemplateResult models the data returned from the getblocktemplate
|
|
// command.
|
|
type GetBlockTemplateResult struct {
|
|
// Base fields from BIP 0022. CoinbaseAux is optional. One of
|
|
// CoinbaseTxn or CoinbaseValue must be specified, but not both.
|
|
Bits string `json:"bits"`
|
|
CurTime int64 `json:"curtime"`
|
|
Height int64 `json:"height"`
|
|
PreviousHash string `json:"previousblockhash"`
|
|
SigOpLimit int64 `json:"sigoplimit,omitempty"`
|
|
SizeLimit int64 `json:"sizelimit,omitempty"`
|
|
Transactions []GetBlockTemplateResultTx `json:"transactions"`
|
|
Version int32 `json:"version"`
|
|
CoinbaseAux *GetBlockTemplateResultAux `json:"coinbaseaux,omitempty"`
|
|
CoinbaseTxn *GetBlockTemplateResultTx `json:"coinbasetxn,omitempty"`
|
|
CoinbaseValue *int64 `json:"coinbasevalue,omitempty"`
|
|
WorkID string `json:"workid,omitempty"`
|
|
|
|
// Optional long polling from BIP 0022.
|
|
LongPollID string `json:"longpollid,omitempty"`
|
|
LongPollURI string `json:"longpolluri,omitempty"`
|
|
SubmitOld *bool `json:"submitold,omitempty"`
|
|
|
|
// Basic pool extension from BIP 0023.
|
|
Target string `json:"target,omitempty"`
|
|
Expires int64 `json:"expires,omitempty"`
|
|
|
|
// Mutations from BIP 0023.
|
|
MaxTime int64 `json:"maxtime,omitempty"`
|
|
MinTime int64 `json:"mintime,omitempty"`
|
|
Mutable []string `json:"mutable,omitempty"`
|
|
NonceRange string `json:"noncerange,omitempty"`
|
|
|
|
// Block proposal from BIP 0023.
|
|
Capabilities []string `json:"capabilities,omitempty"`
|
|
RejectReasion string `json:"reject-reason,omitempty"`
|
|
}
|
|
|
|
// GetNetworkInfoResult models the data returned from the getnetworkinfo
|
|
// command.
|
|
type GetNetworkInfoResult struct {
|
|
Version int32 `json:"version"`
|
|
ProtocolVersion int32 `json:"protocolversion"`
|
|
TimeOffset int64 `json:"timeoffset"`
|
|
Connections int32 `json:"connections"`
|
|
Networks []NetworksResult `json:"networks"`
|
|
RelayFee float64 `json:"relayfee"`
|
|
LocalAddresses []LocalAddressesResult `json:"localaddresses"`
|
|
}
|
|
|
|
// GetPeerInfoResult models the data returned from the getpeerinfo command.
|
|
type GetPeerInfoResult struct {
|
|
Addr string `json:"addr"`
|
|
AddrLocal string `json:"addrlocal,omitempty"`
|
|
Services string `json:"services"`
|
|
LastSend int64 `json:"lastsend"`
|
|
LastRecv int64 `json:"lastrecv"`
|
|
BytesSent uint64 `json:"bytessent"`
|
|
BytesRecv uint64 `json:"bytesrecv"`
|
|
PingTime float64 `json:"pingtime"`
|
|
PingWait float64 `json:"pingwait,omitempty"`
|
|
ConnTime int64 `json:"conntime"`
|
|
Version uint32 `json:"version"`
|
|
SubVer string `json:"subver"`
|
|
Inbound bool `json:"inbound"`
|
|
StartingHeight int32 `json:"startingheight"`
|
|
CurrentHeight int32 `json:"currentheight,omitempty"`
|
|
BanScore int32 `json:"banscore"`
|
|
SyncNode bool `json:"syncnode"`
|
|
}
|
|
|
|
// GetRawMempoolVerboseResult models the data returned from the getrawmempool
|
|
// command when the verbose flag is set. When the verbose flag is not set,
|
|
// getrawmempool returns an array of transaction hashes.
|
|
type GetRawMempoolVerboseResult struct {
|
|
Size int32 `json:"size"`
|
|
Fee float64 `json:"fee"`
|
|
Time int64 `json:"time"`
|
|
Height int64 `json:"height"`
|
|
StartingPriority float64 `json:"startingpriority"`
|
|
CurrentPriority float64 `json:"currentpriority"`
|
|
Depends []string `json:"depends"`
|
|
}
|
|
|
|
// ScriptPubKeyResult models the scriptPubKey data of a tx script. It is
|
|
// defined separately since it is used by multiple commands.
|
|
type ScriptPubKeyResult struct {
|
|
Asm string `json:"asm"`
|
|
Hex string `json:"hex,omitempty"`
|
|
ReqSigs int32 `json:"reqSigs,omitempty"`
|
|
Type string `json:"type"`
|
|
Addresses []string `json:"addresses,omitempty"`
|
|
}
|
|
|
|
// GetTxOutResult models the data from the gettxout command.
|
|
type GetTxOutResult struct {
|
|
BestBlock string `json:"bestblock"`
|
|
Confirmations int64 `json:"confirmations"`
|
|
Value float64 `json:"value"`
|
|
ScriptPubKey ScriptPubKeyResult `json:"scriptPubKey"`
|
|
Version int32 `json:"version"`
|
|
Coinbase bool `json:"coinbase"`
|
|
}
|
|
|
|
// GetNetTotalsResult models the data returned from the getnettotals command.
|
|
type GetNetTotalsResult struct {
|
|
TotalBytesRecv uint64 `json:"totalbytesrecv"`
|
|
TotalBytesSent uint64 `json:"totalbytessent"`
|
|
TimeMillis int64 `json:"timemillis"`
|
|
}
|
|
|
|
// ScriptSig models a signature script. It is defined seperately since it only
|
|
// applies to non-coinbase. Therefore the field in the Vin structure needs
|
|
// to be a pointer.
|
|
type ScriptSig struct {
|
|
Asm string `json:"asm"`
|
|
Hex string `json:"hex"`
|
|
}
|
|
|
|
// Vin models parts of the tx data. It is defined seperately since
|
|
// getrawtransaction, decoderawtransaction, and searchrawtransaction use the
|
|
// same structure.
|
|
type Vin struct {
|
|
Coinbase string `json:"coinbase"`
|
|
Txid string `json:"txid"`
|
|
Vout uint32 `json:"vout"`
|
|
ScriptSig *ScriptSig `json:"scriptSig"`
|
|
Sequence uint32 `json:"sequence"`
|
|
}
|
|
|
|
// IsCoinBase returns a bool to show if a Vin is a Coinbase one or not.
|
|
func (v *Vin) IsCoinBase() bool {
|
|
return len(v.Coinbase) > 0
|
|
}
|
|
|
|
// MarshalJSON provides a custom Marshal method for Vin.
|
|
func (v *Vin) MarshalJSON() ([]byte, error) {
|
|
if v.IsCoinBase() {
|
|
coinbaseStruct := struct {
|
|
Coinbase string `json:"coinbase"`
|
|
Sequence uint32 `json:"sequence"`
|
|
}{
|
|
Coinbase: v.Coinbase,
|
|
Sequence: v.Sequence,
|
|
}
|
|
return json.Marshal(coinbaseStruct)
|
|
}
|
|
|
|
txStruct := struct {
|
|
Txid string `json:"txid"`
|
|
Vout uint32 `json:"vout"`
|
|
ScriptSig *ScriptSig `json:"scriptSig"`
|
|
Sequence uint32 `json:"sequence"`
|
|
}{
|
|
Txid: v.Txid,
|
|
Vout: v.Vout,
|
|
ScriptSig: v.ScriptSig,
|
|
Sequence: v.Sequence,
|
|
}
|
|
return json.Marshal(txStruct)
|
|
}
|
|
|
|
// Vout models parts of the tx data. It is defined seperately since both
|
|
// getrawtransaction and decoderawtransaction use the same structure.
|
|
type Vout struct {
|
|
Value float64 `json:"value"`
|
|
N uint32 `json:"n"`
|
|
ScriptPubKey ScriptPubKeyResult `json:"scriptPubKey"`
|
|
}
|
|
|
|
// GetMiningInfoResult models the data from the getmininginfo command.
|
|
type GetMiningInfoResult struct {
|
|
Blocks int64 `json:"blocks"`
|
|
CurrentBlockSize uint64 `json:"currentblocksize"`
|
|
CurrentBlockTx uint64 `json:"currentblocktx"`
|
|
Difficulty float64 `json:"difficulty"`
|
|
Errors string `json:"errors"`
|
|
Generate bool `json:"generate"`
|
|
GenProcLimit int32 `json:"genproclimit"`
|
|
HashesPerSec int64 `json:"hashespersec"`
|
|
NetworkHashPS int64 `json:"networkhashps"`
|
|
PooledTx uint64 `json:"pooledtx"`
|
|
TestNet bool `json:"testnet"`
|
|
}
|
|
|
|
// GetWorkResult models the data from the getwork command.
|
|
type GetWorkResult struct {
|
|
Data string `json:"data"`
|
|
Hash1 string `json:"hash1"`
|
|
Midstate string `json:"midstate"`
|
|
Target string `json:"target"`
|
|
}
|
|
|
|
// InfoChainResult models the data returned by the chain server getinfo command.
|
|
type InfoChainResult struct {
|
|
Version int32 `json:"version"`
|
|
ProtocolVersion int32 `json:"protocolversion"`
|
|
Blocks int32 `json:"blocks"`
|
|
TimeOffset int64 `json:"timeoffset"`
|
|
Connections int32 `json:"connections"`
|
|
Proxy string `json:"proxy"`
|
|
Difficulty float64 `json:"difficulty"`
|
|
TestNet bool `json:"testnet"`
|
|
RelayFee float64 `json:"relayfee"`
|
|
}
|
|
|
|
// LocalAddressesResult models the localaddresses data from the getnetworkinfo
|
|
// command.
|
|
type LocalAddressesResult struct {
|
|
Address string `json:"address"`
|
|
Port uint16 `json:"port"`
|
|
Score int32 `json:"score"`
|
|
}
|
|
|
|
// NetworksResult models the networks data from the getnetworkinfo command.
|
|
type NetworksResult struct {
|
|
Name string `json:"name"`
|
|
Limited bool `json:"limited"`
|
|
Reachable bool `json:"reachable"`
|
|
Proxy string `json:"proxy"`
|
|
}
|
|
|
|
// TxRawResult models the data from the getrawtransaction and
|
|
// searchrawtransaction commands.
|
|
type TxRawResult struct {
|
|
Hex string `json:"hex"`
|
|
Txid string `json:"txid"`
|
|
Version int32 `json:"version"`
|
|
LockTime uint32 `json:"locktime"`
|
|
Vin []Vin `json:"vin"`
|
|
Vout []Vout `json:"vout"`
|
|
BlockHash string `json:"blockhash,omitempty"`
|
|
Confirmations uint64 `json:"confirmations"`
|
|
Time int64 `json:"time,omitempty"`
|
|
Blocktime int64 `json:"blocktime,omitempty"`
|
|
}
|
|
|
|
// TxRawDecodeResult models the data from the decoderawtransaction command.
|
|
type TxRawDecodeResult struct {
|
|
Txid string `json:"txid"`
|
|
Version int32 `json:"version"`
|
|
Locktime uint32 `json:"locktime"`
|
|
Vin []Vin `json:"vin"`
|
|
Vout []Vout `json:"vout"`
|
|
}
|
|
|
|
// ValidateAddressChainResult models the data returned by the chain server
|
|
// validateaddress command.
|
|
type ValidateAddressChainResult struct {
|
|
IsValid bool `json:"isvalid"`
|
|
Address string `json:"address,omitempty"`
|
|
}
|