WIP change creation logic

This commit is contained in:
mcrakhman 2022-07-07 11:11:34 +02:00 committed by Mikhail Iudin
parent eea64a3014
commit 2f66bd3e9c
No known key found for this signature in database
GPG Key ID: FAAAA8BAABDFF1C0
5 changed files with 229 additions and 3 deletions

View File

@ -33,8 +33,7 @@ func (sb *ACLStateBuilder) Build() (*ACLState, error) {
return state, err
}
func (sb *ACLStateBuilder) Init(
tree *Tree) error {
func (sb *ACLStateBuilder) Init(tree *Tree) error {
root := tree.Root()
if !root.IsSnapshot {
return fmt.Errorf("root should always be a snapshot")

View File

@ -128,7 +128,7 @@ func (tb *ACLTreeBuilder) getACLHeads(heads []string) (aclTreeHeads []string, er
}
precedingHeads, err := tb.getPrecedingACLHeads(head)
if err != nil {
return nil, err
continue
}
for _, aclHead := range precedingHeads {

View File

@ -2,11 +2,15 @@ package data
import (
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/pb"
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/threadmodels"
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
"github.com/gogo/protobuf/proto"
)
type AccountData struct {
Identity string
SignKey threadmodels.SigningPrivKey
EncKey threadmodels.EncryptionPrivKey
}
@ -33,6 +37,12 @@ const (
UpdateResultRebuild
)
type CreateChangePayload struct {
ChangesData proto.Marshaler
ACLData *pb.ACLChangeACLData
Id string // TODO: this is just for testing, because id should be created automatically from content
}
func NewDocument(
thread threadmodels.Thread,
stateProvider InitialStateProvider,
@ -53,6 +63,59 @@ func NewDocument(
}
}
func (d *Document) Create(payload *CreateChangePayload) error {
// TODO: add snapshot creation logic
marshalled, err := payload.ChangesData.Marshal()
if err != nil {
return err
}
encrypted, err := d.docContext.aclState.userReadKeys[d.docContext.aclState.currentReadKeyHash].
Encrypt(marshalled)
if err != nil {
return err
}
aclChange := &pb.ACLChange{
TreeHeadIds: d.docContext.fullTree.Heads(),
AclHeadIds: d.getACLHeads(),
SnapshotBaseId: d.docContext.fullTree.RootId(),
AclData: payload.ACLData,
ChangesData: encrypted,
CurrentReadKeyHash: d.docContext.aclState.currentReadKeyHash,
Timestamp: 0,
Identity: d.accountData.Identity,
}
// TODO: add CID creation logic based on content
ch := NewChange(payload.Id, aclChange)
ch.DecryptedDocumentChange = marshalled
fullMarshalledChange, err := proto.Marshal(aclChange)
if err != nil {
return err
}
signature, err := d.accountData.SignKey.Sign(fullMarshalledChange)
if err != nil {
return err
}
d.docContext.fullTree.AddFast(ch)
err = d.thread.AddChange(&threadmodels.RawChange{
Payload: marshalled,
Signature: signature,
Id: payload.Id,
})
if err != nil {
return err
}
d.thread.SetHeads([]string{ch.Id})
d.thread.SetMaybeHeads([]string{ch.Id})
return nil
}
func (d *Document) Update(changes ...*threadmodels.RawChange) (DocumentState, UpdateResult, error) {
var treeChanges []*Change
@ -133,6 +196,35 @@ func (d *Document) Build() (DocumentState, error) {
return d.build(false)
}
// TODO: this should not be the responsibility of Document, move it somewhere else after testing
func (d *Document) getACLHeads() []string {
var aclTreeHeads []string
for _, head := range d.docContext.fullTree.Heads() {
if slice.FindPos(aclTreeHeads, head) != -1 { // do not scan known heads
continue
}
precedingHeads := d.getPrecedingACLHeads(head)
for _, aclHead := range precedingHeads {
if slice.FindPos(aclTreeHeads, aclHead) != -1 {
continue
}
aclTreeHeads = append(aclTreeHeads, aclHead)
}
}
return aclTreeHeads
}
func (d *Document) getPrecedingACLHeads(head string) []string {
headChange := d.docContext.fullTree.attached[head]
if headChange.Content.GetAclData() != nil {
return []string{head}
} else {
return headChange.Content.AclHeadIds
}
}
func (d *Document) build(fromStart bool) (DocumentState, error) {
d.treeBuilder.Init()
d.aclTreeBuilder.Init()
@ -143,6 +235,7 @@ func (d *Document) build(fromStart bool) (DocumentState, error) {
return nil, err
}
// TODO: remove this from context as this is used only to validate snapshot
d.docContext.aclTree, err = d.aclTreeBuilder.Build()
if err != nil {
return nil, err

View File

@ -64,6 +64,7 @@ func (d *documentStateBuilder) build() (s DocumentState, err error) {
}
func (d *documentStateBuilder) appendFrom(fromId string, init DocumentState) (s DocumentState, err error) {
// TODO: we should do something like state copy probably
s = init
d.tree.Iterate(fromId, func(c *Change) (isContinue bool) {
if c.Id == fromId {

View File

@ -0,0 +1,133 @@
thread:
author: A
changes:
- id: A.1.1
identity: A
aclSnapshot:
userStates:
- identity: A
encryptionKey: key.Enc.A
encryptedReadKeys: [key.Read.1]
permission: admin
snapshot:
text: "some text"
aclChanges:
- userAdd:
identity: A
permission: admin
encryptionKey: key.Enc.A
encryptedReadKeys: [key.Read.1]
changes:
- textAppend:
text: "some text"
readKey: key.Read.1
- id: A.1.2
identity: A
aclChanges:
- userInvite:
acceptKey: key.Sign.Onetime1
encryptionKey: key.Enc.Onetime1
encryptedReadKeys: [key.Read.1]
permissions: writer
- userAdd:
identity: C
permission: reader
encryptionKey: key.Enc.C
encryptedReadKeys: [ key.Read.1 ]
readKey: key.Read.1
- id: A.1.3
identity: A
changes:
- textAppend:
text: "second"
readKey: key.Read.1
- id: B.1.1
identity: B
aclChanges:
- userJoin:
identity: B
encryptionKey: key.Enc.B
acceptSignature: key.Sign.Onetime1
inviteId: A.1.2
encryptedReadKeys: [key.Read.1]
readKey: key.Read.1
- id: B.1.2
identity: B
changes:
- textAppend:
text: "first"
readKey: key.Read.1
- id: C.1.1
identity: C
changes:
- textAppend:
text: "third"
readKey: key.Read.1
keys:
Enc:
- A
- B
- C
- D
- Onetime1
Sign:
- A
- B
- C
- D
- Onetime1
Read:
- 1
graph:
- id: A.1.1
baseSnapshot: A.1.1
- id: A.1.2
baseSnapshot: A.1.1
aclHeads: [A.1.1]
treeHeads: [A.1.1]
- id: B.1.1
baseSnapshot: A.1.1
aclHeads: [A.1.2]
treeHeads: [A.1.2]
- id: B.1.2
baseSnapshot: A.1.1
aclHeads: [B.1.1]
treeHeads: [B.1.1]
- id: A.1.3 # this should be invalid, because it is based on one of the invalid changes
baseSnapshot: A.1.1
aclHeads: [B.1.1]
treeHeads: [B.1.2, C.1.1]
- id: C.1.1 # this should be invalid, because C is a reader
baseSnapshot: A.1.1
aclHeads: [B.1.1]
treeHeads: [B.1.1]
maybeHeads:
- "A.1.3"
updatedChanges:
- id: B.1.3
identity: B
changes:
- textAppend:
text: "second"
readKey: key.Read.1
- id: A.1.4
identity: A
aclChanges:
- userAdd:
identity: D
permission: writer
encryptionKey: key.Enc.D
encryptedReadKeys: [ key.Read.1 ]
changes:
- textAppend:
text: "second"
readKey: key.Read.1
updatedGraph:
- id: B.1.3
baseSnapshot: A.1.1
aclHeads: [ B.1.1 ]
treeHeads: [ B.1.2 ]
- id: A.1.4
baseSnapshot: A.1.1
aclHeads: [ B.1.1 ]
treeHeads: [ B.1.3 ]