It was necessary to split the composition chain in other coins from BitcoinParser to BitcoinLikeParser to keep backwards compatibility
228 lines
5.8 KiB
Go
Executable File
228 lines
5.8 KiB
Go
Executable File
package divi
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"io"
|
|
"math/big"
|
|
|
|
"github.com/juju/errors"
|
|
"github.com/martinboehm/btcd/wire"
|
|
"github.com/martinboehm/btcutil/chaincfg"
|
|
"github.com/trezor/blockbook/bchain"
|
|
"github.com/trezor/blockbook/bchain/coins/btc"
|
|
"github.com/trezor/blockbook/bchain/coins/utils"
|
|
)
|
|
|
|
const (
|
|
// MainnetMagic = "network messages so the messages can be identified to belong to a specific coin"
|
|
// Source https://github.com/DiviProject/Divi/blob/master0/divi/src/chainparams.cpp#L128-L136
|
|
MainnetMagic wire.BitcoinNet = 0x8f8da0df
|
|
)
|
|
|
|
var (
|
|
// MainNetParams = ???
|
|
MainNetParams chaincfg.Params
|
|
)
|
|
|
|
func init() {
|
|
// DIVI mainnet Address encoding magics
|
|
MainNetParams = chaincfg.MainNetParams
|
|
MainNetParams.Net = MainnetMagic
|
|
MainNetParams.PubKeyHashAddrID = []byte{30} // starting with 'D'
|
|
MainNetParams.ScriptHashAddrID = []byte{13}
|
|
MainNetParams.PrivateKeyID = []byte{212}
|
|
}
|
|
|
|
// DivicoinParser handle
|
|
type DivicoinParser struct {
|
|
*btc.BitcoinLikeParser
|
|
baseparser *bchain.BaseParser
|
|
BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc
|
|
}
|
|
|
|
// NewDiviParser returns new DivicoinParser instance
|
|
func NewDiviParser(params *chaincfg.Params, c *btc.Configuration) *DivicoinParser {
|
|
p := &DivicoinParser{
|
|
BitcoinLikeParser: btc.NewBitcoinLikeParser(params, c),
|
|
baseparser: &bchain.BaseParser{},
|
|
}
|
|
p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc
|
|
p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
|
|
return p
|
|
}
|
|
|
|
// GetChainParams contains network parameters for the main Divi network
|
|
func GetChainParams(chain string) *chaincfg.Params {
|
|
if !chaincfg.IsRegistered(&MainNetParams) {
|
|
err := chaincfg.Register(&MainNetParams)
|
|
/*if err == nil {
|
|
err = chaincfg.Register(&TestNetParams)
|
|
}*/
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
} /*
|
|
switch chain {
|
|
case "test":
|
|
return &TestNetParams
|
|
default:
|
|
*/return &MainNetParams
|
|
//}
|
|
}
|
|
|
|
// ParseBlock parses raw block to our Block struct
|
|
func (p *DivicoinParser) 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, errors.Annotatef(err, "Deserialize")
|
|
}
|
|
|
|
if h.Version > 3 {
|
|
// Skip past AccumulatorCheckpoint which was added in pivx block version 4
|
|
r.Seek(32, io.SeekCurrent)
|
|
}
|
|
|
|
err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w)
|
|
if err != nil {
|
|
return nil, errors.Annotatef(err, "DecodeTransactions")
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// PackTx packs transaction to byte array using protobuf
|
|
func (p *DivicoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) {
|
|
return p.baseparser.PackTx(tx, height, blockTime)
|
|
}
|
|
|
|
// UnpackTx unpacks transaction from protobuf byte array
|
|
func (p *DivicoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) {
|
|
return p.baseparser.UnpackTx(buf)
|
|
}
|
|
|
|
// ParseTx parses byte array containing transaction and returns Tx struct
|
|
func (p *DivicoinParser) ParseTx(b []byte) (*bchain.Tx, error) {
|
|
t := wire.MsgTx{}
|
|
r := bytes.NewReader(b)
|
|
if err := t.Deserialize(r); err != nil {
|
|
return nil, err
|
|
}
|
|
tx := p.TxFromMsgTx(&t, true)
|
|
tx.Hex = hex.EncodeToString(b)
|
|
return &tx, nil
|
|
}
|
|
|
|
// TxFromMsgTx parses tx and adds handling for OP_ZEROCOINSPEND inputs
|
|
func (p *DivicoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx {
|
|
vin := make([]bchain.Vin, len(t.TxIn))
|
|
for i, in := range t.TxIn {
|
|
s := bchain.ScriptSig{
|
|
Hex: hex.EncodeToString(in.SignatureScript),
|
|
// missing: Asm,
|
|
}
|
|
|
|
txid := in.PreviousOutPoint.Hash.String()
|
|
|
|
vin[i] = bchain.Vin{
|
|
Txid: txid,
|
|
Vout: in.PreviousOutPoint.Index,
|
|
Sequence: in.Sequence,
|
|
ScriptSig: s,
|
|
}
|
|
}
|
|
vout := make([]bchain.Vout, len(t.TxOut))
|
|
for i, out := range t.TxOut {
|
|
addrs := []string{}
|
|
if parseAddresses {
|
|
addrs, _, _ = p.OutputScriptToAddressesFunc(out.PkScript)
|
|
}
|
|
s := bchain.ScriptPubKey{
|
|
Hex: hex.EncodeToString(out.PkScript),
|
|
Addresses: addrs,
|
|
// missing: Asm,
|
|
// missing: Type,
|
|
}
|
|
var vs big.Int
|
|
vs.SetInt64(out.Value)
|
|
vout[i] = bchain.Vout{
|
|
ValueSat: vs,
|
|
N: uint32(i),
|
|
ScriptPubKey: s,
|
|
}
|
|
}
|
|
tx := bchain.Tx{
|
|
Txid: t.TxHash().String(),
|
|
Version: t.Version,
|
|
LockTime: t.LockTime,
|
|
Vin: vin,
|
|
Vout: vout,
|
|
// skip: BlockHash,
|
|
// skip: Confirmations,
|
|
// skip: Time,
|
|
// skip: Blocktime,
|
|
}
|
|
return tx
|
|
}
|
|
|
|
// ParseTxFromJSON parses JSON message containing transaction and returns Tx struct
|
|
func (p *DivicoinParser) ParseTxFromJSON(msg json.RawMessage) (*bchain.Tx, error) {
|
|
var tx bchain.Tx
|
|
err := json.Unmarshal(msg, &tx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i := range tx.Vout {
|
|
vout := &tx.Vout[i]
|
|
// convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal
|
|
vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
vout.JsonValue = ""
|
|
|
|
if vout.ScriptPubKey.Addresses == nil {
|
|
vout.ScriptPubKey.Addresses = []string{}
|
|
}
|
|
}
|
|
|
|
return &tx, nil
|
|
}
|
|
|
|
// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
|
|
func (p *DivicoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) {
|
|
rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script)
|
|
return rv, s, nil
|
|
}
|
|
|
|
// GetAddrDescForUnknownInput = ???
|
|
func (p *DivicoinParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor {
|
|
if len(tx.Vin) > input {
|
|
scriptHex := tx.Vin[input].ScriptSig.Hex
|
|
|
|
if scriptHex != "" {
|
|
script, _ := hex.DecodeString(scriptHex)
|
|
return script
|
|
}
|
|
}
|
|
|
|
s := make([]byte, 10)
|
|
return s
|
|
}
|