Viacoin add support

indexv5
romanornr 2019-04-14 19:19:36 +02:00 committed by Martin Boehm
parent 32c77fe69a
commit e8a83ccfe2
9 changed files with 568 additions and 0 deletions

View File

@ -25,6 +25,7 @@ import (
"blockbook/bchain/coins/polis"
"blockbook/bchain/coins/qtum"
"blockbook/bchain/coins/vertcoin"
"blockbook/bchain/coins/viacoin"
"blockbook/bchain/coins/xzc"
"blockbook/bchain/coins/zec"
"blockbook/common"
@ -81,6 +82,7 @@ func init() {
BlockChainFactories["Flo"] = flo.NewFloRPC
BlockChainFactories["Bellcoin"] = bellcoin.NewBellcoinRPC
BlockChainFactories["Qtum"] = qtum.NewQtumRPC
BlockChainFactories["Viacoin"] = viacoin.NewViacoinRPC
BlockChainFactories["Qtum Testnet"] = qtum.NewQtumRPC
BlockChainFactories["NULS"] = nuls.NewNulsRPC
}

View File

@ -0,0 +1,101 @@
package viacoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"blockbook/bchain/coins/utils"
"bytes"
"github.com/martinboehm/btcd/wire"
"github.com/martinboehm/btcutil/chaincfg"
)
const (
MainnetMagic wire.BitcoinNet = 0xcbc6680f
RegtestMagic wire.BitcoinNet = 0x377b972d
)
var (
MainNetParams chaincfg.Params
RegtestParams chaincfg.Params
)
func init() {
MainNetParams = chaincfg.MainNetParams
MainNetParams.Net = MainnetMagic
// Mainnet address encoding magics
MainNetParams.PubKeyHashAddrID = []byte{71} // base58 prefix: v
MainNetParams.ScriptHashAddrID = []byte{33} // base68 prefix: E
MainNetParams.Bech32HRPSegwit = "via"
RegtestParams = chaincfg.RegressionNetParams
RegtestParams.Net = RegtestMagic
// Regtest address encoding magics
RegtestParams.PubKeyHashAddrID = []byte{111} // base58 prefix: m or n
RegtestParams.ScriptHashAddrID = []byte{196} // base58 prefix: 2
RegtestParams.Bech32HRPSegwit = "tvia"
err := chaincfg.Register(&MainNetParams)
if err == nil {
err = chaincfg.Register(&RegtestParams)
}
if err != nil {
panic(err)
}
}
// ViacoinParser handle
type ViacoinParser struct {
*btc.BitcoinParser
}
// NewViacoinParser returns new VertcoinParser instance
func NewViacoinParser(params *chaincfg.Params, c *btc.Configuration) *ViacoinParser {
return &ViacoinParser{BitcoinParser: btc.NewBitcoinParser(params, c)}
}
func GetChainParams(chain string) *chaincfg.Params {
switch chain {
case "regtest":
return &RegtestParams
default:
return &MainNetParams
}
}
// ParseBlock parses raw block to our Block struct
// it has special handling for Auxpow blocks that cannot be parsed by standard btc wire parse
func (p *ViacoinParser) ParseBlock(b []byte) (*bchain.Block, error) {
r := bytes.NewReader(b)
w := wire.MsgBlock{}
h := wire.BlockHeader{}
err := h.Deserialize(r)
if err != nil {
return nil, err
}
if (h.Version & utils.VersionAuxpow) != 0 {
if err = utils.SkipAuxpow(r); err != nil {
return nil, err
}
}
err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
if err != nil {
return nil, err
}
txs := make([]bchain.Tx, len(w.Transactions))
for ti, t := range w.Transactions {
txs[ti] = p.TxFromMsgTx(t, false)
}
return &bchain.Block{
BlockHeader: bchain.BlockHeader{
Size: len(b),
Time: h.Timestamp.Unix(),
},
Txs: txs,
}, nil
}

View File

