WIP Implementing core/ledger
This commit is contained in:
@@ -1,4 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"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)
|
||||
}
|
||||
|
||||
@@ -2,24 +2,27 @@ package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
type EntryStore interface {
|
||||
Append(ctx context.Context, entry Entry) (EntryID, error)
|
||||
|
||||
Redact(ctx context.Context, entryID EntryID) error
|
||||
|
||||
Append(ctx context.Context, entry Entry) error
|
||||
Get(ctx context.Context, entryID EntryID) (Entry, error)
|
||||
|
||||
ScanForwards(ctx context.Context, entryID EntryID) ([]EntryID, error)
|
||||
ScanBackwards(ctx context.Context, entryID EntryID) ([]EntryID, error)
|
||||
GetBySeq(ctx context.Context, ledgerID LedgerID, seq uint64) (Entry, error)
|
||||
Delete(ctx context.Context, entryID EntryID) error
|
||||
|
||||
Head(ctx context.Context, ledgerID LedgerID) (EntryID, error)
|
||||
IsEmpty(ctx context.Context, ledgerID LedgerID) bool
|
||||
HeadSeq(context.Context, LedgerID) (uint64, error)
|
||||
Tail(ctx context.Context, ledgerID LedgerID) (EntryID, error)
|
||||
Iterator(ctx context.Context, ledgerLedgerID, startSeq uint64) (EntryIterator, error)
|
||||
}
|
||||
|
||||
type EntryIterator interface {
|
||||
Next() bool
|
||||
Entry() Entry
|
||||
}
|
||||
|
||||
type PayloadStore interface {
|
||||
Put(ctx context.Context, reader io.Reader) (PayloadID, error)
|
||||
Put(ctx context.Context, payload []byte) (PayloadID, error)
|
||||
Get(ctx context.Context, payloadID PayloadID) ([]byte, error)
|
||||
Delete(ctx context.Context, payloadID PayloadID) error
|
||||
}
|
||||
|
||||
@@ -1,12 +1,107 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
type Ledger struct {
|
||||
LedgerID LedgerID
|
||||
|
||||
entryStore EntryStore
|
||||
payloadStore PayloadStore
|
||||
|
||||
LedgerID LedgerID
|
||||
hashChaining bool
|
||||
}
|
||||
|
||||
func NewLedger(entryStore EntryStore, payloadStore PayloadStore) (*Ledger, error) {
|
||||
id, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idByes, err := id.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Ledger{
|
||||
LedgerID: LedgerID(idByes),
|
||||
entryStore: entryStore,
|
||||
payloadStore: payloadStore,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *Ledger) ID() LedgerID {
|
||||
return l.LedgerID
|
||||
}
|
||||
|
||||
func (l *Ledger) Head() (Entry, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (l *Ledger) Append(ctx context.Context, payload []byte) (EntryID, error) {
|
||||
payloadDigest := blake3.Sum256(payload)
|
||||
payloadID, err := l.payloadStore.Put(ctx, payload)
|
||||
if err != nil {
|
||||
return EntryID{}, err
|
||||
}
|
||||
|
||||
entryID, err := uuid.NewV7()
|
||||
entryIDBytes, err := entryID.MarshalBinary()
|
||||
if err != nil {
|
||||
return EntryID{}, err
|
||||
}
|
||||
|
||||
head, err := l.Head()
|
||||
if err != nil {
|
||||
return EntryID{}, err
|
||||
}
|
||||
|
||||
entry := Entry{
|
||||
EntryID: EntryID(entryIDBytes),
|
||||
LedgerID: l.LedgerID,
|
||||
Seq: head.Seq + 1,
|
||||
Timestamp: time.Now(),
|
||||
PayloadID: payloadID,
|
||||
PayloadDigest: payloadDigest,
|
||||
}
|
||||
|
||||
entryHash := HashEntry(entry)
|
||||
entry.EntryHash = entryHash
|
||||
|
||||
err = l.entryStore.Append(ctx, entry)
|
||||
if err != nil {
|
||||
return EntryID{}, err
|
||||
}
|
||||
|
||||
return EntryID(entryIDBytes), nil
|
||||
}
|
||||
|
||||
func (l *Ledger) Get(ctx context.Context, seq uint64) (Entry, []byte, error) {
|
||||
entry, err := l.entryStore.GetBySeq(ctx, l.LedgerID, seq)
|
||||
if err != nil {
|
||||
return Entry{}, nil, err
|
||||
}
|
||||
payload, err := l.payloadStore.Get(ctx, entry.PayloadID)
|
||||
if err != nil {
|
||||
return Entry{}, nil, err
|
||||
}
|
||||
|
||||
return entry, payload, nil
|
||||
}
|
||||
|
||||
func (l *Ledger) GetEntry(ctx context.Context, seq uint64) (Entry, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (l *Ledger) GetPayload(ctx context.Context, seq uint64) ([]byte, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func (l *Ledger) Iter(ctx context.Context, startSeq uint64) (EntryIterator, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"lukechampine.com/blake3"
|
||||
)
|
||||
|
||||
type LedgerID [16]byte
|
||||
|
||||
type EntryID [16]byte
|
||||
type PayloadID [16]byte
|
||||
|
||||
type Hash [32]byte
|
||||
type Hash32 [32]byte
|
||||
|
||||
type Entry struct {
|
||||
EntryID EntryID
|
||||
@@ -19,9 +21,31 @@ type Entry struct {
|
||||
|
||||
Timestamp time.Time
|
||||
|
||||
Nonce [16]byte
|
||||
Commitment Hash
|
||||
PayloadID PayloadID
|
||||
PayloadDigest Hash32
|
||||
|
||||
PreviousHash Hash
|
||||
EntryHash Hash
|
||||
PreviousHash Hash32
|
||||
EntryHash Hash32
|
||||
}
|
||||
|
||||
func HashEntry(e Entry) Hash32 {
|
||||
b := make([]byte, 0, 128)
|
||||
|
||||
b = append(b, "chron.entry.v1"...)
|
||||
b = append(b, e.LedgerID[:]...)
|
||||
|
||||
var buf [8]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], e.Seq)
|
||||
b = append(b, buf[:]...)
|
||||
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(e.Timestamp.UTC().UnixNano()))
|
||||
b = append(b, buf[:]...)
|
||||
|
||||
b = append(b, e.EntryID[:]...)
|
||||
b = append(b, e.PayloadID[:]...)
|
||||
b = append(b, e.PayloadDigest[:]...)
|
||||
b = append(b, e.PreviousHash[:]...)
|
||||
|
||||
sum := blake3.Sum256(b)
|
||||
return Hash32(sum)
|
||||
}
|
||||
|
||||
5
go.mod
5
go.mod
@@ -3,3 +3,8 @@ module git.michelsen.id/chron
|
||||
go 1.25.5
|
||||
|
||||
require github.com/google/uuid v1.6.0
|
||||
|
||||
require (
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
lukechampine.com/blake3 v1.4.1 // indirect
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1,2 +1,6 @@
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||
|
||||
Reference in New Issue
Block a user