diff --git a/go.mod b/go.mod index cab08a392..0e82a12f1 100644 --- a/go.mod +++ b/go.mod @@ -71,7 +71,7 @@ require ( github.com/sergi/go-diff v1.2.0 github.com/ulikunitz/xz v0.5.11 github.com/vektra/mockery/v2 v2.42.3 - gitlab.com/accumulatenetwork/core/schema v0.1.1-0.20240613214617-0be27c3bb950 + gitlab.com/accumulatenetwork/core/schema v0.1.1-0.20240618183058-91669372cfa3 gitlab.com/firelizzard/go-script v0.0.0-20240404234115-d5f0a716003d go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 diff --git a/go.sum b/go.sum index 309553c20..bd9cda8d3 100644 --- a/go.sum +++ b/go.sum @@ -1166,6 +1166,8 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= gitlab.com/accumulatenetwork/core/schema v0.1.1-0.20240613214617-0be27c3bb950 h1:dlYE/sYVb60AYrO2Tk4oP3UfmHDn3UVzhZGVXj/HjQs= gitlab.com/accumulatenetwork/core/schema v0.1.1-0.20240613214617-0be27c3bb950/go.mod h1:FTl7W44SWhDenzAtvKkLu30Cin8DAr249mH4eg7BNLY= +gitlab.com/accumulatenetwork/core/schema v0.1.1-0.20240618183058-91669372cfa3 h1:RyNDul6B2nebcjA8+KSBR79MRUftOWWO0NRqN3x0Vh4= +gitlab.com/accumulatenetwork/core/schema v0.1.1-0.20240618183058-91669372cfa3/go.mod h1:FTl7W44SWhDenzAtvKkLu30Cin8DAr249mH4eg7BNLY= gitlab.com/bosi/decorder v0.4.1 h1:VdsdfxhstabyhZovHafFw+9eJ6eU0d2CkFNJcZz/NU4= gitlab.com/bosi/decorder v0.4.1/go.mod h1:jecSqWUew6Yle1pCr2eLWTensJMmsxHsBwt+PVbkAqA= gitlab.com/ethan.reesor/vscode-notebooks/go-playbooks v0.0.0-20220417214602-1121b9fae118 h1:UnyYFTz6dWVMBzLUyqHPIQwMrdpiuE+CE7p/5kUfvmk= diff --git a/pkg/database/bpt/bpt.go b/pkg/database/bpt/bpt.go index fa7b4e3d5..f0d088c96 100644 --- a/pkg/database/bpt/bpt.go +++ b/pkg/database/bpt/bpt.go @@ -10,7 +10,6 @@ import ( "github.com/cometbft/cometbft/libs/log" "gitlab.com/accumulatenetwork/accumulate/internal/database/record" "gitlab.com/accumulatenetwork/accumulate/pkg/database" - "gitlab.com/accumulatenetwork/accumulate/pkg/database/values" "gitlab.com/accumulatenetwork/accumulate/pkg/errors" ) @@ -49,40 +48,6 @@ func (b *BPT) GetRootHash() ([32]byte, error) { return h, nil } -func (b *BPT) newState() values.Value[*stateData] { - v := values.NewValue(b.logger.L, b.store, b.key.Append("Root"), false, values.Struct[stateData]()) - return paramsRecord{v} -} - -// paramsRecord is a wrapper around Value that sets the power to 8 if the -// parameters have not been configured. -type paramsRecord struct { - values.Value[*stateData] -} - -// Get loads the parameters, initializing them to the default values if they -// have not been set. -func (p paramsRecord) Get() (*stateData, error) { - v, err := p.Value.Get() - switch { - case err == nil: - return v, nil - case !errors.Is(err, errors.NotFound): - return nil, errors.UnknownError.Wrap(err) - } - - // TODO Allow power to be configurable? - v = new(stateData) - v.Power = 8 - v.Mask = v.Power - 1 - err = p.Value.Put(v) - if err != nil { - return nil, errors.UnknownError.Wrap(err) - } - - return v, nil -} - // nodeKeyAt // We need a key to address nodes in the protocol. These nodes need a unique key // for debugging purposes. @@ -128,19 +93,6 @@ func parseNodeKey(nodeKey [32]byte) (height uint64, key [32]byte, ok bool) { //n return byteIdx*8 + 8 - bit, key, true } -// getRoot returns the root branch node, creating it if necessary. -func (b *BPT) getRoot() *branch { - return values.GetOrCreate(b, &b.root, (*BPT).newRoot).branch -} - -func (b *BPT) newRoot() *rootRecord { - e := new(branch) - e.bpt = b - e.Height = 0 - e.Key, _ = nodeKeyAt(0, [32]byte{}) - return &rootRecord{e} -} - // Get retrieves the latest hash associated with the given key. func (b *BPT) Get(key *record.Key) ([]byte, error) { if v, ok := b.pending[key.Hash()]; ok { @@ -199,37 +151,3 @@ again: e = g goto again } - -// Resolve implements [database.Record]. -func (b *BPT) Resolve(key *database.Key) (database.Record, *database.Key, error) { - if key.Len() == 0 { - return nil, nil, errors.InternalError.With("bad key for bpt") - } - - // Execute any pending updates - err := b.executePending() - if err != nil { - return nil, nil, errors.UnknownError.Wrap(err) - } - - if key.Get(0) == "Root" { - return b.getState(), key.SliceI(1), nil - } - - nodeKey, ok := key.Get(0).([32]byte) - if !ok { - return nil, nil, errors.InternalError.With("bad key for bpt") - } - e, err := b.getRoot().getBranch(nodeKey) - if err != nil { - return nil, nil, errors.UnknownError.WithFormat("bad key for BPT: %x", err) - } - - // Ensure the node is loaded - err = e.load() - if err != nil { - return nil, nil, errors.UnknownError.WithFormat("load node: %w", err) - } - - return nodeRecord{e}, key.SliceI(1), nil -} diff --git a/pkg/database/bpt/enums.yml b/pkg/database/bpt/enums.yml deleted file mode 100644 index ae6b2b7ad..000000000 --- a/pkg/database/bpt/enums.yml +++ /dev/null @@ -1,17 +0,0 @@ -nodeType: - Empty: - description: is an empty node - value: 1 - Branch: - description: is a branch node - value: 2 - Leaf: - description: is a leaf node - value: 3 - Boundary: - description: is the boundary between blocks - value: 4 - LeafWithExpandedKey: - description: is a leaf node with an expanded key - label: leaf+key - value: 5 diff --git a/pkg/database/bpt/enums_gen.go b/pkg/database/bpt/enums_gen.go deleted file mode 100644 index bd5a9855c..000000000 --- a/pkg/database/bpt/enums_gen.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2023 The Accumulate Authors -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. - -package bpt - -// GENERATED BY go run ./tools/cmd/gen-enum. DO NOT EDIT. - -import ( - "encoding/json" - "fmt" - "strings" -) - -// nodeTypeEmpty is an empty node. -const nodeTypeEmpty nodeType = 1 - -// nodeTypeBranch is a branch node. -const nodeTypeBranch nodeType = 2 - -// nodeTypeLeaf is a leaf node. -const nodeTypeLeaf nodeType = 3 - -// nodeTypeBoundary is the boundary between blocks. -const nodeTypeBoundary nodeType = 4 - -// nodeTypeLeafWithExpandedKey is a leaf node with an expanded key. -const nodeTypeLeafWithExpandedKey nodeType = 5 - -// GetEnumValue returns the value of the node Type -func (v nodeType) GetEnumValue() uint64 { return uint64(v) } - -// SetEnumValue sets the value. SetEnumValue returns false if the value is invalid. -func (v *nodeType) SetEnumValue(id uint64) bool { - u := nodeType(id) - switch u { - case nodeTypeEmpty, nodeTypeBranch, nodeTypeLeaf, nodeTypeBoundary, nodeTypeLeafWithExpandedKey: - *v = u - return true - } - return false -} - -// String returns the name of the node Type. -func (v nodeType) String() string { - switch v { - case nodeTypeEmpty: - return "empty" - case nodeTypeBranch: - return "branch" - case nodeTypeLeaf: - return "leaf" - case nodeTypeBoundary: - return "boundary" - case nodeTypeLeafWithExpandedKey: - return "leaf+key" - } - return fmt.Sprintf("nodeType:%d", v) -} - -// nodeTypeByName returns the named node Type. -func nodeTypeByName(name string) (nodeType, bool) { - switch strings.ToLower(name) { - case "empty": - return nodeTypeEmpty, true - case "branch": - return nodeTypeBranch, true - case "leaf": - return nodeTypeLeaf, true - case "boundary": - return nodeTypeBoundary, true - case "leafwithexpandedkey": - return nodeTypeLeafWithExpandedKey, true - case "leaf+key": - return nodeTypeLeafWithExpandedKey, true - } - return 0, false -} - -// MarshalJSON marshals the node Type to JSON as a string. -func (v nodeType) MarshalJSON() ([]byte, error) { - return json.Marshal(v.String()) -} - -// UnmarshalJSON unmarshals the node Type from JSON as a string. -func (v *nodeType) UnmarshalJSON(data []byte) error { - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return err - } - - var ok bool - *v, ok = nodeTypeByName(s) - if !ok || strings.ContainsRune(v.String(), ':') { - return fmt.Errorf("invalid node Type %q", s) - } - return nil -} diff --git a/pkg/database/bpt/marshal.go b/pkg/database/bpt/marshal.go index 1447277b3..2fefa88b6 100644 --- a/pkg/database/bpt/marshal.go +++ b/pkg/database/bpt/marshal.go @@ -13,55 +13,15 @@ import ( "io" "gitlab.com/accumulatenetwork/accumulate/pkg/errors" - "gitlab.com/accumulatenetwork/accumulate/pkg/types/encoding" "gitlab.com/accumulatenetwork/accumulate/pkg/types/record" ) -// paramsStateSize is the marshaled size of [parameters]. -const paramsStateSize = 1 + 2 + 2 + 32 - // branchStateSize is the marshaled size of [branch]. const branchStateSize = 32 + 1 + 32 // leafStateSize is the marshaled size of [leaf]. const leafStateSize = 32 + 32 -func (r *stateData) MarshalBinary() ([]byte, error) { - // Marshal the fields - var data []byte - data = append(data, byte(r.MaxHeight)) - data = append(data, byte(r.Power>>8), byte(r.Power)) - data = append(data, byte(r.Mask>>8), byte(r.Mask)) - data = append(data, r.RootHash[:]...) - return data, nil -} - -func (r *stateData) UnmarshalBinary(data []byte) error { - // Check the size - if len(data) != paramsStateSize { - return encoding.ErrNotEnoughData - } - - // Unmarshal the fields - r.MaxHeight = uint64(data[0]) - r.Power = uint64(data[1])<<8 + uint64(data[2]) - r.Mask = uint64(data[3])<<8 + uint64(data[4]) - r.RootHash = *(*[32]byte)(data[5:]) - return nil -} - -func (r *stateData) UnmarshalBinaryFrom(rd io.Reader) error { - // Read paramStateSize bytes - var buf [paramsStateSize]byte - _, err := io.ReadFull(rd, buf[:]) - if err != nil { - return err - } - - // Unmarshal - return r.UnmarshalBinary(buf[:]) -} - // tryWrite writes the bytes to the writer if err is nil. If the write returns // an error, tryWrite assigns it to err. func tryWrite(err *error, wr io.Writer, b []byte) { @@ -104,10 +64,6 @@ func (n *branch) readFrom(rd *bytes.Buffer, o marshalOpts) error { return nil } -func (*emptyNode) Type() nodeType { return nodeTypeEmpty } - -func (*branch) Type() nodeType { return nodeTypeBranch } - func (v *leaf) Type() nodeType { if isExpandedKey(v.Key) { return nodeTypeLeafWithExpandedKey diff --git a/pkg/database/bpt/model.go b/pkg/database/bpt/model.go new file mode 100644 index 000000000..dd0b35588 --- /dev/null +++ b/pkg/database/bpt/model.go @@ -0,0 +1,67 @@ +// Copyright 2024 The Accumulate Authors +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +package bpt + +import ( + "gitlab.com/accumulatenetwork/accumulate/pkg/database" + "gitlab.com/accumulatenetwork/accumulate/pkg/database/values" + "gitlab.com/accumulatenetwork/accumulate/pkg/errors" +) + +func (v *stateData) CopyAsInterface() any { return v.Copy() } + +func (b *BPT) newState() values.Value[*stateData] { + v := values.NewValue(b.logger.L, b.store, b.key.Append("Root"), false, values.Struct[stateData]()) + return paramsRecord{v} +} + +// getRoot returns the root branch node, creating it if necessary. +func (b *BPT) getRoot() *branch { + return values.GetOrCreate(b, &b.root, (*BPT).newRoot).branch +} + +func (b *BPT) newRoot() *rootRecord { + e := new(branch) + e.bpt = b + e.Height = 0 + e.Key, _ = nodeKeyAt(0, [32]byte{}) + return &rootRecord{e} +} + +// Resolve implements [database.Record]. +func (b *BPT) Resolve(key *database.Key) (database.Record, *database.Key, error) { + if key.Len() == 0 { + return nil, nil, errors.InternalError.With("bad key for bpt") + } + + // Execute any pending updates + err := b.executePending() + if err != nil { + return nil, nil, errors.UnknownError.Wrap(err) + } + + if key.Get(0) == "Root" { + return b.getState(), key.SliceI(1), nil + } + + nodeKey, ok := key.Get(0).([32]byte) + if !ok { + return nil, nil, errors.InternalError.With("bad key for bpt") + } + e, err := b.getRoot().getBranch(nodeKey) + if err != nil { + return nil, nil, errors.UnknownError.WithFormat("bad key for BPT: %x", err) + } + + // Ensure the node is loaded + err = e.load() + if err != nil { + return nil, nil, errors.UnknownError.WithFormat("load node: %w", err) + } + + return nodeRecord{e}, key.SliceI(1), nil +} diff --git a/pkg/database/bpt/node.go b/pkg/database/bpt/node.go index ce90aab87..560076860 100644 --- a/pkg/database/bpt/node.go +++ b/pkg/database/bpt/node.go @@ -14,17 +14,11 @@ import ( "gitlab.com/accumulatenetwork/accumulate/pkg/errors" ) -// nodeType is the type of an [Node]. -type nodeType uint64 - // node is an node in a [BPT]. type node interface { // Type is the type of the node. Type() nodeType - // CopyAsInterface implements [encoding.BinaryValue]. - CopyAsInterface() any - // IsDirty returns true if the node has been modified. IsDirty() bool diff --git a/pkg/database/bpt/params.go b/pkg/database/bpt/params.go new file mode 100644 index 000000000..6fcdf9b2b --- /dev/null +++ b/pkg/database/bpt/params.go @@ -0,0 +1,83 @@ +// Copyright 2024 The Accumulate Authors +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +package bpt + +import ( + "io" + + "gitlab.com/accumulatenetwork/accumulate/pkg/database/values" + "gitlab.com/accumulatenetwork/accumulate/pkg/errors" + "gitlab.com/accumulatenetwork/accumulate/pkg/types/encoding" +) + +// paramsStateSize is the marshaled size of [parameters]. +const paramsStateSize = 1 + 2 + 2 + 32 + +// paramsRecord is a wrapper around Value that sets the power to 8 if the +// parameters have not been configured. +type paramsRecord struct { + values.Value[*stateData] +} + +// Get loads the parameters, initializing them to the default values if they +// have not been set. +func (p paramsRecord) Get() (*stateData, error) { + v, err := p.Value.Get() + switch { + case err == nil: + return v, nil + case !errors.Is(err, errors.NotFound): + return nil, errors.UnknownError.Wrap(err) + } + + // TODO Allow power to be configurable? + v = new(stateData) + v.Power = 8 + v.Mask = v.Power - 1 + err = p.Value.Put(v) + if err != nil { + return nil, errors.UnknownError.Wrap(err) + } + + return v, nil +} + +func (r *stateData) MarshalBinary() ([]byte, error) { + // Marshal the fields + var data []byte + data = append(data, byte(r.MaxHeight)) + data = append(data, byte(r.Power>>8), byte(r.Power)) + data = append(data, byte(r.Mask>>8), byte(r.Mask)) + data = append(data, r.RootHash[:]...) + return data, nil +} + +func (r *stateData) UnmarshalBinary(data []byte) error { + // Check the size + if len(data) != paramsStateSize { + return encoding.ErrNotEnoughData + } + + // Unmarshal the fields + r.MaxHeight = uint64(data[0]) + r.Power = uint64(data[1])<<8 + uint64(data[2]) + r.Mask = uint64(data[3])<<8 + uint64(data[4]) + r.RootHash = *(*[32]byte)(data[5:]) + return nil +} + +func (r *stateData) UnmarshalBinaryFrom(rd io.Reader) error { + // Read paramStateSize bytes + var buf [paramsStateSize]byte + _, err := io.ReadFull(rd, buf[:]) + if err != nil { + return err + } + + // Unmarshal + return r.UnmarshalBinary(buf[:]) +} diff --git a/pkg/database/bpt/schema.yml b/pkg/database/bpt/schema.yml new file mode 100644 index 000000000..0a4a09bdf --- /dev/null +++ b/pkg/database/bpt/schema.yml @@ -0,0 +1,95 @@ +$generate: + widgets: true + + import: + record: gitlab.com/accumulatenetwork/accumulate/pkg/types/record + + varPrefix: + schema: s + widget: w + +stateData: + class: composite + fields: + - name: RootHash + type: hash + - name: MaxHeight + type: uint + - type: + name: parameters + class: composite + fields: + - name: Power + type: uint + - name: Mask + type: uint + +node: + class: union + discriminator: + field: Type + type: + name: nodeType + class: enum + underlying: int + values: + Empty: + description: is an empty node + value: 1 + Branch: + description: is a branch node + value: 2 + Leaf: + description: is a leaf node + value: 3 + Boundary: + description: is the boundary between blocks + value: 4 + LeafWithExpandedKey: + description: is a leaf node with an expanded key + label: leaf+key + value: 5 + + members: + - name: emptyNode + class: composite + transients: + - name: parent + type: '*branch' + + - name: branch + class: composite + fields: + - name: Height + type: uint + - name: Key + type: hash + - name: Hash + type: hash + + transients: + - name: bpt + type: '*BPT' + - name: parent + type: '*branch' + - name: status + type: branchStatus + + - name: Left + type: node + - name: Right + type: node + + - name: leaf + class: composite + generate: + methods: { discriminator: false } + fields: + - name: Key + type: '*record.Key' + - name: Value + type: bytes + + transients: + - name: parent + type: '*branch' diff --git a/pkg/database/bpt/schema_gen.go b/pkg/database/bpt/schema_gen.go new file mode 100644 index 000000000..f78878323 --- /dev/null +++ b/pkg/database/bpt/schema_gen.go @@ -0,0 +1,240 @@ +// Code generated by gitlab.com/accumulatenetwork/core/schema. DO NOT EDIT. + +package bpt + +import ( + "fmt" + + record "gitlab.com/accumulatenetwork/accumulate/pkg/types/record" + "gitlab.com/accumulatenetwork/core/schema" +) + +var ( + sbranch schema.Methods[*branch, *branch, *schema.CompositeType] + semptyNode schema.Methods[*emptyNode, *emptyNode, *schema.CompositeType] + sleaf schema.Methods[*leaf, *leaf, *schema.CompositeType] + snode schema.Methods[node, *node, *schema.UnionType] + snodeType schema.EnumMethods[nodeType] + sparameters schema.Methods[*parameters, *parameters, *schema.CompositeType] + sstateData schema.Methods[*stateData, *stateData, *schema.CompositeType] +) + +func init() { + var deferredTypes schema.ResolverSet + + sbranch = schema.WithMethods[*branch, *branch](&schema.CompositeType{ + TypeBase: schema.TypeBase{ + Name: "branch", + }, + Fields: []*schema.Field{ + { + Name: "Height", + Type: &schema.SimpleType{Type: schema.SimpleTypeUint}, + }, + { + Name: "Key", + Type: &schema.SimpleType{Type: schema.SimpleTypeHash}, + }, + { + Name: "Hash", + Type: &schema.SimpleType{Type: schema.SimpleTypeHash}, + }, + }, + Transients: []*schema.Field{ + { + Name: "bpt", + Type: &schema.PointerType{ + TypeBase: schema.TypeBase{}, + Elem: schema.ExternalTypeReference[BPT](), + }, + }, + { + Name: "parent", + Type: (&schema.PointerType{ + TypeBase: schema.TypeBase{}, + }). + ResolveElemTo(&deferredTypes, "branch"), + }, + { + Name: "status", + Type: schema.ExternalTypeReference[branchStatus](), + }, + (&schema.Field{ + Name: "Left", + }).ResolveTo(&deferredTypes, "node"), + (&schema.Field{ + Name: "Right", + }).ResolveTo(&deferredTypes, "node"), + }, + }).SetGoType() + + semptyNode = schema.WithMethods[*emptyNode, *emptyNode](&schema.CompositeType{ + TypeBase: schema.TypeBase{ + Name: "emptyNode", + }, + Transients: []*schema.Field{ + { + Name: "parent", + Type: (&schema.PointerType{ + TypeBase: schema.TypeBase{}, + }). + ResolveElemTo(&deferredTypes, "branch"), + }, + }, + }).SetGoType() + + sleaf = schema.WithMethods[*leaf, *leaf](&schema.CompositeType{ + TypeBase: schema.TypeBase{ + Name: "leaf", + Generate: schema.MapValue{ + "methods": schema.MapValue{ + "discriminator": schema.BooleanValue(false), + }, + }, + }, + Fields: []*schema.Field{ + { + Name: "Key", + Type: &schema.PointerType{ + TypeBase: schema.TypeBase{}, + Elem: schema.ExternalTypeReference[record.Key](), + }, + }, + { + Name: "Value", + Type: &schema.SimpleType{Type: schema.SimpleTypeBytes}, + }, + }, + Transients: []*schema.Field{ + { + Name: "parent", + Type: (&schema.PointerType{ + TypeBase: schema.TypeBase{}, + }). + ResolveElemTo(&deferredTypes, "branch"), + }, + }, + }).SetGoType() + + snode = schema.WithMethods[node, *node]( + &schema.UnionType{ + TypeBase: schema.TypeBase{ + Name: "node", + }, + Discriminator: (&schema.UnionDiscriminator{ + Field: "Type", + }). + ResolveTypeTo(&deferredTypes, "nodeType"). + ResolveEnumTo(&deferredTypes, "nodeType"), + Members: []*schema.UnionMember{ + (&schema.UnionMember{ + Discriminator: "empty", + }).ResolveTo(&deferredTypes, "emptyNode"), + (&schema.UnionMember{ + Discriminator: "branch", + }).ResolveTo(&deferredTypes, "branch"), + (&schema.UnionMember{ + Discriminator: "leaf", + }).ResolveTo(&deferredTypes, "leaf"), + }, + }).SetGoType() + + snodeType = schema.WithEnumMethods[nodeType]( + &schema.EnumType{ + TypeBase: schema.TypeBase{ + Name: "nodeType", + }, + Underlying: &schema.SimpleType{Type: schema.SimpleTypeInt}, + Values: map[string]*schema.EnumValue{ + "Boundary": { + Name: "Boundary", + Value: 4, + Description: "is the boundary between blocks", + }, + "Branch": { + Name: "Branch", + Value: 2, + Description: "is a branch node", + }, + "Empty": { + Name: "Empty", + Value: 1, + Description: "is an empty node", + }, + "Leaf": { + Name: "Leaf", + Value: 3, + Description: "is a leaf node", + }, + "LeafWithExpandedKey": { + Name: "LeafWithExpandedKey", + Value: 5, + Description: "is a leaf node with an expanded key", + Label: "leaf+key", + }, + }, + }).SetGoType() + + sparameters = schema.WithMethods[*parameters, *parameters](&schema.CompositeType{ + TypeBase: schema.TypeBase{ + Name: "parameters", + }, + Fields: []*schema.Field{ + { + Name: "Power", + Type: &schema.SimpleType{Type: schema.SimpleTypeUint}, + }, + { + Name: "Mask", + Type: &schema.SimpleType{Type: schema.SimpleTypeUint}, + }, + }, + }).SetGoType() + + sstateData = schema.WithMethods[*stateData, *stateData](&schema.CompositeType{ + TypeBase: schema.TypeBase{ + Name: "stateData", + }, + Fields: []*schema.Field{ + { + Name: "RootHash", + Type: &schema.SimpleType{Type: schema.SimpleTypeHash}, + }, + { + Name: "MaxHeight", + Type: &schema.SimpleType{Type: schema.SimpleTypeUint}, + }, + (&schema.Field{}).ResolveTo(&deferredTypes, "parameters"), + }, + }).SetGoType() + + s, err := schema.New( + sbranch.Type, + semptyNode.Type, + sleaf.Type, + snode.Type, + snodeType.Type, + sparameters.Type, + sstateData.Type, + ) + if err != nil { + panic(fmt.Errorf("invalid embedded schema: %w", err)) + } + + s.Generate = schema.MapValue{ + "import": schema.MapValue{ + "record": schema.StringValue("gitlab.com/accumulatenetwork/accumulate/pkg/types/record"), + }, + "varPrefix": schema.MapValue{ + "schema": schema.StringValue("s"), + "widget": schema.StringValue("w"), + }, + "widgets": schema.BooleanValue(true), + } + + deferredTypes.Resolve(s) + err = s.Validate() + if err != nil { + panic(fmt.Errorf("invalid embedded schema: %w", err)) + } +} diff --git a/pkg/database/bpt/types.go b/pkg/database/bpt/types.go index c4d3ff321..ad04a5cb4 100644 --- a/pkg/database/bpt/types.go +++ b/pkg/database/bpt/types.go @@ -6,8 +6,8 @@ package bpt -//go:generate go run gitlab.com/accumulatenetwork/accumulate/tools/cmd/gen-enum --package bpt enums.yml -//go:generate go run gitlab.com/accumulatenetwork/accumulate/tools/cmd/gen-types --package bpt types.yml --union-skip-type -//go:generate go run gitlab.com/accumulatenetwork/accumulate/tools/cmd/gen-types --package bpt --language go-union --out unions_gen.go types.yml --union-skip-new +//go:generate go run gitlab.com/accumulatenetwork/core/schema/cmd/generate schema schema.yml -w schema_gen.go +//go:generate go run gitlab.com/accumulatenetwork/core/schema/cmd/generate types schema.yml -w types_gen.go //go:generate go run gitlab.com/accumulatenetwork/accumulate/tools/cmd/gen-model --package bpt model.yml //go:generate go run gitlab.com/accumulatenetwork/accumulate/tools/cmd/gen-model --package bpt --out model_gen_test.go model_test.yml +//go:generate go run github.com/rinchsan/gosimports/cmd/gosimports -w . diff --git a/pkg/database/bpt/types.yml b/pkg/database/bpt/types.yml deleted file mode 100644 index 418c3f211..000000000 --- a/pkg/database/bpt/types.yml +++ /dev/null @@ -1,75 +0,0 @@ -stateData: - non-binary: true - non-json: true - fields: - - name: RootHash - type: hash - - name: MaxHeight - type: uint - - name: Power - type: uint - - name: Mask - type: uint - -# TODO Remove the bpt and parent fields and pass the BPT reference in the method -# parameters instead - -emptyNode: - non-binary: true - non-json: true - union: { type: node, private: true } - fields: - - name: parent - type: branch - pointer: true - marshal-as: none - -branch: - non-binary: true - non-json: true - union: { type: node, private: true } - fields: - - name: bpt - type: BPT - pointer: true - marshal-as: none - - name: parent - type: branch - pointer: true - marshal-as: none - - name: status - type: branchStatus - marshal-as: none - - - name: Height - type: uint - - name: Key - type: hash - - name: Hash - type: hash - - - name: Left - type: node - marshal-as: none - zero-value: nil - - name: Right - type: node - marshal-as: none - zero-value: nil - -leaf: - non-binary: true - non-json: true - union: { type: node, private: true } - fields: - - name: Key - type: record.Key - marshal-as: reference - pointer: true - - name: Value - type: bytes - - - name: parent - type: branch - pointer: true - marshal-as: none diff --git a/pkg/database/bpt/types_gen.go b/pkg/database/bpt/types_gen.go index 782f3f5db..136cb6ef8 100644 --- a/pkg/database/bpt/types_gen.go +++ b/pkg/database/bpt/types_gen.go @@ -1,144 +1,191 @@ -// Copyright 2022 The Accumulate Authors -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. +// Code generated by gitlab.com/accumulatenetwork/core/schema. DO NOT EDIT. package bpt -// GENERATED BY go run ./tools/cmd/gen-types. DO NOT EDIT. - -//lint:file-ignore S1001,S1002,S1008,SA4013 generated code - import ( - "bytes" - - "gitlab.com/accumulatenetwork/accumulate/internal/database/record" - "gitlab.com/accumulatenetwork/accumulate/pkg/types/encoding" + record "gitlab.com/accumulatenetwork/accumulate/pkg/types/record" + "gitlab.com/accumulatenetwork/core/schema/pkg/widget" ) type branch struct { + Height uint64 + Key [32]byte + Hash [32]byte bpt *BPT parent *branch status branchStatus - Height uint64 `json:"height,omitempty" form:"height" query:"height" validate:"required"` - Key [32]byte `json:"key,omitempty" form:"key" query:"key" validate:"required"` - Hash [32]byte `json:"hash,omitempty" form:"hash" query:"hash" validate:"required"` Left node Right node } -type emptyNode struct { - parent *branch +var wbranch = widget.ForCompositePtr(widget.Fields[branch]{ + {Name: "type", ID: 1, Widget: widget.ForTag[*nodeType]("type", (*branch).Type)}, + {Name: "height", ID: 2, Widget: widget.ForUint(func(v *branch) *uint64 { return &v.Height })}, + {Name: "key", ID: 3, Widget: widget.ForHash(func(v *branch) *[32]byte { return &v.Key })}, + {Name: "hash", ID: 4, Widget: widget.ForHash(func(v *branch) *[32]byte { return &v.Hash })}, +}, widget.Identity[**branch]) + +func (branch) Type() nodeType { return nodeTypeBranch } + +// Copy returns a copy of the branch. +func (v *branch) Copy() *branch { + var u *branch + wbranch.CopyTo(&u, &v) + return u } -type leaf struct { - Key *record.Key `json:"key,omitempty" form:"key" query:"key" validate:"required"` - Value []byte `json:"value,omitempty" form:"value" query:"value" validate:"required"` - parent *branch +// Equalbranch returns true if V is equal to U. +func (v *branch) Equal(u *branch) bool { + return wbranch.Equal(&v, &u) } -type stateData struct { - RootHash [32]byte `json:"rootHash,omitempty" form:"rootHash" query:"rootHash" validate:"required"` - MaxHeight uint64 `json:"maxHeight,omitempty" form:"maxHeight" query:"maxHeight" validate:"required"` - Power uint64 `json:"power,omitempty" form:"power" query:"power" validate:"required"` - Mask uint64 `json:"mask,omitempty" form:"mask" query:"mask" validate:"required"` +type emptyNode struct { + parent *branch } -func (v *branch) Copy() *branch { - u := new(branch) +var wemptyNode = widget.ForCompositePtr(widget.Fields[emptyNode]{ + {Name: "type", ID: 1, Widget: widget.ForTag[*nodeType]("type", (*emptyNode).Type)}, +}, widget.Identity[**emptyNode]) - u.Height = v.Height - u.Key = v.Key - u.Hash = v.Hash +func (emptyNode) Type() nodeType { return nodeTypeEmpty } +// Copy returns a copy of the emptyNode. +func (v *emptyNode) Copy() *emptyNode { + var u *emptyNode + wemptyNode.CopyTo(&u, &v) return u } -func (v *branch) CopyAsInterface() interface{} { return v.Copy() } - -func (v *emptyNode) Copy() *emptyNode { - u := new(emptyNode) +// EqualemptyNode returns true if V is equal to U. +func (v *emptyNode) Equal(u *emptyNode) bool { + return wemptyNode.Equal(&v, &u) +} - return u +type leaf struct { + Key *record.Key + Value []byte + parent *branch } -func (v *emptyNode) CopyAsInterface() interface{} { return v.Copy() } +var wleaf = widget.ForCompositePtr(widget.Fields[leaf]{ + {Name: "type", ID: 1, Widget: widget.ForTag[*nodeType]("type", (*leaf).Type)}, + {Name: "key", ID: 2, Widget: widget.ForValue(func(v *leaf) **record.Key { return &v.Key })}, + {Name: "value", ID: 3, Widget: widget.ForBytes(func(v *leaf) *[]byte { return &v.Value })}, +}, widget.Identity[**leaf]) +// Copy returns a copy of the leaf. func (v *leaf) Copy() *leaf { - u := new(leaf) + var u *leaf + wleaf.CopyTo(&u, &v) + return u +} - if v.Key != nil { - u.Key = (v.Key).Copy() - } - u.Value = encoding.BytesCopy(v.Value) +// Equalleaf returns true if V is equal to U. +func (v *leaf) Equal(u *leaf) bool { + return wleaf.Equal(&v, &u) +} +// TODO type node interface {} + +var wnode = widget.ForUnion[*nodeType]( + "type", + node.Type, + map[nodeType]widget.UnionMemberFields[node]{ + nodeTypeEmpty: &widget.UnionMember[node, emptyNode]{ + Fields: wemptyNode.Fields, + }, + nodeTypeBranch: &widget.UnionMember[node, branch]{ + Fields: wbranch.Fields, + }, + nodeTypeLeaf: &widget.UnionMember[node, leaf]{ + Fields: wleaf.Fields, + }, + }, + widget.Identity[*node]) + +// copyNode returns a copy of the node. +func copyNode(v node) node { + var u node + wnode.CopyTo(&u, &v) return u } -func (v *leaf) CopyAsInterface() interface{} { return v.Copy() } +// equalNode returns true if A and B are equal. +func equalNode(a, b node) bool { + return wnode.Equal(&a, &b) +} + +type nodeType int64 -func (v *stateData) Copy() *stateData { - u := new(stateData) +const ( + nodeTypeBoundary nodeType = 4 + nodeTypeBranch nodeType = 2 + nodeTypeEmpty nodeType = 1 + nodeTypeLeaf nodeType = 3 + nodeTypeLeafWithExpandedKey nodeType = 5 +) - u.RootHash = v.RootHash - u.MaxHeight = v.MaxHeight - u.Power = v.Power - u.Mask = v.Mask +var wnodeType = widget.ForEnum[*nodeType](widget.Identity[*nodeType]) - return u +// SetByName looks up a nodeType by name. +func (v *nodeType) SetByName(s string) (ok bool) { + *v, ok = snodeType.ByName(s) + return } -func (v *stateData) CopyAsInterface() interface{} { return v.Copy() } +// SetByValue looks up a nodeType by value. +func (v *nodeType) SetByValue(i int64) (ok bool) { + *v, ok = snodeType.ByValue(i) + return +} -func (v *branch) Equal(u *branch) bool { - if !(v.Height == u.Height) { - return false - } - if !(v.Key == u.Key) { - return false - } - if !(v.Hash == u.Hash) { - return false - } +// String returns the label or name of the nodeType. +func (v nodeType) String() string { + return snodeType.String(v) +} - return true +type parameters struct { + Power uint64 + Mask uint64 } -func (v *emptyNode) Equal(u *emptyNode) bool { +var wparameters = widget.ForCompositePtr(widget.Fields[parameters]{ + {Name: "power", ID: 1, Widget: widget.ForUint(func(v *parameters) *uint64 { return &v.Power })}, + {Name: "mask", ID: 2, Widget: widget.ForUint(func(v *parameters) *uint64 { return &v.Mask })}, +}, widget.Identity[**parameters]) - return true +// Copy returns a copy of the parameters. +func (v *parameters) Copy() *parameters { + var u *parameters + wparameters.CopyTo(&u, &v) + return u } -func (v *leaf) Equal(u *leaf) bool { - switch { - case v.Key == u.Key: - // equal - case v.Key == nil || u.Key == nil: - return false - case !((v.Key).Equal(u.Key)): - return false - } - if !(bytes.Equal(v.Value, u.Value)) { - return false - } +// Equalparameters returns true if V is equal to U. +func (v *parameters) Equal(u *parameters) bool { + return wparameters.Equal(&v, &u) +} - return true +type stateData struct { + RootHash [32]byte + MaxHeight uint64 + parameters +} + +var wstateData = widget.ForCompositePtr(widget.Fields[stateData]{ + {Name: "rootHash", ID: 1, Widget: widget.ForHash(func(v *stateData) *[32]byte { return &v.RootHash })}, + {Name: "maxHeight", ID: 2, Widget: widget.ForUint(func(v *stateData) *uint64 { return &v.MaxHeight })}, + {ID: 3, Widget: widget.ForComposite(wparameters.Fields, func(v *stateData) *parameters { return &v.parameters })}, +}, widget.Identity[**stateData]) + +// Copy returns a copy of the stateData. +func (v *stateData) Copy() *stateData { + var u *stateData + wstateData.CopyTo(&u, &v) + return u } +// EqualstateData returns true if V is equal to U. func (v *stateData) Equal(u *stateData) bool { - if !(v.RootHash == u.RootHash) { - return false - } - if !(v.MaxHeight == u.MaxHeight) { - return false - } - if !(v.Power == u.Power) { - return false - } - if !(v.Mask == u.Mask) { - return false - } - - return true + return wstateData.Equal(&v, &u) } diff --git a/pkg/database/bpt/unions_gen.go b/pkg/database/bpt/unions_gen.go deleted file mode 100644 index 838af5820..000000000 --- a/pkg/database/bpt/unions_gen.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2022 The Accumulate Authors -// -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file or at -// https://opensource.org/licenses/MIT. - -package bpt - -// GENERATED BY go run ./tools/cmd/gen-types. DO NOT EDIT. - -import ( - "encoding/json" -) - -// equalNode is used to compare the values of the union -func equalNode(a, b node) bool { - if a == b { - return true - } - switch a := a.(type) { - case *branch: - if a == nil { - return b == nil - } - b, ok := b.(*branch) - return ok && a.Equal(b) - case *emptyNode: - if a == nil { - return b == nil - } - b, ok := b.(*emptyNode) - return ok && a.Equal(b) - case *leaf: - if a == nil { - return b == nil - } - b, ok := b.(*leaf) - return ok && a.Equal(b) - } - return false -} - -// copyNode copies a node. -func copyNode(v node) node { - switch v := v.(type) { - case *branch: - return v.Copy() - case *emptyNode: - return v.Copy() - case *leaf: - return v.Copy() - default: - return v.CopyAsInterface().(node) - } -} - -// unmarshalNodeJson unmarshals a node. -func unmarshalNodeJSON(data []byte) (node, error) { - var typ *struct{ Type nodeType } - err := json.Unmarshal(data, &typ) - if err != nil { - return nil, err - } - - if typ == nil { - return nil, nil - } - - acnt, err := newNode(typ.Type) - if err != nil { - return nil, err - } - - err = json.Unmarshal(data, acnt) - if err != nil { - return nil, err - } - - return acnt, nil -}