@ -0,0 +1,207 @@
// +build unittest
package viacoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/hex"
"math/big"
"os"
"reflect"
"testing"
"github.com/martinboehm/btcutil/chaincfg"
)
func TestMain(m *testing.M) {
c := m.Run()
chaincfg.ResetParams()
os.Exit(c)
}
func Test_GetAddrDescFromAddress_Mainnet(t *testing.T) {
type args struct {
address string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "P2PKH1",
args: args{address: "VhyGT8kJU9x28dHwjf1jEDG8gMY8yhckDR"},
want: "76a91457757edd001d16528c7aa337b314a7bab303ee8088ac",
wantErr: false,
},
{
name: "P2PKH2",
args: args{address: "VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"},
want: "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac",
wantErr: false,
},
{
name: "P2SH1",
args: args{address: "EUtqKT17p1LdHTDyGL1b2WPJiUFidS6gVq"},
want: "a91480c7c8faece680bab1ae81a5969815a05b7565f087",
wantErr: false,
},
{
name: "P2SH2",
args: args{address: "EMdC3QPzx2MsJG56x2QbSR727dRM73B1rK"},
want: "a91431098c569891a8ff1fa11d1cbd3d46ca5e245c6b87",
wantErr: false,
},
{
name: "witness_v0_keyhash",
args: args{address: "via1q95qlu98cpj23xy6w9tdnfn65n5vkpkey99g6wl"},
want: "00142d01fe14f80c9513134e2adb34cf549d1960db24",
wantErr: false,
},
}
parser := NewViacoinParser(GetChainParams("main"), &btc.Configuration{})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parser.GetAddrDescFromAddress(tt.args.address)
if (err != nil) != tt.wantErr {
t.Errorf("GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr)
return
}
h := hex.EncodeToString(got)
if !reflect.DeepEqual(h, tt.want) {
t.Errorf("GetAddrDescFromAddress() = %v, want %v", h, tt.want)
}
})
}
}
var (
testTx1 bchain.Tx
testTxPacked1 = "004eb96d8bb3b6c6140200000001ddc431a8f5c4e74296de8a6bff796ece148b9bd6827a80ecde8671df41a51fc7000000006a47304402204f929a1e1e40bd352bbd5d3c5ae6c29740e5a8b29dd8c53a15d3eab29aecee7c02206a514e5e4561cfb9330d98f4a4fe1385af56d87eb1d3e1a379d7a50276788cfe0121034a9305644fbcb56d4fc0bc15959b917f7753ae8e581acc97f9cfe771ad1e8249feffffff0200ca9a3b000000001976a91456c7359ed52d61c1ca371d7dc136632148169c5e88acd0e8cc10000000001976a914112e29df5df4866e40ef98e0857036b275380fe088ac6ab94e00"
)
func init() {
testTx1 = bchain.Tx{
Hex: "0200000001ddc431a8f5c4e74296de8a6bff796ece148b9bd6827a80ecde8671df41a51fc7000000006a47304402204f929a1e1e40bd352bbd5d3c5ae6c29740e5a8b29dd8c53a15d3eab29aecee7c02206a514e5e4561cfb9330d98f4a4fe1385af56d87eb1d3e1a379d7a50276788cfe0121034a9305644fbcb56d4fc0bc15959b917f7753ae8e581acc97f9cfe771ad1e8249feffffff0200ca9a3b000000001976a91456c7359ed52d61c1ca371d7dc136632148169c5e88acd0e8cc10000000001976a914112e29df5df4866e40ef98e0857036b275380fe088ac6ab94e00",
Blocktime: 1530319242,
Txid: "d0284c75a389a07cc256e0bb913110d8d8059efd04daa8147ecf2fa0b3bdf6ff",
LockTime: 5159274,
Version: 2,
Vin: []bchain.Vin{
{
ScriptSig: bchain.ScriptSig{
Hex: "47304402204f929a1e1e40bd352bbd5d3c5ae6c29740e5a8b29dd8c53a15d3eab29aecee7c02206a514e5e4561cfb9330d98f4a4fe1385af56d87eb1d3e1a379d7a50276788cfe0121034a9305644fbcb56d4fc0bc15959b917f7753ae8e581acc97f9cfe771ad1e8249",
},
Txid: "c71fa541df7186deec807a82d69b8b14ce6e79ff6b8ade9642e7c4f5a831c4dd",
Vout: 0,
Sequence: 4294967294,
},
},
Vout: []bchain.Vout{
{
ValueSat: *big.NewInt(1000000000),
N: 0,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a91456c7359ed52d61c1ca371d7dc136632148169c5e88ac",
Addresses: []string{
"VhuffXKNA3j9hgp2JYGrj6uHQ6KUU6zNbS",
},
},
},
{
ValueSat: *big.NewInt(281864400),
N: 1,
ScriptPubKey: bchain.ScriptPubKey{
Hex: "76a914112e29df5df4866e40ef98e0857036b275380fe088ac",
Addresses: []string{
"VbZfhUMCUJHDjqjby6ynYFPZSNVYhfe4cK",
},
},
},
},
}
}
func Test_PackTx(t *testing.T) {
type args struct {
tx bchain.Tx
height uint32
blockTime int64
parser *ViacoinParser
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "viacoin-1",
args: args{
tx: testTx1,
height: 5159277,
blockTime: 1530319242,
parser: NewViacoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: testTxPacked1,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.args.parser.PackTx(&tt.args.tx, tt.args.height, tt.args.blockTime)
if (err != nil) != tt.wantErr {
t.Errorf("packTx() error = %v, wantErr %v", err, tt.wantErr)
return
}
h := hex.EncodeToString(got)
if !reflect.DeepEqual(h, tt.want) {
t.Errorf("packTx() = %v, want %v", h, tt.want)
}
})
}
}
func Test_UnpackTx(t *testing.T) {
type args struct {
packedTx string
parser *ViacoinParser
}
tests := []struct {
name string
args args
want *bchain.Tx
want1 uint32
wantErr bool
}{
{
name: "viacoin-1",
args: args{
packedTx: testTxPacked1,
parser: NewViacoinParser(GetChainParams("main"), &btc.Configuration{}),
},
want: &testTx1,
want1: 5159277,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, _ := hex.DecodeString(tt.args.packedTx)
got, got1, err := tt.args.parser.UnpackTx(b)
if (err != nil) != tt.wantErr {
t.Errorf("unpackTx() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("unpackTx() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1)
}
})
}
}

