-
Notifications
You must be signed in to change notification settings - Fork 5
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: Migrate from substrate to polkadot-sdk repo + Implement genesis builder #313
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
4435672
add polkadot-sdk submodule
tgntr b66dd08
remove substrate submodule
tgntr 8fe8976
init GenesisBuilder
tgntr 4093402
WIP implement genesis builder
tgntr c46d480
replace polkadot-sdk with fork
tgntr 7b0be17
wip ss58 decoding when building aura authorities
tgntr ea0d447
fix: ss58 addresses; add todos
failfmi b98b9cb
refactor json unmarshaling + add tests
tgntr 0843bc1
Merge branch 'develop' into polkadot-sdk
tgntr 3f27d24
remove commented code
tgntr 515a413
implement DecodeSequenceSr25519PublicKey
tgntr d7dd907
improve test coverage
tgntr 1f3d174
skip duplicate authorities
tgntr 79d9398
fix: decoding json numbers + storing genesis balances
tgntr d4ec0d8
address PR comments
tgntr 0d9dfc9
rename want to expected + remove public IncProviders
tgntr f8f3323
rename Gc to GenesisConfig in types
tgntr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package genesisbuilder | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"strings" | ||
|
||
sc "github.com/LimeChain/goscale" | ||
"github.com/LimeChain/gosemble/primitives/hashing" | ||
"github.com/LimeChain/gosemble/primitives/log" | ||
primitives "github.com/LimeChain/gosemble/primitives/types" | ||
"github.com/LimeChain/gosemble/utils" | ||
) | ||
|
||
const ( | ||
ApiModuleName = "GenesisBuilder" | ||
apiVersion = 1 | ||
) | ||
|
||
type GenesisBuilder interface { | ||
CreateDefaultConfig() ([]byte, error) | ||
BuildConfig(config []byte) error | ||
} | ||
|
||
type Module struct { | ||
modules []primitives.Module | ||
memUtils utils.WasmMemoryTranslator | ||
} | ||
|
||
func New(modules []primitives.Module) Module { | ||
return Module{ | ||
modules: modules, | ||
memUtils: utils.NewMemoryTranslator(), | ||
} | ||
} | ||
|
||
func (m Module) Name() string { | ||
return ApiModuleName | ||
} | ||
|
||
func (m Module) Item() primitives.ApiItem { | ||
hash := hashing.MustBlake2b8([]byte(ApiModuleName)) | ||
return primitives.NewApiItem(hash, apiVersion) | ||
} | ||
|
||
func (m Module) CreateDefaultConfig() int64 { | ||
gcs := []string{} | ||
for _, m := range m.modules { | ||
genesisBuilder, ok := m.(GenesisBuilder) | ||
if !ok { | ||
continue | ||
} | ||
|
||
gcJsonBytes, err := genesisBuilder.CreateDefaultConfig() | ||
if err != nil { | ||
log.Critical(err.Error()) | ||
} | ||
|
||
// gcJsonBytes[1:len(gcJsonBytes)-1] trims first and last characters which represent start and end of the json | ||
// CreateDefaultConfig returns a valid json (e.g. {"system":{}}), and here we need it as a json field | ||
gcs = append(gcs, string(gcJsonBytes[1:len(gcJsonBytes)-1])) | ||
} | ||
|
||
gcJson := []byte(fmt.Sprintf("{%s}", strings.Join(gcs, ","))) | ||
|
||
return m.memUtils.BytesToOffsetAndSize(sc.BytesToSequenceU8(gcJson).Bytes()) | ||
} | ||
|
||
func (m Module) BuildConfig(dataPtr int32, dataLen int32) int64 { | ||
gcJsonBytes := m.memUtils.GetWasmMemorySlice(dataPtr, dataLen) | ||
gcDecoded, err := sc.DecodeSequence[sc.U8](bytes.NewBuffer(gcJsonBytes)) | ||
if err != nil { | ||
log.Critical(err.Error()) | ||
} | ||
|
||
gcDecodedBytes := sc.SequenceU8ToBytes(gcDecoded) | ||
|
||
for _, m := range m.modules { | ||
genesisBuilder, ok := m.(GenesisBuilder) | ||
if !ok { | ||
continue | ||
} | ||
|
||
if err := genesisBuilder.BuildConfig(gcDecodedBytes); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every module configuration must be included in the bytes. Currently, you can execute the function without having |
||
log.Critical(err.Error()) | ||
} | ||
} | ||
|
||
return m.memUtils.BytesToOffsetAndSize([]byte{0}) | ||
} | ||
|
||
// todo metadata | ||
// func (m Module) Metadata() primitives.RuntimeApiMetadata { | ||
// return primitives.RuntimeApiMetadata{} | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package genesisbuilder | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"github.com/ChainSafe/gossamer/lib/common" | ||
sc "github.com/LimeChain/goscale" | ||
"github.com/LimeChain/gosemble/mocks" | ||
"github.com/LimeChain/gosemble/primitives/types" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
var ( | ||
genesis = []byte("{\"module\":{\"field\":[]}}") | ||
genesisSequence = sc.BytesToSequenceU8(genesis).Bytes() | ||
) | ||
|
||
var ( | ||
target Module | ||
mockModule *mocks.Module | ||
mockMemoryUtils *mocks.MemoryTranslator | ||
) | ||
|
||
func setup() { | ||
mockModule = new(mocks.Module) | ||
mockMemoryUtils = new(mocks.MemoryTranslator) | ||
|
||
target = New([]types.Module{mockModule}) | ||
target.memUtils = mockMemoryUtils | ||
} | ||
|
||
func Test_Module_Name(t *testing.T) { | ||
setup() | ||
result := target.Name() | ||
assert.Equal(t, ApiModuleName, result) | ||
} | ||
|
||
func Test_Module_Item(t *testing.T) { | ||
setup() | ||
hexName := common.MustBlake2b8([]byte(ApiModuleName)) | ||
expect := types.NewApiItem(hexName, apiVersion) | ||
result := target.Item() | ||
assert.Equal(t, expect, result) | ||
} | ||
|
||
func Test_CreateDefaultConfig(t *testing.T) { | ||
setup() | ||
mockModule.On("CreateDefaultConfig").Return(genesis, nil) | ||
mockMemoryUtils.On("BytesToOffsetAndSize", genesisSequence).Return(int64(0)) | ||
|
||
target.CreateDefaultConfig() | ||
|
||
mockModule.AssertCalled(t, "CreateDefaultConfig") | ||
mockMemoryUtils.AssertCalled(t, "BytesToOffsetAndSize", genesisSequence) | ||
} | ||
|
||
func Test_CreateDefaultConfig_Error(t *testing.T) { | ||
setup() | ||
mockModule.On("CreateDefaultConfig").Return(genesis, errors.New("err")) | ||
mockMemoryUtils.On("BytesToOffsetAndSize", genesisSequence).Return(int64(0)) | ||
|
||
assert.PanicsWithValue(t, | ||
errors.New("err").Error(), | ||
func() { target.CreateDefaultConfig() }, | ||
) | ||
} | ||
|
||
func Test_BuildConfig(t *testing.T) { | ||
setup() | ||
mockModule.On("BuildConfig", genesis).Return(nil) | ||
mockMemoryUtils.On("GetWasmMemorySlice", int32(0), int32(0)).Return(genesisSequence) | ||
mockMemoryUtils.On("BytesToOffsetAndSize", []byte{0}).Return(int64(0)) | ||
|
||
target.BuildConfig(0, 0) | ||
|
||
mockMemoryUtils.AssertCalled(t, "GetWasmMemorySlice", int32(0), int32(0)) | ||
mockModule.AssertCalled(t, "BuildConfig", genesis) | ||
mockMemoryUtils.AssertCalled(t, "BytesToOffsetAndSize", []byte{0}) | ||
} | ||
|
||
func Test_BuildConfig_Error(t *testing.T) { | ||
setup() | ||
mockModule.On("BuildConfig", genesis).Return(errors.New("err")) | ||
mockMemoryUtils.On("GetWasmMemorySlice", int32(0), int32(0)).Return(genesisSequence) | ||
mockMemoryUtils.On("BytesToOffsetAndSize", []byte{0}).Return(int64(0)) | ||
|
||
assert.PanicsWithValue(t, | ||
errors.New("err").Error(), | ||
func() { target.BuildConfig(0, 0) }, | ||
) | ||
} |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package aura | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
|
||
sc "github.com/LimeChain/goscale" | ||
"github.com/LimeChain/gosemble/primitives/types" | ||
"github.com/vedhavyas/go-subkey" | ||
) | ||
|
||
var ( | ||
errAuthoritiesAlreadyInitialized = errors.New("Authorities are already initialized!") | ||
errAuthoritiesExceedMaxAuthorities = errors.New("Initial authority set must be less than MaxAuthorities") | ||
) | ||
|
||
type GenesisConfig struct { | ||
Authorities sc.Sequence[types.Sr25519PublicKey] | ||
} | ||
|
||
type genesisConfigJsonStruct struct { | ||
AuraGenesisConfig struct { | ||
Authorities []string `json:"authorities"` | ||
} `json:"aura"` | ||
} | ||
|
||
func (gc *GenesisConfig) UnmarshalJSON(data []byte) error { | ||
gcJson := genesisConfigJsonStruct{} | ||
|
||
if err := json.Unmarshal(data, &gcJson); err != nil { | ||
return err | ||
} | ||
|
||
addrExists := map[string]bool{} | ||
for _, a := range gcJson.AuraGenesisConfig.Authorities { | ||
if addrExists[a] { | ||
continue | ||
} | ||
|
||
_, pubKeyBytes, err := subkey.SS58Decode(a) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
pubKey, err := types.NewSr25519PublicKey(sc.BytesToSequenceU8(pubKeyBytes)...) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
gc.Authorities = append(gc.Authorities, pubKey) | ||
addrExists[a] = true | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (m Module) CreateDefaultConfig() ([]byte, error) { | ||
gc := genesisConfigJsonStruct{} | ||
gc.AuraGenesisConfig.Authorities = []string{} | ||
|
||
return json.Marshal(gc) | ||
} | ||
|
||
func (m Module) BuildConfig(config []byte) error { | ||
gc := GenesisConfig{} | ||
if err := json.Unmarshal(config, &gc); err != nil { | ||
return err | ||
} | ||
|
||
if len(gc.Authorities) == 0 { | ||
return nil | ||
} | ||
|
||
totalAuthorities, err := m.storage.Authorities.DecodeLen() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if totalAuthorities.HasValue { | ||
return errAuthoritiesAlreadyInitialized | ||
} | ||
|
||
if len(gc.Authorities) > int(m.config.MaxAuthorities) { | ||
return errAuthoritiesExceedMaxAuthorities | ||
} | ||
|
||
m.storage.Authorities.Put(gc.Authorities) | ||
|
||
return nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that we unmarshal the decoded bytes every time in each module. Thoughts on unmarshalling only once here, and pass the struct to the modules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about it, but I'm not sure if that's achievable without predefining all available genesis configs. I think we should keep it dynamic, especially for when we start supporting custom pallets. Let me know if you have any ideas