From 126d080c63b90fab2f97f896ff6a2da236e28542 Mon Sep 17 00:00:00 2001 From: mcrakhman Date: Sun, 10 Jul 2022 11:44:02 +0200 Subject: [PATCH] WIP Change interface rework --- aclchanges/change.go | 10 ++++++ acltree/acltree.go | 21 +++++-------- acltree/acltreebuilder.go | 2 +- acltree/change.go | 17 ++++++++++ acltree/tree.go | 4 +++ acltree/treebuilder.go | 2 +- exampledocument/document.go | 3 +- testutils/threadbuilder/threadbuilder.go | 40 +++++++++++++++++++++--- thread/models.go | 15 ++++++--- 9 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 aclchanges/change.go diff --git a/aclchanges/change.go b/aclchanges/change.go new file mode 100644 index 00000000..f8253ace --- /dev/null +++ b/aclchanges/change.go @@ -0,0 +1,10 @@ +package aclchanges + +import "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges/pb" + +type Change interface { + ProtoChange() *pb.ACLChange + DecryptedChangeContent() []byte + Signature() []byte + CID() string +} diff --git a/acltree/acltree.go b/acltree/acltree.go index 13f7e769..1cb83da7 100644 --- a/acltree/acltree.go +++ b/acltree/acltree.go @@ -32,7 +32,7 @@ type ACLTree interface { Heads() []string Iterate(func(change *Change) bool) IterateFrom(string, func(change *Change) bool) - HasChange(change *Change) bool + HasChange(string) bool } type aclTree struct { @@ -225,7 +225,7 @@ func (a *aclTree) AddContent(changeContent *ChangeContent) (*Change, error) { } a.fullTree.AddFast(ch) - err = a.thread.AddChange(&thread.RawChange{ + err = a.thread.AddRawChange(&thread.RawChange{ Payload: marshalled, Signature: signature, Id: changeContent.Id, @@ -245,28 +245,23 @@ func (a *aclTree) AddChanges(changes ...*Change) (AddResult, error) { aclChanges = append(aclChanges, ch) break } + a.thread.A } // TODO: understand the common snapshot problem prevHeads := a.fullTree.Heads() - prevRoot := a. mode := a.fullTree.Add(changes...) switch mode { - case acltree.Nothing: - return d.docContext.docState, UpdateResultNoAction, nil - case acltree.Rebuild: + case Nothing: + return AddResult{Summary: AddResultSummaryNothing}, nil + case Rebuild: res, err := d.Build() - return res, UpdateResultRebuild, err + return AddResult{Summary: Rebuild}, err default: break } } -func (a *aclTree) Heads() []string { - //TODO implement me - panic("implement me") -} - func (a *aclTree) Iterate(f func(change *Change) bool) { //TODO implement me panic("implement me") @@ -277,7 +272,7 @@ func (a *aclTree) IterateFrom(s string, f func(change *Change) bool) { panic("implement me") } -func (a *aclTree) HasChange(change *Change) bool { +func (a *aclTree) HasChange(s string) bool { //TODO implement me panic("implement me") } diff --git a/acltree/acltreebuilder.go b/acltree/acltreebuilder.go index 4396da6e..83d7afd3 100644 --- a/acltree/acltreebuilder.go +++ b/acltree/acltreebuilder.go @@ -38,7 +38,7 @@ func (tb *aclTreeBuilder) init() { } func (tb *aclTreeBuilder) build() (*Tree, error) { - heads := tb.thread.MaybeHeads() + heads := tb.thread.PossibleHeads() aclHeads, err := tb.getACLHeads(heads) if err != nil { return nil, err diff --git a/acltree/change.go b/acltree/change.go index 0973d55e..40a168d0 100644 --- a/acltree/change.go +++ b/acltree/change.go @@ -25,6 +25,7 @@ type Change struct { DecryptedDocumentChange []byte Content *pb.ACLChange + Sign []byte } func (ch *Change) DecryptContents(key *symmetric.Key) error { @@ -66,3 +67,19 @@ func NewACLChange(id string, ch *pb.ACLChange) *Change { IsSnapshot: ch.GetAclData().GetAclSnapshot() != nil, } } + +func (ch *Change) ProtoChange() *pb.ACLChange { + return ch.Content +} + +func (ch *Change) DecryptedChangeContent() []byte { + return ch.DecryptedDocumentChange +} + +func (ch *Change) Signature() []byte { + return ch.Sign +} + +func (ch *Change) CID() string { + return ch.Id +} diff --git a/acltree/tree.go b/acltree/tree.go index 6b4525e9..326ebcad 100644 --- a/acltree/tree.go +++ b/acltree/tree.go @@ -33,6 +33,10 @@ type Tree struct { duplicateEvents int } +func (t *Tree) GetUnattachedChanges(changes ...*Change) []*Change { + return nil +} + func (t *Tree) RootId() string { if t.root != nil { return t.root.Id diff --git a/acltree/treebuilder.go b/acltree/treebuilder.go index 96de435f..8196046e 100644 --- a/acltree/treebuilder.go +++ b/acltree/treebuilder.go @@ -46,7 +46,7 @@ func (tb *treeBuilder) init() { } func (tb *treeBuilder) build(fromStart bool) (*Tree, error) { - heads := tb.thread.MaybeHeads() + heads := tb.thread.PossibleHeads() if fromStart { if err := tb.buildTreeFromStart(heads); err != nil { diff --git a/exampledocument/document.go b/exampledocument/document.go index f9f9e1d6..d196b111 100644 --- a/exampledocument/document.go +++ b/exampledocument/document.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/acltree" "github.com/anytypeio/go-anytype-infrastructure-experiments/data/pb" + "github.com/anytypeio/go-anytype-infrastructure-experiments/thread" "github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice" "github.com/gogo/protobuf/proto" ) @@ -144,7 +145,7 @@ func (d *Document) Update(changes ...*thread.RawChange) (DocumentState, UpdateRe treeChange := d.treeBuilder.changeCreator(ch.Id, aclChange) treeChanges = append(treeChanges, treeChange) - // this already sets MaybeHeads to include new changes + // this already sets PossibleHeads to include new changes // TODO: change this behaviour as non-obvious, because it is not evident from the interface err = d.thread.AddChange(ch) if err != nil { diff --git a/testutils/threadbuilder/threadbuilder.go b/testutils/threadbuilder/threadbuilder.go index b7507b9f..9d695479 100644 --- a/testutils/threadbuilder/threadbuilder.go +++ b/testutils/threadbuilder/threadbuilder.go @@ -3,6 +3,7 @@ package threadbuilder import ( "context" "fmt" + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges" "io/ioutil" "github.com/gogo/protobuf/proto" @@ -77,11 +78,10 @@ func (t *ThreadBuilder) Heads() []string { return t.heads } -func (t *ThreadBuilder) AddChange(change *thread.RawChange) error { +func (t *ThreadBuilder) AddRawChange(change *thread.RawChange) error { aclChange := new(pb.ACLChange) var err error - // TODO: think what should we do with such cases, because this can be used by attacker to break our tree if err = proto.Unmarshal(change.Payload, aclChange); err != nil { return fmt.Errorf("could not unmarshall changes") } @@ -98,7 +98,6 @@ func (t *ThreadBuilder) AddChange(change *thread.RawChange) error { // get correct signing key signKey := t.keychain.SigningKeysByIdentity[aclChange.Identity] - t.maybeHeads = append(t.maybeHeads, change.Id) t.allChanges[change.Id] = &threadChange{ ACLChange: aclChange, @@ -110,11 +109,42 @@ func (t *ThreadBuilder) AddChange(change *thread.RawChange) error { return nil } -func (t *ThreadBuilder) MaybeHeads() []string { +func (t *ThreadBuilder) AddPossibleHead(head string) { + t.maybeHeads = append(t.maybeHeads, head) +} + +func (t *ThreadBuilder) AddChange(change aclchanges.Change) error { + aclChange := change.ProtoChange() + var err error + var changesData []byte + + // get correct readkey + readKey := t.keychain.ReadKeysByHash[aclChange.CurrentReadKeyHash] + if aclChange.ChangesData != nil { + changesData, err = readKey.Key.Decrypt(aclChange.ChangesData) + if err != nil { + return fmt.Errorf("failed to decrypt changes data: %w", err) + } + } + + // get correct signing key + signKey := t.keychain.SigningKeysByIdentity[aclChange.Identity] + + t.allChanges[change.CID()] = &threadChange{ + ACLChange: aclChange, + id: change.CID(), + readKey: readKey, + signKey: signKey, + changesDataDecrypted: changesData, + } + return nil +} + +func (t *ThreadBuilder) PossibleHeads() []string { return t.maybeHeads } -func (t *ThreadBuilder) SetMaybeHeads(heads []string) { +func (t *ThreadBuilder) SetPossibleHeads(heads []string) { // we should copy here instead of just setting the value t.maybeHeads = heads } diff --git a/thread/models.go b/thread/models.go index 3dee82e1..89e0737c 100644 --- a/thread/models.go +++ b/thread/models.go @@ -2,16 +2,23 @@ package thread import ( "context" + + "github.com/anytypeio/go-anytype-infrastructure-experiments/aclchanges" ) +// TODO: change methods to have errors as a return parameter, because we will be dealing with a real database type Thread interface { ID() string + Heads() []string - MaybeHeads() []string - GetChange(ctx context.Context, recordID string) (*RawChange, error) + PossibleHeads() []string SetHeads(heads []string) - SetMaybeHeads(heads []string) - AddChange(change *RawChange) error + SetPossibleHeads(heads []string) + AddPossibleHead(head string) + + AddRawChange(change *RawChange) error + AddChange(change aclchanges.Change) error + GetChange(ctx context.Context, recordID string) (*RawChange, error) } type RawChange struct {