Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore (pkg/scale) scale babe integration #1670

Merged
merged 11 commits into from
Jul 6, 2021
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
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
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?

Copy link
Contributor Author

@jimjbrettj jimjbrettj Jul 5, 2021

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