View File

@ -0,0 +1,73 @@
package viacoin
import (
"blockbook/bchain"
"blockbook/bchain/coins/btc"
"encoding/json"
"github.com/golang/glog"
)
// ViacoinRPC is an interface to JSON-RPC bitcoind service
type ViacoinRPC struct {
*btc.BitcoinRPC
}
// NewViacoinRPC returns new ViacoinRPC instance
func NewViacoinRPC(config json.RawMessage, pushHandler func(notificationType bchain.NotificationType)) (bchain.BlockChain, error) {
b, err := btc.NewBitcoinRPC(config, pushHandler)
if err != nil {
return nil, err
}
s := &ViacoinRPC{
b.(*btc.BitcoinRPC),
}
s.RPCMarshaler = btc.JSONMarshalerV1{}
s.ChainConfig.SupportsEstimateSmartFee = false
return s, nil
}
// Initialize initializes ViacoinRPC instance.
func (b *ViacoinRPC) Initialize() error {
ci, err := b.GetChainInfo()
if err != nil {
return err
}
chainName := ci.Chain
glog.Info("Chain name ", chainName)
params := GetChainParams(chainName)
// always create parser
b.Parser = NewViacoinParser(params, b.ChainConfig)
// parameters for getInfo request
if params.Net == MainnetMagic {
b.Testnet = false
b.Network = "livenet"
} else {
b.Testnet = true
b.Network = "testnet"
}
glog.Info("rpc: block chain ", params.Name)
return nil
}
// GetBlock returns block with given hash
func (b *ViacoinRPC) GetBlock(hash string, height uint32) (*bchain.Block, error) {
var err error
if hash == "" {
hash, err = b.GetBlockHash(height)
if err != nil {
return nil, err
}
}
if !b.ParseBlocks {
return b.GetBlockFull(hash)
}
return b.GetBlockWithoutHeader(hash, height)
}

