Skip to content

Commit

Permalink
implement SubmitAndWatchEthExtrinsic
Browse files Browse the repository at this point in the history
  • Loading branch information
onexie committed Apr 24, 2024
1 parent 54dc72a commit 5c18e99
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
1 change: 1 addition & 0 deletions rpc/author/author.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

type Author interface {
SubmitAndWatchExtrinsic(xt types.Extrinsic) (*ExtrinsicStatusSubscription, error)
SubmitAndWatchEthExtrinsic(xt types.EthExtrinsic) (*ExtrinsicStatusSubscription, error)
PendingExtrinsics() ([]types.Extrinsic, error)
SubmitExtrinsic(xt types.Extrinsic) (types.Hash, error)
}
Expand Down
20 changes: 20 additions & 0 deletions rpc/author/submit_and_watch_extrinsic.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,23 @@ func (a *author) SubmitAndWatchExtrinsic(xt types.Extrinsic) (*ExtrinsicStatusSu

return &ExtrinsicStatusSubscription{sub: sub, channel: c}, nil
}

func (a *author) SubmitAndWatchEthExtrinsic(xt types.EthExtrinsic) (*ExtrinsicStatusSubscription, error) { //nolint:lll
ctx, cancel := context.WithTimeout(context.Background(), config.Default().SubscribeTimeout)
defer cancel()

c := make(chan types.ExtrinsicStatus)

enc, err := codec.EncodeToHex(xt)
if err != nil {
return nil, err
}

sub, err := a.client.Subscribe(ctx, "author", "submitAndWatchExtrinsic", "unwatchExtrinsic", "extrinsicUpdate",
c, enc)
if err != nil {
return nil, err
}

return &ExtrinsicStatusSubscription{sub: sub, channel: c}, nil
}
154 changes: 154 additions & 0 deletions types/extrinsic.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,160 @@ func (e Extrinsic) Encode(encoder scale.Encoder) error {
return nil
}

// NewEthExtrinsic creates a new EthExtrinsic from the provided Call
func NewEthExtrinsic(c Call) EthExtrinsic {
return EthExtrinsic{
Version: ExtrinsicVersion4,
Method: c,
}
}

// UnmarshalJSON fills Extrinsic with the JSON encoded byte array given by bz
func (e *EthExtrinsic) UnmarshalJSON(bz []byte) error {
var tmp string
if err := json.Unmarshal(bz, &tmp); err != nil {
return err
}

// HACK 11 Jan 2019 - before https://github.com/paritytech/substrate/pull/1388
// extrinsics didn't have the length, cater for both approaches. This is very
// inconsistent with any other `Vec<u8>` implementation
var l UCompact
err := codec.DecodeFromHex(tmp, &l)
if err != nil {
return err
}

prefix, err := codec.EncodeToHex(l)
if err != nil {
return err
}

// determine whether length prefix is there
if strings.HasPrefix(tmp, prefix) {
return codec.DecodeFromHex(tmp, e)
}

// not there, prepend with compact encoded length prefix
dec, err := codec.HexDecodeString(tmp)
if err != nil {
return err
}
length := NewUCompactFromUInt(uint64(len(dec)))
bprefix, err := codec.Encode(length)
if err != nil {
return err
}
bprefix = append(bprefix, dec...)
return codec.Decode(bprefix, e)
}

// MarshalJSON returns a JSON encoded byte array of Extrinsic
func (e EthExtrinsic) MarshalJSON() ([]byte, error) {
s, err := codec.EncodeToHex(e)
if err != nil {
return nil, err
}
return json.Marshal(s)
}

// IsSigned returns true if the extrinsic is signed
func (e EthExtrinsic) IsSigned() bool {
return e.Version&ExtrinsicBitSigned == ExtrinsicBitSigned
}

// Type returns the raw transaction version (not flagged with signing information)
func (e EthExtrinsic) Type() uint8 {
return e.Version & ExtrinsicUnmaskVersion
}

// Sign adds a signature to the extrinsic
func (e *EthExtrinsic) Sign(signer signature.KeyringPair, o SignatureOptions) error {
return nil
}

func (e *EthExtrinsic) Decode(decoder scale.Decoder) error {
// compact length encoding (1, 2, or 4 bytes) (may not be there for Extrinsics older than Jan 11 2019)
_, err := decoder.DecodeUintCompact()
if err != nil {
return err
}

// version, signature bitmask (1 byte)
err = decoder.Decode(&e.Version)
if err != nil {
return err
}

// signature
if e.IsSigned() {
if e.Type() != ExtrinsicVersion4 {
return fmt.Errorf("unsupported extrinsic version: %v (isSigned: %v, type: %v)", e.Version, e.IsSigned(),
e.Type())
}

err = decoder.Decode(&e.Signature)
if err != nil {
return err
}
}

// call
err = decoder.Decode(&e.Method)
if err != nil {
return err
}

return nil
}

func (e EthExtrinsic) Encode(encoder scale.Encoder) error {
if e.Type() != ExtrinsicVersion4 {
return fmt.Errorf("unsupported extrinsic version: %v (isSigned: %v, type: %v)", e.Version, e.IsSigned(),
e.Type())
}

// create a temporary buffer that will receive the plain encoded transaction (version, signature (optional),
// method/call)
var bb = bytes.Buffer{}
tempEnc := scale.NewEncoder(&bb)

// encode the version of the extrinsic
err := tempEnc.Encode(e.Version)
if err != nil {
return err
}

// encode the signature if signed
if e.IsSigned() {
err = tempEnc.Encode(e.Signature)
if err != nil {
return err
}
}

// encode the method
err = tempEnc.Encode(e.Method)
if err != nil {
return err
}

// take the temporary buffer to determine length, write that as prefix
eb := bb.Bytes()
err = encoder.EncodeUintCompact(*big.NewInt(0).SetUint64(uint64(len(eb))))
if err != nil {
return err
}

// write the actual encoded transaction
err = encoder.Write(eb)
if err != nil {
return err
}

return nil
}

// Call is the extrinsic function descriptor
type Call struct {
CallIndex CallIndex
Expand Down

0 comments on commit 5c18e99

Please sign in to comment.