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

feat(runtime): implement ParachainHost_para_backing_state runtime call #4420

Open
wants to merge 12 commits into
base: feat/parachain
Choose a base branch
from
Open
73 changes: 73 additions & 0 deletions dot/parachain/types/async_backing.go
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,76 @@ type AsyncBackingParams struct {
// When async backing is disabled, the only valid value is 0.
AllowedAncestryLen uint32 `scale:"2"`
}

// InboundHRMPLimitations constraints on inbound HRMP channels.
type InboundHRMPLimitations struct {
// An exhaustive set of all valid watermarks, sorted ascending.
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
//
// It's only expected to contain block numbers at which messages were
// previously sent to a para, excluding most recent head.
ValidWatermarks []BlockNumber
}

// OutboundHRMPChannelLimitations constraints on outbound HRMP channels.
type OutboundHRMPChannelLimitations struct {
// The maximum bytes that can be written to the channel.
BytesRemaining uint32
// The maximum messages that can be written to the channel.
MessagesRemaining uint32
}

// Constraints on the actions that can be taken by a new parachain block. These
// limitations are implicitly associated with some particular parachain, which should
// be apparent from usage.
type Constraints struct {
// The minimum relay-parent number accepted under these constraints.
MinRelayParentNumber BlockNumber
// The maximum Proof-of-Validity size allowed, in bytes.
MaxPoVSize uint32
// The maximum new validation code size allowed, in bytes.
MaxCodeSize uint32
// The amount of UMP messages remaining.
UmpRemaining uint32
// The amount of UMP bytes remaining.
UmpRemainingBytes uint32
// The maximum number of UMP messages allowed per candidate.
MaxUmpNumPerCandidate uint32
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
// Remaining DMP queue. Only includes sent-at block numbers.
DmpRemainingMessages []uint32
// The limitations of all registered inbound HRMP channels.
HrmpInbound InboundHRMPLimitations
// The limitations of all registered outbound HRMP channels.
HrmpChannelsOut map[ParaID]OutboundHRMPChannelLimitations
// The maximum number of HRMP messages allowed per candidate.
MaxHrmpNumPerCandidate uint32
// The required parent head-data of the parachain.
RequiredParent HeadData
// The expected validation-code-hash of this parachain.
ValidationCodeHash ValidationCodeHash
// The code upgrade restriction signal as-of this parachain.
UpgradeRestriction *UpgradeRestriction
// The future validation code hash, if any, and at what relay-parent
// number the upgrade would be minimally applied.
FutureValidationCode *FutureValidationCode
}

// FutureValidationCode represents a tuple of BlockNumber and ValidationCodeHash
type FutureValidationCode struct {
BlockNumber BlockNumber
ValidationCodeHash ValidationCodeHash
}

type CandidatePendingAvailability struct {
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
CandidateHash CandidateHash
Descriptor CandidateDescriptorV2
Commitments CandidateCommitments
RelayParentNumber BlockNumber
MaxPoVSize uint32
}

// BackingState holds the state of the backing system per-parachain, including
// state-machine constraints and candidates pending availability
type BackingState struct {
Constraints Constraints
PendingAvailability []CandidatePendingAvailability
}
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
83 changes: 83 additions & 0 deletions dot/parachain/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,39 @@ func (cd CandidateDescriptor) CheckCollatorSignature() error {
return sr25519.VerifySignature(cd.Collator[:], cd.Signature[:], payload)
}

type CandidateDescriptorV2 struct {
// The ID of the para this is a candidate for.
ParaID ParaID
// RelayParent is the hash of the relay-chain block this should be executed in
// the context of.
RelayParent common.Hash
// Version field. The raw value here is not exposed, instead it is used
// to determine the `CandidateDescriptorVersion`, see `fn version()`.
// For the current version this field is set to `0` and will be incremented
// by next versions.
Version uint8
// The core index where the candidate is backed.
CoreIndex uint16
axaysagathiya marked this conversation as resolved.
Show resolved Hide resolved
// The session index of the candidate relay parent.
SessionIndex SessionIndex
// Reserved bytes.
Reserved1 [25]uint8
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we give better naming/descriptions to the two differed reserved bytes fields here?

Copy link
Member Author

Choose a reason for hiding this comment

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

in the RFC they call them as reserved, that's because they want to be compatible with the V1 as they changed some fields, but in their code they just used reserved and does not have future plans for them

// PersistedValidationDataHash is the blake2-256 hash of the persisted validation data. This is extra data derived from
// relay-chain state which may vary based on bitfields included before the candidate.
// Thus, it cannot be derived entirely from the relay-parent.
PersistedValidationDataHash common.Hash
// PovHash is the hash of the `pov-block`.
PovHash common.Hash
// ErasureRoot is the root of a block's erasure encoding Merkle tree.
ErasureRoot common.Hash
// Reserved bytes.
Reserved2 [64]uint8
// ParaHead is the hash of the para header that is being generated by this candidate.
ParaHead common.Hash
// ValidationCodeHash is the blake2-256 hash of the validation code bytes.
ValidationCodeHash ValidationCodeHash
}

