Skip to content
23 changes: 15 additions & 8 deletions lib/babe/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import (
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/runtime"
"github.com/ChainSafe/gossamer/lib/scale"
"github.com/ChainSafe/gossamer/lib/transaction"
"github.com/ChainSafe/gossamer/pkg/scale"
)

const (
Expand Down Expand Up @@ -305,14 +305,15 @@ func (b *BlockBuilder) buildBlockInherents(slot Slot) ([][]byte, error) {
}

// decode inherent extrinsics
exts, err := scale.Decode(inherentExts, [][]byte{})
var exts [][]byte
err = scale.Unmarshal(inherentExts, &exts)
if err != nil {
return nil, err
}

// apply each inherent extrinsic
for _, ext := range exts.([][]byte) {
in, err := scale.Encode(ext)
for _, ext := range exts {
in, err := scale.Marshal(ext)
if err != nil {
return nil, err
}
Expand All @@ -328,7 +329,7 @@ func (b *BlockBuilder) buildBlockInherents(slot Slot) ([][]byte, error) {
}
}

return exts.([][]byte), nil
return exts, nil
}

func (b *BlockBuilder) addToQueue(txs []*transaction.ValidTransaction) {
Expand All @@ -352,12 +353,18 @@ func ExtrinsicsToBody(inherents [][]byte, txs []*transaction.ValidTransaction) (
extrinsics := types.BytesArrayToExtrinsics(inherents)

for _, tx := range txs {
decExt, err := scale.Decode(tx.Extrinsic, []byte{})
var decExt []byte
err := scale.Unmarshal(tx.Extrinsic, &decExt)
if err != nil {
return nil, err
}
extrinsics = append(extrinsics, decExt.([]byte))
extrinsics = append(extrinsics, decExt)
}

return types.NewBodyFromExtrinsics(extrinsics)
enc, err := scale.Marshal(extrinsics)
if err != nil {
return nil, err
}
body := types.Body(enc)
return &body, nil
}
7 changes: 4 additions & 3 deletions lib/babe/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto/sr25519"
"github.com/ChainSafe/gossamer/lib/scale"
"github.com/ChainSafe/gossamer/lib/transaction"
"github.com/ChainSafe/gossamer/pkg/scale"
log "github.com/ChainSafe/log15"
cscale "github.com/centrifuge/go-substrate-rpc-client/v2/scale"
"github.com/centrifuge/go-substrate-rpc-client/v2/signature"
Expand Down Expand Up @@ -223,11 +223,12 @@ func TestBuildAndApplyExtrinsic(t *testing.T) {
// build extrinsic
rawMeta, err := babeService.rt.Metadata()
require.NoError(t, err)
decoded, err := scale.Decode(rawMeta, []byte{})
var decoded []byte
err = scale.Unmarshal(rawMeta, []byte{})
require.NoError(t, err)

meta := &ctypes.Metadata{}
err = ctypes.DecodeFromBytes(decoded.([]byte), meta)
err = ctypes.DecodeFromBytes(decoded, meta)
require.NoError(t, err)

rv, err := babeService.rt.Version()
Expand Down
253 changes: 192 additions & 61 deletions lib/babe/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import (
"errors"
"fmt"

"github.com/ChainSafe/gossamer/lib/common/optional"
"github.com/ChainSafe/gossamer/lib/scale"
"github.com/ChainSafe/gossamer/pkg/scale"
)

var (
Expand Down Expand Up @@ -81,88 +80,220 @@ func (e TransactionValidityError) Error() string {
return fmt.Sprintf("transaction validity error: %s", e.msg)
}

func determineCustomModuleErr(res []byte) error {
if len(res) < 3 {
return errInvalidResult
}
errMsg, err := optional.NewBytes(false, nil).DecodeBytes(res[2:])
if err != nil {
return err
}
return fmt.Errorf("index: %d code: %d message: %s", res[0], res[1], errMsg.String())
// A UnmarshalError is when unmarshalling fails
type UnmarshalError struct {
msg string
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// A UnmarshalError is when unmarshalling fails
type UnmarshalError struct {
msg string
}
// UnmarshalError occurs when unmarshalling fails
type UnmarshalError struct {
msg string
}


func determineDispatchErr(res []byte) error {
switch res[0] {
case 0:
unKnownError, _ := scale.Decode(res[1:], []byte{})
return &DispatchOutcomeError{fmt.Sprintf("unknown error: %s", string(unKnownError.([]byte)))}
case 1:
return &DispatchOutcomeError{"failed lookup"}
case 2:
return &DispatchOutcomeError{"bad origin"}
case 3:
return &DispatchOutcomeError{fmt.Sprintf("custom module error: %s", determineCustomModuleErr(res[1:]))}
}
return errInvalidResult
func (e UnmarshalError) Error() string {
return fmt.Sprintf("unmarshal error: %s", e.msg)
}

// Other Some error occurred
type Other string

// Index Returns VDT index
func (err Other) Index() uint { return 0 }

// CannotLookup Failed to lookup some data
type CannotLookup struct{}

// Index Returns VDT index
func (err CannotLookup) Index() uint { return 1 }

// BadOrigin A bad origin
type BadOrigin struct{}

// Index Returns VDT index
func (err BadOrigin) Index() uint { return 2 }

// Module A custom error in a module
type Module struct {
Idx uint8
Err uint8
Message *string
}

func determineInvalidTxnErr(res []byte) error {
switch res[0] {
case 0:
// Index Returns VDT index
func (err Module) Index() uint { return 3 }

func (err Module) string() string {
return fmt.Sprintf("index: %d code: %d message: %x", err.Idx, err.Err, *err.Message)
}

// ValidityCannotLookup Could not lookup some information that is required to validate the transaction
type ValidityCannotLookup struct{}

// Index Returns VDT index
func (err ValidityCannotLookup) Index() uint { return 0 }

// NoUnsignedValidator No validator found for the given unsigned transaction
type NoUnsignedValidator struct{}

// Index Returns VDT index
func (err NoUnsignedValidator) Index() uint { return 1 }

// UnknownCustom Any other custom unknown validity that is not covered
type UnknownCustom uint8

// Index Returns VDT index
func (err UnknownCustom) Index() uint { return 2 }

// Call The call of the transaction is not expected
type Call struct{}

// Index Returns VDT index
func (err Call) Index() uint { return 0 }

// Payment General error to do with the inability to pay some fees (e.g. account balance too low)
type Payment struct{}

// Index Returns VDT index
func (err Payment) Index() uint { return 1 }

// Future General error to do with the transaction not yet being valid (e.g. nonce too high)
type Future struct{}

// Index Returns VDT index
func (err Future) Index() uint { return 2 }

// Stale General error to do with the transaction being outdated (e.g. nonce too low)
type Stale struct{}

// Index Returns VDT index
func (err Stale) Index() uint { return 3 }

// BadProof General error to do with the transaction’s proofs (e.g. signature)
type BadProof struct{}

// Index Returns VDT index
func (err BadProof) Index() uint { return 4 }

// AncientBirthBlock The transaction birth block is ancient
type AncientBirthBlock struct{}

// Index Returns VDT index
func (err AncientBirthBlock) Index() uint { return 5 }

// ExhaustsResources The transaction would exhaust the resources of current block
type ExhaustsResources struct{}

// Index Returns VDT index
func (err ExhaustsResources) Index() uint { return 6 }

// InvalidCustom Any other custom invalid validity that is not covered
type InvalidCustom uint8

// Index Returns VDT index
func (err InvalidCustom) Index() uint { return 7 }

// BadMandatory An extrinsic with a Mandatory dispatch resulted in Error
type BadMandatory struct{}

// Index Returns VDT index
func (err BadMandatory) Index() uint { return 8 }

// MandatoryDispatch A transaction with a mandatory dispatch
type MandatoryDispatch struct{}

// Index Returns VDT index
func (err MandatoryDispatch) Index() uint { return 9 }

func determineErrType(vdt scale.VaryingDataType) error {
switch val := vdt.Value().(type) {
case Other:
return &DispatchOutcomeError{fmt.Sprintf("unknown error: %s", val)}
case CannotLookup:
return &DispatchOutcomeError{"failed lookup"}
case BadOrigin:
return &DispatchOutcomeError{"bad origin"}
case Module:
return &DispatchOutcomeError{fmt.Sprintf("custom module error: %s", val.string())}
case Call:
return &TransactionValidityError{"call of the transaction is not expected"}
case 1:
case Payment:
return &TransactionValidityError{"invalid payment"}
case 2:
case Future:
return &TransactionValidityError{"invalid transaction"}
case 3:
case Stale:
return &TransactionValidityError{"outdated transaction"}
case 4:
case BadProof:
return &TransactionValidityError{"bad proof"}
case 5:
case AncientBirthBlock:
return &TransactionValidityError{"ancient birth block"}
case 6:
case ExhaustsResources:
return &TransactionValidityError{"exhausts resources"}
case 7:
return &TransactionValidityError{fmt.Sprintf("unknown error: %d", res[1])}
case 8:
case InvalidCustom:
return &TransactionValidityError{fmt.Sprintf("unknown error: %d", val)}
case BadMandatory:
return &TransactionValidityError{"mandatory dispatch error"}
case 9:
case MandatoryDispatch:
return &TransactionValidityError{"invalid mandatory dispatch"}
}
return errInvalidResult
}

func determineUnknownTxnErr(res []byte) error {
switch res[0] {
case 0:
case ValidityCannotLookup:
return &TransactionValidityError{"lookup failed"}
case 1:
case NoUnsignedValidator:
return &TransactionValidityError{"validator not found"}
case 2:
return &TransactionValidityError{fmt.Sprintf("unknown error: %d", res[1])}
case UnknownCustom:
return &TransactionValidityError{fmt.Sprintf("unknown error: %d", val)}
}

return errInvalidResult
}

func determineErr(res []byte) error {
switch res[0] {
case 0: // DispatchOutcome
switch res[1] {
case 0:
return nil
case 1:
return determineDispatchErr(res[2:])
var other Other
var invalidCustom InvalidCustom
var unknownCustom UnknownCustom

dispatchError := scale.MustNewVaryingDataType(other, CannotLookup{}, BadOrigin{}, Module{})
invalid := scale.MustNewVaryingDataType(Call{}, Payment{}, Future{}, Stale{}, BadProof{}, AncientBirthBlock{},
ExhaustsResources{}, invalidCustom, BadMandatory{}, MandatoryDispatch{})
unknown := scale.MustNewVaryingDataType(ValidityCannotLookup{}, NoUnsignedValidator{}, unknownCustom)

okRes := scale.NewResult(nil, dispatchError)
errRes := scale.NewResult(invalid, unknown)
result := scale.NewResult(okRes, errRes)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these could be declared as package vars since they wouldn't ever change?

@jimjbrettj jimjbrettj Jul 5, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup you are right, will do. I will just have to declare the custom string types there as well (like other and invalidCustom)


err := scale.Unmarshal(res, &result)
if err != nil {
return &UnmarshalError{err.Error()}
}

ok, err := result.Unwrap()
if err != nil {
switch o := err.(type) {
case scale.WrappedErr:
errResult := o.Err.(scale.Result)
ok, err = errResult.Unwrap()
if err != nil {
switch err := err.(type) {
case scale.WrappedErr:
return determineErrType(err.Err.(scale.VaryingDataType))
default:
return errInvalidResult
}
} else {
return determineErrType(ok.(scale.VaryingDataType))
}
default:
return errInvalidResult
}
case 1: // TransactionValidityError
switch res[1] {
case 0:
return determineInvalidTxnErr(res[2:])
case 1:
return determineUnknownTxnErr(res[2:])
} else {
switch o := ok.(type) {
case scale.Result:
_, err = o.Unwrap()
if err != nil {
switch err := err.(type) {
case scale.WrappedErr:
return determineErrType(err.Err.(scale.VaryingDataType))
default:
return errInvalidResult
}
} else {
return nil
}
default:
return errInvalidResult
}
}
return errInvalidResult
}
10 changes: 10 additions & 0 deletions lib/babe/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ func TestApplyExtrinsicErrors(t *testing.T) {
test: []byte{0, 1, 0, 0x04, 65},
expected: "dispatch outcome error: unknown error: A",
},
{
name: "Dispatch failed lookup",
test: []byte{0, 1, 1},
expected: "dispatch outcome error: failed lookup",
},
{
name: "Dispatch bad origin",
test: []byte{0, 1, 2},
expected: "dispatch outcome error: bad origin",
},
{
name: "Invalid txn payment error",
test: []byte{1, 0, 1},
Expand Down
Loading