github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/divi/diviparser.go (about) 1 package divi 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "io" 8 "math/big" 9 10 "github.com/juju/errors" 11 "github.com/martinboehm/btcd/wire" 12 "github.com/martinboehm/btcutil/chaincfg" 13 "github.com/trezor/blockbook/bchain" 14 "github.com/trezor/blockbook/bchain/coins/btc" 15 "github.com/trezor/blockbook/bchain/coins/utils" 16 ) 17 18 const ( 19 // MainnetMagic = "network messages so the messages can be identified to belong to a specific coin" 20 // Source https://github.com/DiviProject/Divi/blob/master0/divi/src/chainparams.cpp#L128-L136 21 MainnetMagic wire.BitcoinNet = 0x8f8da0df 22 ) 23 24 var ( 25 // MainNetParams = ??? 26 MainNetParams chaincfg.Params 27 ) 28 29 func init() { 30 // DIVI mainnet Address encoding magics 31 MainNetParams = chaincfg.MainNetParams 32 MainNetParams.Net = MainnetMagic 33 MainNetParams.PubKeyHashAddrID = []byte{30} // starting with 'D' 34 MainNetParams.ScriptHashAddrID = []byte{13} 35 MainNetParams.PrivateKeyID = []byte{212} 36 } 37 38 // DivicoinParser handle 39 type DivicoinParser struct { 40 *btc.BitcoinLikeParser 41 baseparser *bchain.BaseParser 42 BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc 43 } 44 45 // NewDiviParser returns new DivicoinParser instance 46 func NewDiviParser(params *chaincfg.Params, c *btc.Configuration) *DivicoinParser { 47 p := &DivicoinParser{ 48 BitcoinLikeParser: btc.NewBitcoinLikeParser(params, c), 49 baseparser: &bchain.BaseParser{}, 50 } 51 p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc 52 p.OutputScriptToAddressesFunc = p.outputScriptToAddresses 53 return p 54 } 55 56 // GetChainParams contains network parameters for the main Divi network 57 func GetChainParams(chain string) *chaincfg.Params { 58 if !chaincfg.IsRegistered(&MainNetParams) { 59 err := chaincfg.Register(&MainNetParams) 60 /*if err == nil { 61 err = chaincfg.Register(&TestNetParams) 62 }*/ 63 if err != nil { 64 panic(err) 65 } 66 } /* 67 switch chain { 68 case "test": 69 return &TestNetParams 70 default: 71 */return &MainNetParams 72 //} 73 } 74 75 // ParseBlock parses raw block to our Block struct 76 func (p *DivicoinParser) ParseBlock(b []byte) (*bchain.Block, error) { 77 r := bytes.NewReader(b) 78 w := wire.MsgBlock{} 79 h := wire.BlockHeader{} 80 err := h.Deserialize(r) 81 if err != nil { 82 return nil, errors.Annotatef(err, "Deserialize") 83 } 84 85 if h.Version > 3 { 86 // Skip past AccumulatorCheckpoint which was added in pivx block version 4 87 r.Seek(32, io.SeekCurrent) 88 } 89 90 err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) 91 if err != nil { 92 return nil, errors.Annotatef(err, "DecodeTransactions") 93 } 94 95 txs := make([]bchain.Tx, len(w.Transactions)) 96 for ti, t := range w.Transactions { 97 txs[ti] = p.TxFromMsgTx(t, false) 98 } 99 100 return &bchain.Block{ 101 BlockHeader: bchain.BlockHeader{ 102 Size: len(b), 103 Time: h.Timestamp.Unix(), 104 }, 105 Txs: txs, 106 }, nil 107 } 108 109 // PackTx packs transaction to byte array using protobuf 110 func (p *DivicoinParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { 111 return p.baseparser.PackTx(tx, height, blockTime) 112 } 113 114 // UnpackTx unpacks transaction from protobuf byte array 115 func (p *DivicoinParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { 116 return p.baseparser.UnpackTx(buf) 117 } 118 119 // ParseTx parses byte array containing transaction and returns Tx struct 120 func (p *DivicoinParser) ParseTx(b []byte) (*bchain.Tx, error) { 121 t := wire.MsgTx{} 122 r := bytes.NewReader(b) 123 if err := t.Deserialize(r); err != nil { 124 return nil, err 125 } 126 tx := p.TxFromMsgTx(&t, true) 127 tx.Hex = hex.EncodeToString(b) 128 return &tx, nil 129 } 130 131 // TxFromMsgTx parses tx and adds handling for OP_ZEROCOINSPEND inputs 132 func (p *DivicoinParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx { 133 vin := make([]bchain.Vin, len(t.TxIn)) 134 for i, in := range t.TxIn { 135 s := bchain.ScriptSig{ 136 Hex: hex.EncodeToString(in.SignatureScript), 137 // missing: Asm, 138 } 139 140 txid := in.PreviousOutPoint.Hash.String() 141 142 vin[i] = bchain.Vin{ 143 Txid: txid, 144 Vout: in.PreviousOutPoint.Index, 145 Sequence: in.Sequence, 146 ScriptSig: s, 147 } 148 } 149 vout := make([]bchain.Vout, len(t.TxOut)) 150 for i, out := range t.TxOut { 151 addrs := []string{} 152 if parseAddresses { 153 addrs, _, _ = p.OutputScriptToAddressesFunc(out.PkScript) 154 } 155 s := bchain.ScriptPubKey{ 156 Hex: hex.EncodeToString(out.PkScript), 157 Addresses: addrs, 158 // missing: Asm, 159 // missing: Type, 160 } 161 var vs big.Int 162 vs.SetInt64(out.Value) 163 vout[i] = bchain.Vout{ 164 ValueSat: vs, 165 N: uint32(i), 166 ScriptPubKey: s, 167 } 168 } 169 tx := bchain.Tx{ 170 Txid: t.TxHash().String(), 171 Version: t.Version, 172 LockTime: t.LockTime, 173 Vin: vin, 174 Vout: vout, 175 // skip: BlockHash, 176 // skip: Confirmations, 177 // skip: Time, 178 // skip: Blocktime, 179 } 180 return tx 181 } 182 183 // ParseTxFromJSON parses JSON message containing transaction and returns Tx struct 184 func (p *DivicoinParser) ParseTxFromJSON(msg json.RawMessage) (*bchain.Tx, error) { 185 var tx bchain.Tx 186 err := json.Unmarshal(msg, &tx) 187 if err != nil { 188 return nil, err 189 } 190 191 for i := range tx.Vout { 192 vout := &tx.Vout[i] 193 // convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal 194 vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue) 195 if err != nil { 196 return nil, err 197 } 198 vout.JsonValue = "" 199 200 if vout.ScriptPubKey.Addresses == nil { 201 vout.ScriptPubKey.Addresses = []string{} 202 } 203 } 204 205 return &tx, nil 206 } 207 208 // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses 209 func (p *DivicoinParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { 210 rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script) 211 return rv, s, nil 212 } 213 214 // GetAddrDescForUnknownInput = ??? 215 func (p *DivicoinParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor { 216 if len(tx.Vin) > input { 217 scriptHex := tx.Vin[input].ScriptSig.Hex 218 219 if scriptHex != "" { 220 script, _ := hex.DecodeString(scriptHex) 221 return script 222 } 223 } 224 225 s := make([]byte, 10) 226 return s 227 }