// OccupiedCore Information about a core which is currently occupied.
type OccupiedCore struct {
// NOTE: this has no ParaId as it can be deduced from the candidate descriptor.
Expand Down Expand Up @@ -740,6 +773,56 @@ type Subsystem interface {
Stop()
}

// Present is a variant of UpgradeRestriction enumerator that signals
// a upgrade restriction is present and there are no details about its
// specifics nor how long it could last
type Present struct{}

// UpgradeRestriction a possible restriction that prevents a parachain
// from performing an upgrade
type UpgradeRestriction struct {
EclesioMeloJunior marked this conversation as resolved.
Show resolved Hide resolved
inner any
}

type UpgradeRestrictionValues interface {
Present
}

func setMyVaryingDataType[Value UpgradeRestrictionValues](mvdt *UpgradeRestriction, value Value) {
mvdt.inner = value
}

func (mvdt *UpgradeRestriction) SetValue(value any) (err error) {
switch value := value.(type) {
case Present:
setMyVaryingDataType(mvdt, value)
return
default:
return fmt.Errorf("unsupported type")
}
}

func (mvdt UpgradeRestriction) IndexValue() (index uint, value any, err error) {
switch mvdt.inner.(type) {
case Present:
return 0, mvdt.inner, nil
}
return 0, nil, scale.ErrUnsupportedVaryingDataTypeValue
}

func (mvdt UpgradeRestriction) Value() (value any, err error) {
_, value, err = mvdt.IndexValue()
return
}

func (mvdt UpgradeRestriction) ValueAt(index uint) (value any, err error) {
switch index {
case 0:
return Present{}, nil
}
return nil, scale.ErrUnknownVaryingDataTypeValue
}

// CandidateHashAndRelayParent is a pair of candidate hash and relay parent hash
type CandidateHashAndRelayParent struct {
CandidateHash CandidateHash
Expand Down
12 changes: 12 additions & 0 deletions dot/parachain/types/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,15 @@ func TestOccupiedCoreAssumption(t *testing.T) {
})
}
}

func TestUpgradeRestrictionEncodingDecoding(t *testing.T) {
presentVariant := []byte{0}
var restriction UpgradeRestriction

require.NoError(t, scale.Unmarshal(presentVariant, &restriction))

expectedRestriction := &UpgradeRestriction{}
require.NoError(t, expectedRestriction.SetValue(Present{}))

require.Equal(t, expectedRestriction, &restriction)
}
6 changes: 6 additions & 0 deletions lib/runtime/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ const (
WESTEND_RUNTIME_V190_FP = "westend_runtime-v190.compact.wasm"
WESTEND_RUNTIME_V190_URL = "https://github.com/paritytech/polkadot-sdk/releases/download/" +
"polkadot-v1.9.0/westend_runtime.compact.compressed.wasm?raw=true"

WESTEND_RUNTIME_v1017001 = "westend_runtime-v1017000"
WESTEND_RUNTIME_v1017001_FP = "westend_runtime-v1017000.compact.wasm"
WESTEND_RUNTIME_v1017001_URL = "https://github.com/paritytech/polkadot-sdk/releases/download/" +
"polkadot-stable2412/westend_runtime.compact.compressed.wasm?raw=true"
)

const (
Expand Down Expand Up @@ -108,4 +113,5 @@ const (
ParachainHostMinimumBackingVotes = "ParachainHost_minimum_backing_votes"
// ParachainHostSessionExecutorParams is the runtime API call ParachainHost_session_executor_params
ParachainHostSessionExecutorParams = "ParachainHost_session_executor_params"
ParachainHostParaBackingState = "ParachainHost_para_backing_state"
)
3 changes: 3 additions & 0 deletions lib/runtime/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ func GetRuntime(ctx context.Context, runtime string) (
case WESTEND_RUNTIME_v190:
runtimeFilename = WESTEND_RUNTIME_V190_FP
url = WESTEND_RUNTIME_V190_URL
case WESTEND_RUNTIME_v1017001:
runtimeFilename = WESTEND_RUNTIME_v1017001_FP
url = WESTEND_RUNTIME_v1017001_URL
default:
return "", fmt.Errorf("%w: %s", ErrRuntimeUnknown, runtime)
}
Expand Down
13 changes: 9 additions & 4 deletions lib/runtime/wazero/imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ChainSafe/gossamer/pkg/trie/inmemory/proof"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tetratelabs/wazero"
)

