Address format is set in configuration instead of RPC options

pull/7/head
Jakub Matys 2018-05-29 14:15:27 +02:00
parent 9147781772
commit ea3cfd2d6a
9 changed files with 109 additions and 116 deletions

View File

@ -3,7 +3,6 @@ package bchain
import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/gogo/protobuf/proto"
"github.com/juju/errors"
@ -215,15 +214,12 @@ func (a baseAddress) String() string {
return a.addr
}
func (a baseAddress) EncodeAddress(format AddressFormat) (string, error) {
if format != DefaultAddress {
return "", fmt.Errorf("Unknown address format: %d", format)
}
func (a baseAddress) EncodeAddress() (string, error) {
return a.addr, nil
}
func (a baseAddress) AreEqual(addr string) (bool, error) {
ea, err := a.EncodeAddress(0)
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
@ -231,12 +227,12 @@ func (a baseAddress) AreEqual(addr string) (bool, error) {
}
func (a baseAddress) InSlice(addrs []string) (bool, error) {
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
for _, addr := range addrs {
eq, err := a.AreEqual(addr)
if err != nil {
return false, err
}
if eq {
if ea == addr {
return true, nil
}
}

View File

@ -12,23 +12,45 @@ import (
"github.com/cpacia/bchutil"
)
type AddressFormat = uint8
const (
Legacy AddressFormat = iota
CashAddr
)
var prefixes = []string{"bitcoincash", "bchtest", "bchreg"}
// BCashParser handle
type BCashParser struct {
*btc.BitcoinParser
AddressFormat AddressFormat
}
// NewBCashParser returns new BCashParser instance
func NewBCashParser(params *chaincfg.Params, c *btc.Configuration) *BCashParser {
var format AddressFormat
switch c.AddressFormat {
case "":
fallthrough
case "cashaddr":
format = CashAddr
case "legacy":
format = Legacy
default:
// XXX
e := fmt.Errorf("Unknown address format: %s", c.AddressFormat)
panic(e)
}
return &BCashParser{
BitcoinParser: &btc.BitcoinParser{
BaseParser: &bchain.BaseParser{
AddressFactory: func(addr string) (bchain.Address, error) { return newBCashAddress(addr, params) },
AddressFactory: func(addr string) (bchain.Address, error) { return newBCashAddress(addr, params, format) },
BlockAddressesToKeep: c.BlockAddressesToKeep,
},
Params: params,
},
AddressFormat: format,
}
}
@ -103,7 +125,7 @@ func (p *BCashParser) UnpackTx(buf []byte) (tx *bchain.Tx, height uint32, err er
for i, vout := range tx.Vout {
if len(vout.ScriptPubKey.Addresses) == 1 {
a, err := newBCashAddress(vout.ScriptPubKey.Addresses[0], p.Params)
a, err := newBCashAddress(vout.ScriptPubKey.Addresses[0], p.Params, p.AddressFormat)
if err != nil {
return nil, 0, err
}
@ -115,11 +137,12 @@ func (p *BCashParser) UnpackTx(buf []byte) (tx *bchain.Tx, height uint32, err er
}
type bcashAddress struct {
addr btcutil.Address
net *chaincfg.Params
addr btcutil.Address
net *chaincfg.Params
format AddressFormat
}
func newBCashAddress(addr string, net *chaincfg.Params) (*bcashAddress, error) {
func newBCashAddress(addr string, net *chaincfg.Params, format AddressFormat) (*bcashAddress, error) {
var (
da btcutil.Address
err error
@ -148,18 +171,23 @@ func newBCashAddress(addr string, net *chaincfg.Params) (*bcashAddress, error) {
return nil, err
}
}
return &bcashAddress{addr: da, net: net}, nil
switch format {
case Legacy, CashAddr:
default:
return nil, fmt.Errorf("Unknown address format: %d", format)
}
return &bcashAddress{addr: da, net: net, format: format}, nil
}
func (a *bcashAddress) String() string {
return a.addr.String()
}
func (a *bcashAddress) EncodeAddress(format bchain.AddressFormat) (string, error) {
switch format {
case bchain.DefaultAddress:
func (a *bcashAddress) EncodeAddress() (string, error) {
switch a.format {
case Legacy:
return a.String(), nil
case bchain.BCashAddress:
case CashAddr:
var (
ca btcutil.Address
err error
@ -178,18 +206,12 @@ func (a *bcashAddress) EncodeAddress(format bchain.AddressFormat) (string, error
return ca.String(), nil
default:
return "", fmt.Errorf("Unknown address format: %d", format)
return "", fmt.Errorf("Unknown address format: %d", a.format)
}
}
func (a *bcashAddress) AreEqual(addr string) (bool, error) {
var format bchain.AddressFormat
if isCashAddr(addr) {
format = bchain.BCashAddress
} else {
format = bchain.DefaultAddress
}
ea, err := a.EncodeAddress(format)
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
@ -197,12 +219,12 @@ func (a *bcashAddress) AreEqual(addr string) (bool, error) {
}
func (a *bcashAddress) InSlice(addrs []string) (bool, error) {
ea, err := a.EncodeAddress()
if err != nil {
return false, err
}
for _, addr := range addrs {
eq, err := a.AreEqual(addr)
if err != nil {
return false, err
}
if eq {
if ea == addr {
return true, nil
}
}

View File

@ -10,12 +10,12 @@ import (
)
func TestBcashAddressEncodeAddress(t *testing.T) {
addr, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"))
addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy)
if err != nil {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr.EncodeAddress(bchain.DefaultAddress)
got1, err := addr1.EncodeAddress()
if err != nil {
t.Errorf("EncodeAddress() error = %v", err)
return
@ -23,7 +23,12 @@ func TestBcashAddressEncodeAddress(t *testing.T) {
if got1 != "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji" {
t.Errorf("EncodeAddress() got1 = %v, want %v", got1, "13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji")
}
got2, err := addr.EncodeAddress(bchain.BCashAddress)
addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr)
if err != nil {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got2, err := addr2.EncodeAddress()
if err != nil {
t.Errorf("EncodeAddress() error = %v", err)
return
@ -34,12 +39,17 @@ func TestBcashAddressEncodeAddress(t *testing.T) {
}
func TestBcashAddressAreEqual(t *testing.T) {
addr, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"))
addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy)
if err != nil {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr.AreEqual("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji")
addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr)
if err != nil {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr1.AreEqual("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
@ -47,7 +57,7 @@ func TestBcashAddressAreEqual(t *testing.T) {
if got1 != true {
t.Errorf("AreEqual() got1 = %v, want %v", got1, true)
}
got2, err := addr.AreEqual("bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf")
got2, err := addr2.AreEqual("bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
@ -55,7 +65,7 @@ func TestBcashAddressAreEqual(t *testing.T) {
if got2 != true {
t.Errorf("AreEqual() got2 = %v, want %v", got2, true)
}
got3, err := addr.AreEqual("1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w")
got3, err := addr1.AreEqual("1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
@ -63,7 +73,7 @@ func TestBcashAddressAreEqual(t *testing.T) {
if got3 != false {
t.Errorf("AreEqual() got3 = %v, want %v", got3, false)
}
got4, err := addr.AreEqual("bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch")
got4, err := addr2.AreEqual("bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch")
if err != nil {
t.Errorf("AreEqual() error = %v", err)
return
@ -74,12 +84,17 @@ func TestBcashAddressAreEqual(t *testing.T) {
}
func TestBcashAddressInSlice(t *testing.T) {
addr, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"))
addr1, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), Legacy)
if err != nil {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr.InSlice([]string{"13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", "bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch"})
addr2, err := newBCashAddress("13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", GetChainParams("main"), CashAddr)
if err != nil {
t.Errorf("newBCashAddress() error = %v", err)
return
}
got1, err := addr1.InSlice([]string{"13zMwGC5bxRn9ckJ1mgxf7UR8qbbNe2iji", "1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
@ -87,7 +102,7 @@ func TestBcashAddressInSlice(t *testing.T) {
if got1 != true {
t.Errorf("InSlice() got1 = %v, want %v", got1, true)
}
got2, err := addr.InSlice([]string{"1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w", "bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf"})
got2, err := addr2.InSlice([]string{"bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch", "bitcoincash:qqsvjuqqwgyzvz7zz9xcvxent0ul2xjs6y4d9qvsrf"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
@ -95,7 +110,7 @@ func TestBcashAddressInSlice(t *testing.T) {
if got2 != true {
t.Errorf("InSlice() got2 = %v, want %v", got2, true)
}
got3, err := addr.InSlice([]string{"1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w", "1E6Np6dUPYpBSdLMLuwBF8sRQ3cngdaRRY"})
got3, err := addr1.InSlice([]string{"1HoKgKQh7ZNomWURmS9Tk3z8JM2MWm7S1w", "1E6Np6dUPYpBSdLMLuwBF8sRQ3cngdaRRY"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
@ -103,7 +118,7 @@ func TestBcashAddressInSlice(t *testing.T) {
if got3 != false {
t.Errorf("InSlice() got3 = %v, want %v", got3, false)
}
got4, err := addr.InSlice([]string{"bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch", "bitcoincash:qz8emmpenqgeg7et8xsz8prvhy6cqcalyyjcamt7e9"})
got4, err := addr2.InSlice([]string{"bitcoincash:qzuyf0gpqj7q5wfck3nyghhklju7r0k3ksmq6d0vch", "bitcoincash:qz8emmpenqgeg7et8xsz8prvhy6cqcalyyjcamt7e9"})
if err != nil {
t.Errorf("InSlice() error = %v", err)
return
@ -149,12 +164,12 @@ func init() {
addr1, addr2, addr3 bchain.Address
err error
)
addr1, err = newBCashAddress("3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", GetChainParams("main"))
addr1, err = newBCashAddress("3AZKvpKhSh1o8t1QrX3UeXG9d2BhCRnbcK", GetChainParams("main"), Legacy)
if err == nil {
addr2, err = newBCashAddress("2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", GetChainParams("test"))
addr2, err = newBCashAddress("2NByHN6A8QYkBATzxf4pRGbCSHD5CEN2TRu", GetChainParams("test"), Legacy)
}
if err == nil {
addr3, err = newBCashAddress("2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", GetChainParams("test"))
addr3, err = newBCashAddress("2MvZguYaGjM7JihBgNqgLF2Ca2Enb76Hj9D", GetChainParams("test"), Legacy)
}
if err != nil {
panic(err)
@ -248,7 +263,7 @@ func Test_UnpackTx(t *testing.T) {
name: "btc-1",
args: args{
packedTx: testTxPacked1,
parser: NewBCashParser(GetChainParams("main"), &btc.Configuration{}),
parser: NewBCashParser(GetChainParams("main"), &btc.Configuration{AddressFormat: "legacy"}),
},
want: &testTx1,
want1: 123456,
@ -258,7 +273,7 @@ func Test_UnpackTx(t *testing.T) {
name: "testnet-1",
args: args{
packedTx: testTxPacked2,
parser: NewBCashParser(GetChainParams("test"), &btc.Configuration{}),
parser: NewBCashParser(GetChainParams("test"), &btc.Configuration{AddressFormat: "legacy"}),
},
want: &testTx2,
want1: 510234,

View File

@ -44,6 +44,7 @@ type Configuration struct {
BlockAddressesToKeep int `json:"blockAddressesToKeep"`
MempoolWorkers int `json:"mempoolWorkers"`
MempoolSubWorkers int `json:"mempoolSubWorkers"`
AddressFormat string `json:"addressFormat"`
}
// NewBitcoinRPC returns new BitcoinRPC instance.

View File

@ -41,16 +41,9 @@ type ScriptPubKey struct {
Addresses []string `json:"addresses,omitempty"`
}
type AddressFormat = uint8
const (
DefaultAddress AddressFormat = iota
BCashAddress
)
type Address interface {
String() string
EncodeAddress(format AddressFormat) (string, error)
EncodeAddress() (string, error)
AreEqual(addr string) (bool, error)
InSlice(addrs []string) (bool, error)
}

View File

@ -8,5 +8,6 @@
"subversion": "/Bitcoin ABC:0.17.1/",
"mempoolWorkers": 8,
"mempoolSubWorkers": 2,
"blockAddressesToKeep": 300
"blockAddressesToKeep": 300,
"addressFormat": "legacy"
}

View File

@ -8,5 +8,6 @@
"subversion": "/Bitcoin ABC:0.17.1/",
"mempoolWorkers": 8,
"mempoolSubWorkers": 2,
"blockAddressesToKeep": 300
"blockAddressesToKeep": 300,
"addressFormat": "legacy"
}

View File

@ -208,16 +208,11 @@ func (s *SocketIoServer) apiBlockIndex(w http.ResponseWriter, r *http.Request) {
}
type addrOpts struct {
Start int `json:"start"`
End int `json:"end"`
QueryMempoolOnly bool `json:"queryMempoolOnly"`
From int `json:"from"`
To int `json:"to"`
AddressFormat uint8 `json:"addressFormat"`
}
type txOpts struct {
AddressFormat uint8 `json:"addressFormat"`
Start int `json:"start"`
End int `json:"end"`
QueryMempoolOnly bool `json:"queryMempoolOnly"`
From int `json:"from"`
To int `json:"to"`
}
var onMessageHandlers = map[string]func(*SocketIoServer, json.RawMessage) (interface{}, error){
@ -260,9 +255,9 @@ var onMessageHandlers = map[string]func(*SocketIoServer, json.RawMessage) (inter
return s.getInfo()
},
"getDetailedTransaction": func(s *SocketIoServer, params json.RawMessage) (rv interface{}, err error) {
txid, opts, err := unmarshalGetDetailedTransaction(params)
txid, err := unmarshalGetDetailedTransaction(params)
if err == nil {
rv, err = s.getDetailedTransaction(txid, opts)
rv, err = s.getDetailedTransaction(txid)
}
return
},
@ -483,7 +478,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
Script: &aoh,
}
if vout.Address != nil {
a, err := vout.Address.EncodeAddress(opts.AddressFormat)
a, err := vout.Address.EncodeAddress()
if err != nil {
return res, err
}
@ -693,13 +688,13 @@ func unmarshalStringParameter(params []byte) (s string, err error) {
return
}
func unmarshalGetDetailedTransaction(params []byte) (txid string, opts txOpts, err error) {
func unmarshalGetDetailedTransaction(params []byte) (txid string, err error) {
var p []json.RawMessage
err = json.Unmarshal(params, &p)
if err != nil {
return
}
if len(p) < 1 || len(p) > 2 {
if len(p) != 1 {
err = errors.New("incorrect number of parameters")
return
}
@ -707,9 +702,6 @@ func unmarshalGetDetailedTransaction(params []byte) (txid string, opts txOpts, e
if err != nil {
return
}
if len(p) > 1 {
err = json.Unmarshal(p[1], &opts)
}
return
}
@ -717,7 +709,7 @@ type resultGetDetailedTransaction struct {
Result resTx `json:"result"`
}
func (s *SocketIoServer) getDetailedTransaction(txid string, opts txOpts) (res resultGetDetailedTransaction, err error) {
func (s *SocketIoServer) getDetailedTransaction(txid string) (res resultGetDetailedTransaction, err error) {
bestheight, _, err := s.db.GetBestBlock()
if err != nil {
return
@ -743,7 +735,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string, opts txOpts) (res r
if len(otx.Vout) > int(vin.Vout) {
vout := otx.Vout[vin.Vout]
if vout.Address != nil {
a, err := vout.Address.EncodeAddress(opts.AddressFormat)
a, err := vout.Address.EncodeAddress()
if err != nil {
return res, err
}
@ -761,7 +753,7 @@ func (s *SocketIoServer) getDetailedTransaction(txid string, opts txOpts) (res r
Script: &aos,
}
if vout.Address != nil {
a, err := vout.Address.EncodeAddress(opts.AddressFormat)
a, err := vout.Address.EncodeAddress()
if err != nil {
return res, err
}

View File

@ -56,15 +56,14 @@
var addresses = document.getElementById('getAddressHistoryAddresses').value.split(",");
addresses = addresses.map(s => s.trim());
var mempool = document.getElementById("getAddressHistoryMempool").checked;
var format = document.getElementById("getAddressHistoryFormat").value;
lookupAddressHistories(addresses, 0, 5, mempool, 20000000, 0, format, function (result) {
lookupAddressHistories(addresses, 0, 5, mempool, 20000000, 0, function (result) {
console.log('getAddressHistory sent successfully');
console.log(result);
document.getElementById('getAddressHistoryResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
});
}
function lookupAddressHistories(addresses, from, to, mempool, start, end, format, f) {
function lookupAddressHistories(addresses, from, to, mempool, start, end, f) {
const method = 'getAddressHistory';
const opts = mempool ? {
start, // needed for older bitcores (so we don't load all history if bitcore-node < 3.1.3)
@ -81,7 +80,6 @@
...opts,
from,
to,
addressFormat: parseInt(format),
},
];
return socket.send({ method, params }, f);
@ -172,28 +170,18 @@
function getDetailedTransaction() {
var hash = document.getElementById('getDetailedTransactionHash').value.trim();
var format = document.getElementById("getDetailedTransactionFormat").value;
lookupDetailedTransaction(hash, format, function (result) {
lookupDetailedTransaction(hash, function (result) {
console.log('getDetailedTransaction sent successfully');
console.log(result);
document.getElementById('getDetailedTransactionResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
});
}
function lookupDetailedTransaction(hash, format, f) {
function lookupDetailedTransaction(hash, f) {
const method = 'getDetailedTransaction';
const af = parseInt(format)
var params = [
hash,
];
if (af !== 0) {
params = [
hash,
{
addressFormat: af,
},
];
}
return socket.send({ method, params }, f);
}
@ -302,14 +290,6 @@
<input type="checkbox" id="getAddressHistoryMempool">&nbsp;
<label>only mempool</label>
</div>
<div class="col-9"></div>
<div class="col form-inline">
<label>address format</label>&nbsp;
<select id="getAddressHistoryFormat" value="0">
<option value="0">default</option>
<option value="1">bitcoincash</option>
</select>
</div>
</div>
<div class="row">
<div class="col" id="getAddressHistoryResult">
@ -373,14 +353,6 @@
<input type="text" class="form-control" id="getDetailedTransactionHash" value="474e6795760ebe81cb4023dc227e5a0efe340e1771c89a0035276361ed733de7">
</div>
<div class="col"></div>
<div class="col-9"></div>
<div class="col form-inline">
<label>address format</label>&nbsp;
<select id="getDetailedTransactionFormat" value="0">
<option value="0">default</option>
<option value="1">bitcoincash</option>
</select>
</div>
</div>
<div class="row">
<div class="col" id="getDetailedTransactionResult">
@ -443,4 +415,4 @@
document.getElementById('serverAddress').value = window.location.protocol.replace("http", "ws") + "//" + window.location.host;
</script>
</html>
</html>