github.com/bchainhub/blockbook@v0.3.2/bchain/coins/nuls/nulsparser.go (about) 1 package nuls 2 3 import ( 4 "blockbook/bchain" 5 "blockbook/bchain/coins/btc" 6 "bytes" 7 "encoding/binary" 8 "encoding/json" 9 "errors" 10 vlq "github.com/bsm/go-vlq" 11 "github.com/martinboehm/btcutil/base58" 12 13 "github.com/martinboehm/btcd/wire" 14 "github.com/martinboehm/btcutil/chaincfg" 15 "github.com/martinboehm/btcutil/hdkeychain" 16 ) 17 18 // magic numbers 19 const ( 20 MainnetMagic wire.BitcoinNet = 0xbd6b0cbf 21 TestnetMagic wire.BitcoinNet = 0xffcae2ce 22 RegtestMagic wire.BitcoinNet = 0xdcb7c1fc 23 24 AddressHashLength = 24 25 ) 26 27 // chain parameters 28 var ( 29 MainNetParams chaincfg.Params 30 TestNetParams chaincfg.Params 31 RegtestParams chaincfg.Params 32 ) 33 34 func init() { 35 MainNetParams = chaincfg.MainNetParams 36 MainNetParams.Net = MainnetMagic 37 38 // Address encoding magics 39 MainNetParams.AddressMagicLen = 3 40 41 // Address encoding magics 42 MainNetParams.PubKeyHashAddrID = []byte{4, 35, 1} // base58 prefix: Ns 43 MainNetParams.ScriptHashAddrID = []byte{4, 35, 1} // base58 prefix: Ns 44 45 TestNetParams = chaincfg.TestNet3Params 46 TestNetParams.Net = TestnetMagic 47 48 // Address encoding magics 49 TestNetParams.PubKeyHashAddrID = []byte{140} // base58 prefix: y 50 TestNetParams.ScriptHashAddrID = []byte{19} // base58 prefix: 8 or 9 51 52 RegtestParams = chaincfg.RegressionNetParams 53 RegtestParams.Net = RegtestMagic 54 55 // Address encoding magics 56 RegtestParams.PubKeyHashAddrID = []byte{140} // base58 prefix: y 57 RegtestParams.ScriptHashAddrID = []byte{19} // base58 prefix: 8 or 9 58 } 59 60 // NulsParser handle 61 type NulsParser struct { 62 *btc.BitcoinParser 63 } 64 65 // NewNulsParser returns new NulsParser instance 66 func NewNulsParser(params *chaincfg.Params, c *btc.Configuration) *NulsParser { 67 return &NulsParser{BitcoinParser: btc.NewBitcoinParser(params, c)} 68 } 69 70 // GetChainParams contains network parameters for the main Gincoin network, 71 // the regression test Gincoin network, the test Gincoin network and 72 // the simulation test Gincoin network, in this order 73 func GetChainParams(chain string) *chaincfg.Params { 74 if !chaincfg.IsRegistered(&MainNetParams) { 75 err := chaincfg.Register(&MainNetParams) 76 if err == nil { 77 err = chaincfg.Register(&TestNetParams) 78 } 79 if err == nil { 80 err = chaincfg.Register(&RegtestParams) 81 } 82 if err != nil { 83 panic(err) 84 } 85 } 86 switch chain { 87 case "test": 88 return &TestNetParams 89 case "regtest": 90 return &RegtestParams 91 default: 92 return &MainNetParams 93 } 94 } 95 96 // PackedTxidLen returns length in bytes of packed txid 97 func (p *NulsParser) PackedTxidLen() int { 98 return 34 99 } 100 101 // GetAddrDescFromAddress returns internal address representation (descriptor) of given address 102 func (p *NulsParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) { 103 addressByte := base58.Decode(address) 104 return bchain.AddressDescriptor(addressByte), nil 105 } 106 107 // GetAddrDescFromVout returns internal address representation (descriptor) of given transaction output 108 func (p *NulsParser) GetAddrDescFromVout(output *bchain.Vout) (bchain.AddressDescriptor, error) { 109 addressStr := output.ScriptPubKey.Hex 110 addressByte := base58.Decode(addressStr) 111 return bchain.AddressDescriptor(addressByte), nil 112 } 113 114 // GetAddressesFromAddrDesc returns addresses for given address descriptor with flag if the addresses are searchable 115 func (p *NulsParser) GetAddressesFromAddrDesc(addrDesc bchain.AddressDescriptor) ([]string, bool, error) { 116 var addrs []string 117 118 if addrDesc != nil { 119 addrs = append(addrs, base58.Encode(addrDesc)) 120 } 121 122 return addrs, true, nil 123 } 124 125 // PackTx packs transaction to byte array 126 func (p *NulsParser) PackTx(tx *bchain.Tx, height uint32, blockTime int64) ([]byte, error) { 127 txBytes, error := json.Marshal(tx) 128 if error != nil { 129 return nil, error 130 } 131 132 buf := make([]byte, 4+vlq.MaxLen64) 133 binary.BigEndian.PutUint32(buf[0:4], height) 134 vlq.PutInt(buf[4:4+vlq.MaxLen64], blockTime) 135 resByes := bytes.Join([][]byte{buf, txBytes}, []byte("")) 136 return resByes, nil 137 } 138 139 // UnpackTx unpacks transaction from byte array 140 func (p *NulsParser) UnpackTx(buf []byte) (*bchain.Tx, uint32, error) { 141 height := binary.BigEndian.Uint32(buf) 142 bt, _ := vlq.Int(buf[4 : 4+vlq.MaxLen64]) 143 tx, err := p.ParseTx(buf[4+vlq.MaxLen64:]) 144 if err != nil { 145 return nil, 0, err 146 } 147 tx.Blocktime = bt 148 149 return tx, height, nil 150 } 151 152 // ParseTx parses tx from blob 153 func (p *NulsParser) ParseTx(b []byte) (*bchain.Tx, error) { 154 tx := bchain.Tx{} 155 err := json.Unmarshal(b, &tx) 156 157 if err != nil { 158 return nil, err 159 } 160 return &tx, err 161 } 162 163 // DeriveAddressDescriptorsFromTo derives address descriptors from given xpub for addresses in index range 164 func (p *NulsParser) DeriveAddressDescriptorsFromTo(xpub string, change uint32, fromIndex uint32, toIndex uint32) ([]bchain.AddressDescriptor, error) { 165 if toIndex <= fromIndex { 166 return nil, errors.New("toIndex<=fromIndex") 167 } 168 extKey, err := hdkeychain.NewKeyFromString(xpub, p.Params.Base58CksumHasher) 169 if err != nil { 170 return nil, err 171 } 172 changeExtKey, err := extKey.Child(change) 173 if err != nil { 174 return nil, err 175 } 176 ad := make([]bchain.AddressDescriptor, toIndex-fromIndex) 177 for index := fromIndex; index < toIndex; index++ { 178 indexExtKey, err := changeExtKey.Child(index) 179 if err != nil { 180 return nil, err 181 } 182 s, err := indexExtKey.Address(p.Params) 183 184 if err != nil && indexExtKey != nil { 185 return nil, err 186 } 187 addHashs := make([]byte, AddressHashLength) 188 copy(addHashs[0:3], p.Params.PubKeyHashAddrID) 189 copy(addHashs[3:], s.ScriptAddress()) 190 copy(addHashs[23:], []byte{p.xor(addHashs[0:23])}) 191 192 //addressStr := base58.Encode(addHashs) 193 ad[index-fromIndex] = addHashs 194 } 195 return ad, nil 196 } 197 198 func (p *NulsParser) xor(body []byte) byte { 199 var xor byte = 0x00 200 for i := 0; i < len(body); i++ { 201 xor ^= body[i] 202 } 203 return xor 204 }