github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/pkg/stafidecoder/extrinsic.go (about) 1 package stafi_decoder 2 3 import ( 4 "fmt" 5 6 "github.com/itering/scale.go/utiles" 7 "github.com/shopspring/decimal" 8 commonTypes "github.com/stafiprotocol/go-substrate-rpc-client/types/common" 9 "golang.org/x/crypto/blake2b" 10 ) 11 12 type ExtrinsicDecoder struct { 13 ScaleDecoder 14 ExtrinsicLength int `json:"extrinsic_length"` 15 ExtrinsicHash string `json:"extrinsic_hash"` 16 VersionInfo string `json:"version_info"` 17 ContainsTransaction bool `json:"contains_transaction"` 18 Address interface{} `json:"address"` 19 Signature string `json:"signature"` 20 SignatureVersion int `json:"signature_version"` 21 Nonce int `json:"nonce"` 22 Era string `json:"era"` 23 CallIndex string `json:"call_index"` 24 Tip interface{} `json:"tip"` 25 CallModule MetadataModules `json:"call_module"` 26 Call MetadataCalls `json:"call"` 27 Params []commonTypes.ExtrinsicParam `json:"params"` 28 Metadata *MetadataStruct 29 } 30 31 func (e *ExtrinsicDecoder) Init(data ScaleBytes, option *ScaleDecoderOption) { 32 if option == nil || option.Metadata == nil { 33 panic("ExtrinsicDecoder option metadata required") 34 } 35 e.Params = []commonTypes.ExtrinsicParam{} 36 e.Metadata = option.Metadata 37 e.ScaleDecoder.Init(data, option) 38 } 39 40 func (e *ExtrinsicDecoder) generateHash() string { 41 if !e.ContainsTransaction { 42 return "" 43 } 44 var extrinsicData []byte 45 if e.ExtrinsicLength > 0 { 46 extrinsicData = e.Data.Data 47 } else { 48 extrinsicLengthType := CompactU32{} 49 extrinsicLengthType.Encode(len(e.Data.Data)) 50 extrinsicData = append(extrinsicLengthType.Data.Data[:], e.Data.Data[:]...) 51 } 52 checksum, _ := blake2b.New(32, []byte{}) 53 _, _ = checksum.Write(extrinsicData) 54 h := checksum.Sum(nil) 55 return utiles.BytesToHex(h) 56 } 57 58 func (e *ExtrinsicDecoder) Process() { 59 e.ExtrinsicLength = e.ProcessAndUpdateData("Compact<u32>").(int) 60 if e.ExtrinsicLength != e.Data.GetRemainingLength() { 61 e.ExtrinsicLength = 0 62 e.Data.Reset() 63 } 64 65 e.VersionInfo = utiles.BytesToHex(e.NextBytes(1)) 66 67 e.ContainsTransaction = utiles.U256(e.VersionInfo).Int64() >= 80 68 69 result := map[string]interface{}{ 70 "extrinsic_length": e.ExtrinsicLength, 71 "version_info": e.VersionInfo, 72 } 73 74 if e.VersionInfo == "01" || e.VersionInfo == "81" { 75 76 if e.ContainsTransaction { 77 e.Address = e.ProcessAndUpdateData("Address").(string) 78 e.Signature = e.ProcessAndUpdateData("Signature").(string) 79 e.Nonce = e.ProcessAndUpdateData("Compact<u32>").(int) 80 e.Era = e.ProcessAndUpdateData("Era").(string) 81 e.ExtrinsicHash = e.generateHash() 82 } 83 e.CallIndex = utiles.BytesToHex(e.NextBytes(2)) 84 85 } else if e.VersionInfo == "02" || e.VersionInfo == "82" { 86 87 if e.ContainsTransaction { 88 e.Address = e.ProcessAndUpdateData("Address").(string) 89 e.Signature = e.ProcessAndUpdateData("Signature").(string) 90 e.Era = e.ProcessAndUpdateData("Era").(string) 91 e.Nonce = int(e.ProcessAndUpdateData("Compact<U64>").(uint64)) 92 e.Tip = e.ProcessAndUpdateData("Compact<Balance>").(decimal.Decimal) 93 e.ExtrinsicHash = e.generateHash() 94 } 95 e.CallIndex = utiles.BytesToHex(e.NextBytes(2)) 96 97 } else if e.VersionInfo == "03" || e.VersionInfo == "83" { 98 99 if e.ContainsTransaction { 100 e.Address = e.ProcessAndUpdateData("Address").(string) 101 e.Signature = e.ProcessAndUpdateData("Signature").(string) 102 e.Era = e.ProcessAndUpdateData("Era").(string) 103 e.Nonce = int(e.ProcessAndUpdateData("Compact<U64>").(uint64)) 104 e.Tip = e.ProcessAndUpdateData("Compact<Balance>").(decimal.Decimal) 105 e.ExtrinsicHash = e.generateHash() 106 } 107 e.CallIndex = utiles.BytesToHex(e.NextBytes(2)) 108 109 } else if e.VersionInfo == "04" || e.VersionInfo == "84" { 110 111 if e.ContainsTransaction { 112 113 address := e.ProcessAndUpdateData("Address") 114 switch v := address.(type) { 115 case string: 116 e.Address = v 117 result["address_type"] = "AccountId" 118 case map[string]interface{}: 119 for name, value := range v { 120 result["address_type"] = name 121 e.Address = value 122 } 123 } 124 e.SignatureVersion = e.ProcessAndUpdateData("U8").(int) 125 if e.SignatureVersion == 2 { 126 e.Signature = e.ProcessAndUpdateData("EcdsaSignature").(string) 127 } else { 128 e.Signature = e.ProcessAndUpdateData("Signature").(string) 129 } 130 e.Era = e.ProcessAndUpdateData("EraExtrinsic").(string) 131 e.Nonce = int(e.ProcessAndUpdateData("Compact<U64>").(uint64)) 132 if e.Metadata.Extrinsic != nil { 133 if utiles.SliceIndex("ChargeTransactionPayment", e.Metadata.Extrinsic.SignedExtensions) != -1 { 134 e.Tip = e.ProcessAndUpdateData("Compact<Balance>") 135 } 136 } else { 137 e.Tip = e.ProcessAndUpdateData("Compact<Balance>") 138 } 139 e.ExtrinsicHash = e.generateHash() 140 } 141 e.CallIndex = utiles.BytesToHex(e.NextBytes(2)) 142 } else { 143 panic(fmt.Sprintf("Extrinsics version %s is not support", e.VersionInfo)) 144 } 145 if e.CallIndex == "" { 146 panic("Not find Extrinsic Lookup, please check type registry") 147 } 148 149 call, ok := e.Metadata.CallIndex[e.CallIndex] 150 if !ok { 151 panic(fmt.Sprintf("Not find Extrinsic Lookup %s, please check metadata info", e.CallIndex)) 152 } 153 e.Call = call.Call 154 e.CallModule = call.Module 155 156 for _, arg := range e.Call.Args { 157 e.Params = append(e.Params, commonTypes.ExtrinsicParam{ 158 Name: arg.Name, 159 Type: arg.Type, 160 Value: e.ProcessAndUpdateData(arg.Type)}) 161 } 162 163 if e.ContainsTransaction { 164 result["account_id"] = e.Address 165 result["signature"] = e.Signature 166 result["nonce"] = e.Nonce 167 result["era"] = e.Era 168 result["extrinsic_hash"] = e.ExtrinsicHash 169 } 170 171 if e.CallIndex != "" { 172 result["call_code"] = e.CallIndex 173 result["call_module_function"] = e.Call.Name 174 result["call_module"] = e.CallModule.Name 175 } 176 177 result["nonce"] = e.Nonce 178 result["era"] = e.Era 179 result["tip"] = e.Tip 180 result["params"] = e.Params 181 e.Value = result 182 }