WIP Implementing core/ledger
This commit is contained in:
@@ -1,4 +1,46 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.michelsen.id/chron/core"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"lukechampine.com/blake3"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type EntryStore interface {
|
type EntryStore interface {
|
||||||
Append(ctx context.Context, entry Entry) (EntryID, error)
|
Append(ctx context.Context, entry Entry) error
|
||||||
|
|
||||||
Redact(ctx context.Context, entryID EntryID) error
|
|
||||||
|
|
||||||
Get(ctx context.Context, entryID EntryID) (Entry, error)
|
Get(ctx context.Context, entryID EntryID) (Entry, error)
|
||||||
|
GetBySeq(ctx context.Context, ledgerID LedgerID, seq uint64) (Entry, error)
|
||||||
ScanForwards(ctx context.Context, entryID EntryID) ([]EntryID, error)
|
Delete(ctx context.Context, entryID EntryID) error
|
||||||
ScanBackwards(ctx context.Context, entryID EntryID) ([]EntryID, error)
|
|
||||||
|
|
||||||
Head(ctx context.Context, ledgerID LedgerID) (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 {
|
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
|
Delete(ctx context.Context, payloadID PayloadID) error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,107 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"lukechampine.com/blake3"
|
||||||
|
)
|
||||||
|
|
||||||
type Ledger struct {
|
type Ledger struct {
|
||||||
|
LedgerID LedgerID
|
||||||
|
|
||||||
entryStore EntryStore
|
entryStore EntryStore
|
||||||
payloadStore PayloadStore
|
payloadStore PayloadStore
|
||||||
|
|
||||||
LedgerID LedgerID
|
hashChaining bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLedger(entryStore EntryStore, payloadStore PayloadStore) (*Ledger, error) {
|
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")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"lukechampine.com/blake3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LedgerID [16]byte
|
type LedgerID [16]byte
|
||||||
|
|
||||||
type EntryID [16]byte
|
type EntryID [16]byte
|
||||||
type PayloadID [16]byte
|
type PayloadID [16]byte
|
||||||
|
|
||||||
type Hash [32]byte
|
type Hash32 [32]byte
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
EntryID EntryID
|
EntryID EntryID
|
||||||
@@ -19,9 +21,31 @@ type Entry struct {
|
|||||||
|
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
|
|
||||||
Nonce [16]byte
|
PayloadID PayloadID
|
||||||
Commitment Hash
|
PayloadDigest Hash32
|
||||||
|
|
||||||
PreviousHash Hash
|
PreviousHash Hash32
|
||||||
EntryHash Hash
|
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
|
go 1.25.5
|
||||||
|
|
||||||
require github.com/google/uuid v1.6.0
|
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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
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