Skip to content

Commit

Permalink
extrinsic: Add more comments
Browse files Browse the repository at this point in the history
  • Loading branch information
cdamian committed Jul 3, 2024
1 parent e972ab6 commit c825e9f
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 15 deletions.
15 changes: 10 additions & 5 deletions types/extrinsic/extrinsic.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,27 @@ import (
"math/big"
)

// DynamicExtrinsic is an extrinsic type that can be used on chains that
// have a custom signed extension logic.
type DynamicExtrinsic struct {
// Version is the encoded version flag (which encodes the raw transaction version and signing information in one byte)
Version byte
// Version is the encoded version flag (which encodes the raw transaction version
// and signing information in one byte).
Version byte
// Signature is the extrinsic signature.
Signature *Signature
// Method is the call this extrinsic wraps
Method *types.Call
}

// NewExtrinsic creates a new Extrinsic from the provided Call
// NewDynamicExtrinsic creates a new DynamicExtrinsic from the provided Call.
func NewDynamicExtrinsic(c *types.Call) DynamicExtrinsic {
return DynamicExtrinsic{
Version: types.ExtrinsicVersion4,
Method: c,
}
}

// MarshalJSON returns a JSON encoded byte array of Extrinsic
// MarshalJSON returns a JSON encoded byte array of DynamicExtrinsic.
func (e DynamicExtrinsic) MarshalJSON() ([]byte, error) {
s, err := codec.EncodeToHex(e)
if err != nil {
Expand All @@ -46,7 +50,7 @@ func (e DynamicExtrinsic) Type() uint8 {
return e.Version & types.ExtrinsicUnmaskVersion
}

// Sign adds a signature to the extrinsic
// Sign adds a signature to the extrinsic.
func (e *DynamicExtrinsic) Sign(signer signature.KeyringPair, meta *types.Metadata, opts ...SigningOption) error {
if e.Type() != types.ExtrinsicVersion4 {
return fmt.Errorf("unsupported extrinsic version: %v (isSigned: %v, type: %v)", e.Version, e.IsSigned(), e.Type())
Expand Down Expand Up @@ -103,6 +107,7 @@ func (e DynamicExtrinsic) Encode(encoder scale.Encoder) error {
return fmt.Errorf("unsupported extrinsic version: %v (isSigned: %v, type: %v)", e.Version, e.IsSigned(),
e.Type())
}

var bb = bytes.Buffer{}
tempEnc := scale.NewEncoder(&bb)

Expand Down
9 changes: 9 additions & 0 deletions types/extrinsic/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,57 @@ import (
"github.com/centrifuge/go-substrate-rpc-client/v4/types/extrinsic/extensions"
)

// SignedFieldValues is a map that holds a value for a particular SignedFieldName.
type SignedFieldValues map[SignedFieldName]any

// SigningOption is the type used for providing values to a SignedFieldValues map.
type SigningOption func(vals SignedFieldValues)

// WithEra returns a SigningOption that is used to add the era and block hash to a Payload.
func WithEra(era types.ExtrinsicEra, blockHash types.Hash) SigningOption {
return func(vals SignedFieldValues) {
vals[EraSignedField] = era
vals[BlockHashSignedField] = blockHash
}
}

// WithNonce returns a SigningOption that is used to add the nonce to a Payload.
func WithNonce(nonce types.UCompact) SigningOption {
return func(vals SignedFieldValues) {
vals[NonceSignedField] = nonce
}
}

// WithMetadataMode returns a SigningOption that is used to add the check metadata mode and hash to a Payload.
func WithMetadataMode(mode extensions.CheckMetadataMode, metadataHash extensions.CheckMetadataHash) SigningOption {
return func(vals SignedFieldValues) {
vals[CheckMetadataHashModeSignedField] = mode
vals[CheckMetadataHashSignedField] = metadataHash
}
}

// WithTip returns a SigningOption that is used to add the tip to a Payload.
func WithTip(tip types.UCompact) SigningOption {
return func(vals SignedFieldValues) {
vals[TipSignedField] = tip
}
}

// WithSpecVersion returns a SigningOption that is used to add the spec version to a Payload.
func WithSpecVersion(specVersion types.U32) SigningOption {
return func(vals SignedFieldValues) {
vals[SpecVersionSignedField] = specVersion
}
}

// WithTransactionVersion returns a SigningOption that is used to add the transaction version to a Payload.
func WithTransactionVersion(transactionVersion types.U32) SigningOption {
return func(vals SignedFieldValues) {
vals[TransactionVersionSignedField] = transactionVersion
}
}

// WithGenesisHash returns a SigningOption that is used to add the genesis hash to a Payload.
func WithGenesisHash(genesisHash types.Hash) SigningOption {
return func(vals SignedFieldValues) {
vals[GenesisHashSignedField] = genesisHash
Expand Down
28 changes: 26 additions & 2 deletions types/extrinsic/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,33 @@ import (
"github.com/centrifuge/go-substrate-rpc-client/v4/types/extrinsic/extensions"
)

// SignedField represents a field used in the Payload.
type SignedField struct {
Name SignedFieldName
Value any
// Name of the field, this is omitted when the extrinsic is signed.
Name SignedFieldName

// Value of the field used when the extrinsic is signed.
Value any

// Mutated is used to keep track of changes done to the field.
Mutated bool
}

// Payload holds the encoded types.Call and the fields that are used for generating
// the DynamicExtrinsic payload and signature.
//
// Notes - the ordering of the SignedFields and SignedExtraFields is the order in which they are provided in
// the metadata.
type Payload struct {
EncodedCall types.BytesBare
SignedFields []*SignedField
SignedExtraFields []*SignedField
}

// Encode the call bytes and the signed fields in the order that is provided during creation
// from the metadata.
//
// The function also performs an extra check to ensure that all required fields were mutated.
func (p *Payload) Encode(encoder scale.Encoder) error {
if err := encoder.Encode(p.EncodedCall); err != nil {
return fmt.Errorf("unable to encode method: %w", err)
Expand Down Expand Up @@ -51,6 +66,8 @@ func (p *Payload) Encode(encoder scale.Encoder) error {
return nil
}

// MutateSignedFields is mutating the payload's SignedFields and SignedExtraFields
// based on the provided SignedFieldValues.
func (p *Payload) MutateSignedFields(vals SignedFieldValues) error {
if p == nil {
return errors.New("payload is nil")
Expand Down Expand Up @@ -92,6 +109,7 @@ func (p *Payload) Sign(signer signature.KeyringPair) (types.Signature, error) {
return types.NewSignature(sig), err
}

// SignedFieldName is the type used for representing a field name.
type SignedFieldName string

const (
Expand All @@ -107,8 +125,10 @@ const (
GenesisHashSignedField SignedFieldName = "genesis_hash"
)

// PayloadMutatorFn is the type used for mutating the Payload during creation.
type PayloadMutatorFn func(payload *Payload)

// PayloadMutatorFns is a map that holds a PayloadMutatorFn for each supported signed extension.
var PayloadMutatorFns = map[extensions.SignedExtensionName]PayloadMutatorFn{
extensions.CheckMortalitySignedExtension: func(payload *Payload) {
payload.SignedFields = append(payload.SignedFields, &SignedField{
Expand Down Expand Up @@ -187,6 +207,10 @@ var PayloadMutatorFns = map[extensions.SignedExtensionName]PayloadMutatorFn{
extensions.PreBalanceTransferExtensionSignedExtension: func(payload *Payload) {},
}

// createPayload iterates over all signed extensions provided in the metadata and
// attempts to load and use a PayloadMutatorFn for each one.
//
// If a PayloadMutatorFn is not found for a specific signed extension, it means that it is not currently supported.
func createPayload(meta *types.Metadata, encodedCall []byte) (*Payload, error) {
payload := &Payload{
EncodedCall: encodedCall,
Expand Down
13 changes: 5 additions & 8 deletions types/extrinsic/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ import (
"github.com/centrifuge/go-substrate-rpc-client/v4/types"
)

// Signature holds all the relevant fields for an extrinsic signature.
type Signature struct {
Signer types.MultiAddress
Signature types.MultiSignature
SignedFields []*SignedField
}

// Encode is encoding the Signer, Signature, and SignedFields.
//
// Note - the ordering of the SignedFields is the order in which they are provided in
// the metadata.
func (s Signature) Encode(encoder scale.Encoder) error {
if err := encoder.Encode(s.Signer); err != nil {
return err
Expand All @@ -29,11 +34,3 @@ func (s Signature) Encode(encoder scale.Encoder) error {

return nil
}

func createSignature(signer types.MultiAddress, sig types.MultiSignature, signedFields []*SignedField) *Signature {
return &Signature{
Signer: signer,
Signature: sig,
SignedFields: signedFields,
}
}

0 comments on commit c825e9f

Please sign in to comment.