var DefaultVersion = &runtime.Version{
Expand Down Expand Up @@ -910,29 +911,33 @@ func Test_ext_misc_runtime_version_version_1(t *testing.T) {
}
}

mod, err := inst.Runtime.InstantiateModule(
context.Background(), inst.metadata.guestModule, wazero.NewModuleConfig())
require.NoError(t, err)

allocator := allocator.NewFreeingBumpHeapAllocator(0)
inst.Context.Allocator = allocator

data := bytes
dataLength := uint32(len(data))
inputPtr, err := inst.Context.Allocator.Allocate(inst.Module.Memory(), dataLength)
inputPtr, err := inst.Context.Allocator.Allocate(mod.Memory(), dataLength)
if err != nil {
t.Errorf("allocating input memory: %v", err)
}

// Store the data into memory
mem := inst.Module.Memory()
mem := mod.Memory()
ok := mem.Write(inputPtr, data)
if !ok {
panic("write overlow")
}

dataSpan := newPointerSize(inputPtr, dataLength)
ctx := context.WithValue(context.Background(), runtimeContextKey, inst.Context)
versionPtr := ext_misc_runtime_version_version_1(ctx, inst.Module, dataSpan)
versionPtr := ext_misc_runtime_version_version_1(ctx, mod, dataSpan)

var option *[]byte
versionData := read(inst.Module, versionPtr)
versionData := read(mod, versionPtr)
err = scale.Unmarshal(versionData, &option)
require.NoError(t, err)
require.NotNil(t, option)
Expand Down
40 changes: 27 additions & 13 deletions lib/runtime/wazero/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ type wazeroMeta struct {
// Instance backed by wazero.Runtime
type Instance struct {
Runtime wazero.Runtime
Module api.Module
Context *runtime.Context
wasmByteCode []byte
codeHash common.Hash
Expand Down Expand Up @@ -115,7 +114,7 @@ func NewInstanceFromTrie(t trie.Trie, cfg Config) (*Instance, error) {
func newRuntime(ctx context.Context,
code []byte,
config wazero.RuntimeConfig,
) (api.Module, wazero.Runtime, wazero.CompiledModule, error) {
) (wazero.Runtime, wazero.CompiledModule, error) {
rt := wazero.NewRuntimeWithConfig(ctx, config)

const i32, i64 = api.ValueTypeI32, api.ValueTypeI64
Expand Down Expand Up @@ -645,29 +644,25 @@ func newRuntime(ctx context.Context,
Compile(ctx)

if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

_, err = rt.InstantiateModule(ctx, hostCompiledModule, wazero.NewModuleConfig())
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

code, err = decompressWasm(code)
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

guestCompiledModule, err := rt.CompileModule(ctx, code)
if err != nil {
return nil, nil, nil, err
}
mod, err := rt.Instantiate(ctx, code)
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

return mod, rt, guestCompiledModule, nil
return rt, guestCompiledModule, nil
}

// NewInstance instantiates a runtime from raw wasm bytecode
Expand All @@ -679,7 +674,7 @@ func NewInstance(code []byte, cfg Config) (instance *Instance, err error) {
ctx := context.Background()
cache := wazero.NewCompilationCache()
config := wazero.NewRuntimeConfig().WithCompilationCache(cache)
mod, rt, guestCompiledModule, err := newRuntime(ctx, code, config)
rt, guestCompiledModule, err := newRuntime(ctx, code, config)
if err != nil {
return nil, fmt.Errorf("creating runtime instance: %w", err)
}
Expand All @@ -696,7 +691,6 @@ func NewInstance(code []byte, cfg Config) (instance *Instance, err error) {
SigVerifier: crypto.NewSignatureVerifier(logger),
OffchainHTTPSet: offchain.NewHTTPSet(),
},
Module: mod,
codeHash: cfg.CodeHash,
metadata: wazeroMeta{
config: config,
Expand Down Expand Up @@ -1420,6 +1414,26 @@ func (in *Instance) ParachainHostSessionExecutorParams(index parachaintypes.Sess
return &params, nil
}

func (in *Instance) ParachainHostParaBackingState(paraID parachaintypes.ParaID) (*parachaintypes.BackingState, error) {
encodedParaID, err := scale.Marshal(paraID)
if err != nil {
return nil, fmt.Errorf("encoding parachain ID: %w", err)
}

encodedBackingState, err := in.Exec(runtime.ParachainHostParaBackingState, encodedParaID)
if err != nil {
return nil, fmt.Errorf("exec: %w", err)
}

var backingState *parachaintypes.BackingState
err = scale.Unmarshal(encodedBackingState, &backingState)
if err != nil {
return nil, fmt.Errorf("unmarshalling backing state: %w", err)
}

return backingState, nil
}

func (*Instance) RandomSeed() {
panic("unimplemented")
}
Expand Down
Loading
Loading