View File

@ -0,0 +1,72 @@
{
"coin": {
"name": "Viacoin",
"shortcut": "VIA",
"label": "Viacoin",
"alias": "viacoin"
},
"ports": {
"backend_rpc": 8055,
"backend_message_queue": 38355,
"blockbook_internal": 9055,
"blockbook_public": 9155
},
"ipc": {
"rpc_url_template": "http://127.0.0.1:{{.Ports.BackendRPC}}",
"rpc_user": "rpc",
"rpc_pass": "rpcp",
"rpc_timeout": 25,
"message_queue_binding_template": "tcp://127.0.0.1:{{.Ports.BackendMessageQueue}}"
},
"backend": {
"package_name": "backend-viacoin",
"package_revision": "satoshilabs-1",
"system_user": "viacoin",
"version": "1.14-beta-1",
"binary_url": "https://github.com/viacoin/viacoin/releases/download/v0.15.2/viacoin-0.15.2-x86_64-linux-gnu.tar.gz",
"verification_type": "sha256",
"verification_source": "bdbd432645a8b4baadddb7169ea4bef3d03f80dc2ce53dce5783d8582ac63bab",
"extract_command": "tar -C backend --strip 1 -xf",
"exclude_files": [
"bin/viacoin-qt"
],
"exec_command_template": "{{.Env.BackendInstallPath}}/{{.Coin.Alias}}/bin/viacoind -datadir={{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend -conf={{.Env.BackendInstallPath}}/{{.Coin.Alias}}/{{.Coin.Alias}}.conf -pid=/run/{{.Coin.Alias}}/{{.Coin.Alias}}.pid",
"logrotate_files_template": "{{.Env.BackendDataPath}}/{{.Coin.Alias}}/backend/*.log",
"postinst_script_template": "",
"service_type": "forking",
"service_additional_params_template": "",
"protect_memory": false,
"mainnet": true,
"server_config_file": "bitcoin_like.conf",
"client_config_file": "bitcoin_like_client.conf",
"additional_params": {
"discover": 0,
"rpcthreads": 16,
"upnp": 0,
"whitelist": "127.0.0.1"
}
},
"blockbook": {
"package_name": "blockbook-viacoin",
"system_user": "blockbook-viacoin",
"internal_binding_template": ":{{.Ports.BlockbookInternal}}",
"public_binding_template": ":{{.Ports.BlockbookPublic}}",
"explorer_url": "",
"additional_params": "-resyncindexperiod=30011 -resyncmempoolperiod=2011",
"block_chain": {
"parse": true,
"mempool_workers": 8,
"mempool_sub_workers": 2,
"block_addresses_to_keep": 300,
"xpub_magic": 76067358,
"xpub_magic_segwit_p2sh": 77429938,
"xpub_magic_segwit_native": 78792518,
"slip44": 14,
"additional_params": {}
}
},
"meta": {
"package_maintainer": "Romano",
"package_maintainer_email": "romanornr@gmail.com"
}
}

View File

@ -26,6 +26,7 @@
| Koto | 9051 | 9151 | 8051 | 38351 |
| Bellcoin | 9052 | 9152 | 8052 | 38352 |
| NULS | 9053 | 9153 | 8053 | 38353 |
| Viacoin | 9055 | 9155 | 8055 | 38355 |
| Flo | 9066 | 9166 | 8066 | 38366 |
| Polis | 9067 | 9167 | 8067 | 38367 |
| Qtum | 9088 | 9188 | 8088 | 38388 |

36
tests/rpc/testdata/viacoin.json vendored 100644
View File

