diff --git a/snapshot/reader.go b/snapshot/reader.go index dd99f94c..02348c8b 100644 --- a/snapshot/reader.go +++ b/snapshot/reader.go @@ -18,7 +18,6 @@ type Reader struct { filename string fl *os.File - buf io.Reader nextOffset uint64 handlers map[SectionName]sectionHandlerFunc @@ -49,6 +48,10 @@ func NewDefaultReader(filename string) (r *Reader, err error) { reader.RegisterSectionHandler(SectionNameResourceLimitsStateObject, readResourceLimitsStateObject) reader.RegisterSectionHandler(SectionNameResourceLimitsConfigObject, readResourceLimitsConfigObject) reader.RegisterSectionHandler(SectionNameGenesisState, readGenesisState) + + // Ultra Specific + reader.RegisterSectionHandler(SectionAccountFreeActionsObject, readAccountFreeActionsObject) + return reader, nil } @@ -67,7 +70,7 @@ func NewReader(filename string) (r *Reader, err error) { return nil, err } - beginOffset, err := r.fl.Seek(0, os.SEEK_CUR) + beginOffset, err := r.fl.Seek(0, io.SeekCurrent) if err != nil { return nil, err } @@ -88,7 +91,7 @@ func (r *Reader) readHeader() (*Header, error) { return nil, err } - if bytes.Compare(buf[:4], magicNumber) != 0 { + if !bytes.Equal(buf[:4], magicNumber) { return nil, fmt.Errorf("invalid magic number (first 4 bytes): %v, expected %v", buf[:4], magicNumber) } @@ -99,19 +102,27 @@ func (r *Reader) readHeader() (*Header, error) { return h, nil } -var SectionHandlerNotFound = errors.New("section handler not found") +var ErrSectionHandlerNotFound = errors.New("section handler not found") + +// Deprecated: Use ErrSectionHandlerNotFound instead +var SectionHandlerNotFound = ErrSectionHandlerNotFound + +func (r *Reader) HasSectionHandler(s *Section) bool { + _, found := r.handlers[r.CurrentSection.Name] + return found +} func (r *Reader) ProcessCurrentSection(f sectionCallbackFunc) error { h, found := r.handlers[r.CurrentSection.Name] if !found { - return SectionHandlerNotFound + return ErrSectionHandlerNotFound } return h(r.CurrentSection, f) } // Next retrieves the next section. func (r *Reader) NextSection() error { - beginOffset, err := r.fl.Seek(int64(r.nextOffset), os.SEEK_SET) + beginOffset, err := r.fl.Seek(int64(r.nextOffset), io.SeekStart) if err != nil { return err } @@ -123,7 +134,7 @@ func (r *Reader) NextSection() error { } // end marker - if bytesRead == 8 && bytes.Compare(vals[:8], []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) == 0 { + if bytesRead == 8 && bytes.Equal(vals[:8], []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) { return io.EOF } diff --git a/snapshot/section.go b/snapshot/section.go index e225dd8c..d738a7ae 100644 --- a/snapshot/section.go +++ b/snapshot/section.go @@ -25,6 +25,9 @@ const ( SectionNameResourceLimitsStateObject SectionName = "eosio::chain::resource_limits::resource_limits_state_object" SectionNameResourceLimitsConfigObject SectionName = "eosio::chain::resource_limits::resource_limits_config_object" SectionNameGenesisState SectionName = "eosio::chain::genesis_state" + + // Ultra Specific + SectionAccountFreeActionsObject SectionName = "eosio::chain::account_free_actions_object" ) type Section struct { diff --git a/snapshot/snapshot_test.go b/snapshot/snapshot_test.go index c45b2e2d..9d6dc152 100644 --- a/snapshot/snapshot_test.go +++ b/snapshot/snapshot_test.go @@ -25,6 +25,7 @@ func TestSnapshotRead(t *testing.T) { testFile string }{ {name: "Battlefield - b8d703ed1", testFile: "battlefield-snapshot.bin"}, + {name: "Ultra - Testnet", testFile: "ultra-testnet-snapshot.bin"}, } for _, test := range tests { @@ -53,8 +54,9 @@ func TestSnapshotRead(t *testing.T) { logger.Info("new section", zap.String("section_name", string(section.Name)), zap.Uint64("row_count", section.RowCount), - zap.Uint64("bytes_count", section.BufferSize), - zap.Uint64("bytes_count", section.Offset), + zap.Uint64("buffer_size", section.BufferSize), + zap.Uint64("offset", section.Offset), + zap.Bool("has_handler", r.HasSectionHandler(section)), ) switch section.Name { case SectionNameAccountObject: @@ -94,6 +96,19 @@ func TestSnapshotRead(t *testing.T) { } return nil })) + + case SectionAccountFreeActionsObject: + require.NoError(t, r.ProcessCurrentSection(func(o interface{}) error { + acc, ok := o.(AccountFreeActionsObject) + if !ok { + return fmt.Errorf("process account free actopms object: unexpected object type: %T", o) + } + logger.Info("new account free actions object", + zap.String("name", string(acc.Name)), + zap.Reflect("object", acc), + ) + return nil + })) } } }) @@ -114,5 +129,5 @@ func fileExists(path string) bool { } func testData(filename string) string { - return filepath.Join("test-data", filename) + return filepath.Join("testdata", filename) } diff --git a/snapshot/test-data/battlefield-snapshot.bin b/snapshot/testdata/battlefield-snapshot.bin similarity index 100% rename from snapshot/test-data/battlefield-snapshot.bin rename to snapshot/testdata/battlefield-snapshot.bin diff --git a/snapshot/testdata/ultra-testnet-snapshot.bin b/snapshot/testdata/ultra-testnet-snapshot.bin new file mode 100644 index 00000000..e3cdb9ce Binary files /dev/null and b/snapshot/testdata/ultra-testnet-snapshot.bin differ diff --git a/snapshot/typesv3.go b/snapshot/typesv3.go index 625621f9..308d4d77 100644 --- a/snapshot/typesv3.go +++ b/snapshot/typesv3.go @@ -914,3 +914,41 @@ func readTransactionObject(section *Section, f sectionCallbackFunc) error { return nil } + +/// Ultra Specific + +type FreeObjectUsage struct { + UserSize eos.Uint64 + UserCount eos.Uint64 + UltraSize eos.Uint64 + UltraCount eos.Uint64 +} + +type AccountFreeActionsObject struct { + Name eos.AccountName + PermissionObject FreeObjectUsage + SharedKey FreeObjectUsage + PermissionLevel FreeObjectUsage + Wait FreeObjectUsage + PermissionLinkObject FreeObjectUsage +} + +func readAccountFreeActionsObject(section *Section, f sectionCallbackFunc) error { + for i := uint64(0); i < section.RowCount; i++ { + a := AccountFreeActionsObject{} + cnt := make([]byte, 8+(8*4)*5) // fixed size of resource_limits_object + _, err := section.Buffer.Read(cnt) + if err != nil { + return err + } + + if err := eos.UnmarshalBinary(cnt, &a); err != nil { + return err + } + + if err := f(a); err != nil { + return err + } + } + return nil +}