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  }