@ -0,0 +1,36 @@
{
"blockHeight": 6197648,
"blockHash": "7bfaf2048ce581f05ea6c87cb043bb5908e6afa83ef49621bf558a027cfe367e",
"blockTime": 1555275169,
"blockTxs": [
"79f2c2690cae8e3e4631a30462197316228fe0e5cf4f2f2eee904d8dcd0206c6"
],
"txDetails": {
"79f2c2690cae8e3e4631a30462197316228fe0e5cf4f2f2eee904d8dcd0206c6": {
"hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff090390915e045cb39da1ffffffff01ca9a3b00000000001976a91424cc424c1e5e977175d2b20012554d39024bd68f88ac00000000",
"txid": "79f2c2690cae8e3e4631a30462197316228fe0e5cf4f2f2eee904d8dcd0206c6",
"blocktime": 1555275169,
"time": 1555275169,
"locktime": 0,
"version": 1,
"vin": [
{
"coinbase": "0390915e045cb39da1",
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.0390625,
"n": 0,
"scriptPubKey": {
"hex": "76a91424cc424c1e5e977175d2b20012554d39024bd68f88ac",
"addresses": [
"VdMPvn7vUTSzbYjiMDs1jku9wAh1Ri2Y1A"
]
}
}
]
}
}
}

View File

@ -0,0 +1,71 @@
{
"connectBlocks": {
"syncRanges": [
{"lower": 1503776, "upper": 1503796}
],
"blocks": {
"1503796": {
"height": 1503796,
"hash": "f907e10100b3ec0be53c4dd40d0efb563a9d1de1d2b7a156ffec03b8d364ffb4",
"noTxs": 1,
"txDetails": [
{
"txid": "d819588eab648eb7d99f2acc2e4cf21c546a5b15d7090620f703fd9a0d384e59",
"version": 1,
"vin": [
{
"coinbase": "0334f2160101",
"sequence": 4294967295
}
],
"vout": [
{
"value": 5.00000000,
"n": 0,
"scriptPubKey": {
"hex": "76a914d02029d9dffe8f7cbe08122cacb8f57596132f3488ac"
}
}
],
"hex": "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff060334f2160101ffffffff010065cd1d000000001976a914d02029d9dffe8f7cbe08122cacb8f57596132f3488ac00000000",
"time": 1442385302,
"blocktime": 1442385302
}
]
}
}
},
"handleFork": {
"syncRanges": [
{"lower": 1503790, "upper": 1503796}
],
"fakeBlocks": {
"1503794": {
"height": 1503794,
"hash": "a1b30026cfd15e4f46c5ffbd57f615d71e5c5d2366b079131123bf055d9e812f"
},
"1503795": {
"height": 1503795,
"hash": "2d92315148dd3568c1a9ab7bf6bd893ed0ca012372f69e139e026453f23d92c4"
},
"1503796": {
"height": 1503796,
"hash": "dbc84d9af0a74252f337cbcc2fdd6295db53c2cea2bd94ba8afe66f24bc53a5b"
}
},
"realBlocks": {
"1503794": {
"height": 1503794,
"hash": "9f1ad78ac7a7f4bf2ca32a2be4117495510ec517525209c854b51d9b7bfefa95"
},
"1503795": {
"height": 1503795,
"hash": "88084fc69161eb5868bd146d78fb10fe7d80a474029b23728809e0a744bcf5dd"
},
"1503796": {
"height": 1503796,
"hash": "f907e10100b3ec0be53c4dd40d0efb563a9d1de1d2b7a156ffec03b8d364ffb4"
}
}
}
}

View File

@ -131,6 +131,11 @@
"EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"],
"sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"]
},
"viacoin": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetTransactionForMempool", "MempoolSync",
"EstimateSmartFee", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"],
"sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"]
},
"nuls": {
"rpc": ["GetBlock", "GetBlockHash", "GetTransaction", "GetBestBlockHash", "GetBestBlockHeight", "GetBlockHeader"],
"sync": ["ConnectBlocksParallel", "ConnectBlocks", "HandleFork"]