Completed minimal Ledger implementation, first tests in chron-cli
This commit is contained in:
@@ -1,46 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"sort"
|
||||
|
||||
"git.michelsen.id/chron/core"
|
||||
"github.com/google/uuid"
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
payload := []byte{0, 1, 0, 1}
|
||||
payloadDigest := blake3.Sum256(payload)
|
||||
|
||||
entryID, err := uuid.NewV7()
|
||||
entryIDBytes, err := entryID.MarshalBinary()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ledgerID, err := uuid.NewV7()
|
||||
ledgerIDBytes, err := ledgerID.MarshalBinary()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
payloadID, err := uuid.NewV7()
|
||||
payloadIDBytes, err := payloadID.MarshalBinary()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
entry := core.Entry{
|
||||
EntryID: core.EntryID(entryIDBytes),
|
||||
LedgerID: core.LedgerID(ledgerIDBytes),
|
||||
Seq: 1,
|
||||
Timestamp: time.Now(),
|
||||
PayloadID: core.PayloadID(payloadIDBytes),
|
||||
PayloadDigest: payloadDigest,
|
||||
}
|
||||
|
||||
entryHash := core.HashEntry(entry)
|
||||
entry.EntryHash = entryHash
|
||||
|
||||
fmt.Printf("Entry: %+v\n", entry)
|
||||
fmt.Printf("EntryHash: %x\n", entryHash)
|
||||
type InProcEntryStore struct {
|
||||
entries map[core.EntryID]core.Entry
|
||||
}
|
||||
|
||||
func (e *InProcEntryStore) Store(ctx context.Context, entry core.Entry) error {
|
||||
if _, ok := e.entries[entry.EntryID]; ok {
|
||||
return errors.New("entry already exists")
|
||||
}
|
||||
e.entries[entry.EntryID] = entry
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *InProcEntryStore) Load(ctx context.Context, id core.EntryID) (core.Entry, error) {
|
||||
entry, ok := e.entries[id]
|
||||
if !ok {
|
||||
return core.Entry{}, errors.New("entry does not exist")
|
||||
}
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
func (e *InProcEntryStore) Exists(ctx context.Context, id core.EntryID) (bool, error) {
|
||||
_, ok := e.entries[id]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (e *InProcEntryStore) Delete(ctx context.Context, id core.EntryID) error {
|
||||
if _, ok := e.entries[id]; !ok {
|
||||
return errors.New("entry does not exist")
|
||||
}
|
||||
delete(e.entries, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
type InProcReferenceStore struct {
|
||||
references map[string]core.EntryID
|
||||
}
|
||||
|
||||
func (r *InProcReferenceStore) Set(ctx context.Context, name string, entryID core.EntryID) error {
|
||||
r.references[name] = entryID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InProcReferenceStore) Get(ctx context.Context, name string) (core.EntryID, bool, error) {
|
||||
entryID, ok := r.references[name]
|
||||
if !ok {
|
||||
return core.EntryID{}, false, nil
|
||||
}
|
||||
return entryID, true, nil
|
||||
}
|
||||
|
||||
func (r *InProcReferenceStore) Delete(ctx context.Context, name string) error {
|
||||
if _, ok := r.references[name]; !ok {
|
||||
return errors.New("reference does not exist")
|
||||
}
|
||||
delete(r.references, name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.TODO()
|
||||
|
||||
entryStore := InProcEntryStore{
|
||||
entries: make(map[core.EntryID]core.Entry),
|
||||
}
|
||||
referenceStore := InProcReferenceStore{
|
||||
references: make(map[string]core.EntryID),
|
||||
}
|
||||
|
||||
ledger, err := core.NewLedger(&entryStore, &referenceStore)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for i := range 500 {
|
||||
data := fmt.Sprintf("test%d", i)
|
||||
|
||||
err = ledger.Append(ctx, []byte(data))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
entries := make([]core.Entry, 0, len(entryStore.entries))
|
||||
for _, e := range entryStore.entries {
|
||||
entries = append(entries, e)
|
||||
}
|
||||
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
if entries[i].Timestamp.Equal(entries[j].Timestamp) {
|
||||
return hex.EncodeToString(entries[i].EntryID[:]) <
|
||||
hex.EncodeToString(entries[j].EntryID[:])
|
||||
}
|
||||
return entries[i].Timestamp.Before(entries[j].Timestamp)
|
||||
})
|
||||
|
||||
fmt.Println("Entries:")
|
||||
if len(entries) == 0 {
|
||||
fmt.Println(" (none)")
|
||||
} else {
|
||||
for _, e := range entries {
|
||||
fmt.Printf(" ts=%d id=%s prev=%s payload=%q\n",
|
||||
e.Timestamp.UnixNano(),
|
||||
hex.EncodeToString(e.EntryID[:]),
|
||||
hex.EncodeToString(e.Previous[:]),
|
||||
e.Payload,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Print references (name -> EntryID hex) ----
|
||||
names := make([]string, 0, len(referenceStore.references))
|
||||
for name := range referenceStore.references {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
fmt.Println("References:")
|
||||
if len(names) == 0 {
|
||||
fmt.Println(" (none)")
|
||||
} else {
|
||||
for _, name := range names {
|
||||
id := referenceStore.references[name]
|
||||
fmt.Printf(" %s -> %s\n", name, hex.EncodeToString(id[:]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user