github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/monetaryunit/monetaryunitparser.go (about) 1 package monetaryunit 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "encoding/json" 7 "io" 8 9 "github.com/juju/errors" 10 "github.com/martinboehm/btcd/wire" 11 "github.com/martinboehm/btcutil/chaincfg" 12 "github.com/trezor/blockbook/bchain" 13 "github.com/trezor/blockbook/bchain/coins/btc" 14 "github.com/trezor/blockbook/bchain/coins/utils" 15 ) 16 17 const ( 18 // Net Magics 19 MainnetMagic wire.BitcoinNet = 0x91c4fdea 20 TestnetMagic wire.BitcoinNet = 0x477665bd 21 ) 22 23 var ( 24 MainNetParams chaincfg.Params 25 TestNetParams chaincfg.Params 26 ) 27 28 func init() { 29 // MonetaryUnit mainnet Address encoding magics 30 MainNetParams = chaincfg.MainNetParams 31 MainNetParams.Net = MainnetMagic 32 MainNetParams.PubKeyHashAddrID = []byte{16} // starting with '7' 33 MainNetParams.ScriptHashAddrID = []byte{76} 34 MainNetParams.PrivateKeyID = []byte{126} 35 36 // MonetaryUnit testnet Address encoding magics 37 TestNetParams = chaincfg.TestNet3Params 38 TestNetParams.Net = TestnetMagic 39 TestNetParams.PubKeyHashAddrID = []byte{139} // starting with 'x' or 'y' 40 TestNetParams.ScriptHashAddrID = []byte{19} 41 TestNetParams.PrivateKeyID = []byte{239} 42 } 43 44 // MonetaryUnitParser handle 45 type MonetaryUnitParser struct { 46 *btc.BitcoinLikeParser 47 baseparser *bchain.BaseParser 48 BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc 49 } 50 51 // NewMonetaryUnitParser returns new MonetaryUnitParser instance 52 func NewMonetaryUnitParser(params *chaincfg.Params, c *btc.Configuration) *MonetaryUnitParser { 53 p := &MonetaryUnitParser{ 54 BitcoinLikeParser: btc.NewBitcoinLikeParser(params, c), 55 baseparser: &bchain.BaseParser{}, 56 } 57 p.BitcoinOutputScriptToAddressesFunc = p.OutputScriptToAddressesFunc 58 p.OutputScriptToAddressesFunc = p.outputScriptToAddresses 59 return p 60 } 61 62 // GetChainParams contains network parameters for the main MonetaryUnit network 63 func GetChainParams(chain string) *chaincfg.Params { 64 if !chaincfg.IsRegistered(&MainNetParams) { 65 err := chaincfg.Register(&MainNetParams) 66 if err == nil { 67 err = chaincfg.Register(&TestNetParams) 68 } 69 if err != nil { 70 panic(err) 71 } 72 } 73 switch chain { 74 case "test": 75 return &TestNetParams 76 default: 77 return &MainNetParams 78 } 79 } 80 81 // ParseBlock parses raw block to our Block struct 82 func (p *MonetaryUnitParser) ParseBlock(b []byte) (*bchain.Block, error) { 83 r := bytes.NewReader(b) 84 w := wire.MsgBlock{} 85 h := wire.BlockHeader{} 86 err := h.Deserialize(r) 87 if err != nil { 88 return nil, errors.Annotatef(err, "Deserialize") 89 } 90 91 if h.Version > 3 { 92 // Skip past AccumulatorCheckpoint which was added in MonetaryUnit block version 4 93 r.Seek(32, io.SeekCurrent) 94 } 95 96 err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) 97 if err != nil { 98 return nil, errors.Annotatef(err, "DecodeTransactions") 99 } 100 101 txs := make([]bchain.Tx, len(w.Transactions)) 102 for ti, t := range w.Transactions { 103 txs[ti] = p.TxFromMsgTx(t, false) 104 } 105 106 return &bchain.Block{ 107 BlockHeader: bchain.BlockHeader{ 108 Size: len(b), 109 Time: h.Timestamp.Unix(), 110 }, 111 Txs: txs, 112 }, nil 113 } 114 115 // PackTx packs transaction to byte array using protobuf 116 func (p *MonetaryUnitParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { 117 return p.baseparser.PackTx(tx, height, blockTime) 118 } 119 120 // UnpackTx unpacks transaction from protobuf byte array 121 func (p *MonetaryUnitParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { 122 return p.baseparser.UnpackTx(buf) 123 } 124 125 // ParseTx parses byte array containing transaction and returns Tx struct 126 func (p *MonetaryUnitParser) ParseTx(b []byte) (*bchain.Tx, error) { 127 t := wire.MsgTx{} 128 r := bytes.NewReader(b) 129 if err := t.Deserialize(r); err != nil { 130 return nil, err 131 } 132 tx := p.TxFromMsgTx(&t, true) 133 tx.Hex = hex.EncodeToString(b) 134 return &tx, nil 135 } 136 137 // ParseTxFromJson parses JSON message containing transaction and returns Tx struct 138 func (p *MonetaryUnitParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) { 139 var tx bchain.Tx 140 err := json.Unmarshal(msg, &tx) 141 if err != nil { 142 return nil, err 143 } 144 145 for i := range tx.Vout { 146 vout := &tx.Vout[i] 147 // convert vout.JsonValue to big.Int and clear it, it is only temporary value used for unmarshal 148 vout.ValueSat, err = p.AmountToBigInt(vout.JsonValue) 149 if err != nil { 150 return nil, err 151 } 152 vout.JsonValue = "" 153 154 if vout.ScriptPubKey.Addresses == nil { 155 vout.ScriptPubKey.Addresses = []string{} 156 } 157 } 158 159 return &tx, nil 160 } 161 162 // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses 163 func (p *MonetaryUnitParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { 164 165 rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script) 166 return rv, s, nil 167 } 168 169 func (p *MonetaryUnitParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain.AddressDescriptor { 170 if len(tx.Vin) > input { 171 scriptHex := tx.Vin[input].ScriptSig.Hex 172 173 if scriptHex != "" { 174 script, _ := hex.DecodeString(scriptHex) 175 return script 176 } 177 } 178 179 s := make([]byte, 10) 180 return s 181 }