WIP document update
This commit is contained in:
parent
2bd5bf742d
commit
0e62047498
@ -38,7 +38,7 @@ func (ch *Change) IsACLChange() bool {
|
||||
return ch.Content.GetAclData() != nil
|
||||
}
|
||||
|
||||
func NewChange(id string, ch *pb.ACLChange) (*Change, error) {
|
||||
func NewChange(id string, ch *pb.ACLChange) *Change {
|
||||
return &Change{
|
||||
Next: nil,
|
||||
PreviousIds: ch.TreeHeadIds,
|
||||
@ -46,10 +46,10 @@ func NewChange(id string, ch *pb.ACLChange) (*Change, error) {
|
||||
Content: ch,
|
||||
SnapshotId: ch.SnapshotBaseId,
|
||||
IsSnapshot: ch.GetAclData().GetAclSnapshot() != nil,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewACLChange(id string, ch *pb.ACLChange) (*Change, error) {
|
||||
func NewACLChange(id string, ch *pb.ACLChange) *Change {
|
||||
return &Change{
|
||||
Next: nil,
|
||||
PreviousIds: ch.AclHeadIds,
|
||||
@ -57,5 +57,5 @@ func NewACLChange(id string, ch *pb.ACLChange) (*Change, error) {
|
||||
Content: ch,
|
||||
SnapshotId: ch.SnapshotBaseId,
|
||||
IsSnapshot: ch.GetAclData().GetAclSnapshot() != nil,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,13 +14,13 @@ type changeLoader struct {
|
||||
identityKeys map[string]threadmodels.SigningPubKey
|
||||
signingPubKeyDecoder threadmodels.SigningPubKeyDecoder
|
||||
thread threadmodels.Thread
|
||||
changeCreator func(id string, ch *pb.ACLChange) (*Change, error)
|
||||
changeCreator func(id string, ch *pb.ACLChange) *Change
|
||||
}
|
||||
|
||||
func newChangeLoader(
|
||||
thread threadmodels.Thread,
|
||||
signingPubKeyDecoder threadmodels.SigningPubKeyDecoder,
|
||||
changeCreator func(id string, ch *pb.ACLChange) (*Change, error)) *changeLoader {
|
||||
changeCreator func(id string, ch *pb.ACLChange) *Change) *changeLoader {
|
||||
return &changeLoader{
|
||||
signingPubKeyDecoder: signingPubKeyDecoder,
|
||||
thread: thread,
|
||||
@ -48,23 +48,12 @@ func (c *changeLoader) loadChange(id string) (ch *Change, err error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
aclChange := new(pb.ACLChange)
|
||||
|
||||
// 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
|
||||
}
|
||||
var verified bool
|
||||
verified, err = c.verify(aclChange.Identity, change.Payload, change.Signature)
|
||||
aclChange, err := c.makeVerifiedACLChange(change)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !verified {
|
||||
err = fmt.Errorf("the signature of the payload cannot be verified")
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch, err = c.changeCreator(id, aclChange)
|
||||
ch = c.changeCreator(id, aclChange)
|
||||
c.cache[id] = ch
|
||||
|
||||
return ch, nil
|
||||
@ -81,3 +70,22 @@ func (c *changeLoader) verify(identity string, payload, signature []byte) (isVer
|
||||
}
|
||||
return identityKey.Verify(payload, signature)
|
||||
}
|
||||
|
||||
func (c *changeLoader) makeVerifiedACLChange(change *threadmodels.RawChange) (aclChange *pb.ACLChange, err error) {
|
||||
aclChange = new(pb.ACLChange)
|
||||
|
||||
// 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
|
||||
}
|
||||
var verified bool
|
||||
verified, err = c.verify(aclChange.Identity, change.Payload, change.Signature)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !verified {
|
||||
err = fmt.Errorf("the signature of the payload cannot be verified")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/pb"
|
||||
"fmt"
|
||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/data/threadmodels"
|
||||
)
|
||||
|
||||
@ -28,10 +28,9 @@ type Document struct {
|
||||
type UpdateResult int
|
||||
|
||||
const (
|
||||
UpdateResultAppend = iota
|
||||
UpdateResultNoAction = iota
|
||||
UpdateResultAppend
|
||||
UpdateResultRebuild
|
||||
UpdateResultExists
|
||||
UpdateResultNoAction
|
||||
)
|
||||
|
||||
func NewDocument(
|
||||
@ -53,8 +52,54 @@ func NewDocument(
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Document) Update(changes []*pb.ACLChange) (DocumentState, UpdateResult, error) {
|
||||
return nil, 0, nil
|
||||
func (d *Document) Update(changes ...*threadmodels.RawChange) (DocumentState, UpdateResult, error) {
|
||||
var treeChanges []*Change
|
||||
|
||||
for _, ch := range changes {
|
||||
aclChange, err := d.treeBuilder.makeVerifiedACLChange(ch)
|
||||
if err != nil {
|
||||
return nil, UpdateResultNoAction, fmt.Errorf("change with id %s is incorrect: %w", ch.Id, err)
|
||||
}
|
||||
|
||||
treeChange := d.treeBuilder.changeCreator(ch.Id, aclChange)
|
||||
treeChanges = append(treeChanges, treeChange)
|
||||
|
||||
err = d.thread.AddChange(ch)
|
||||
if err != nil {
|
||||
return nil, UpdateResultNoAction, fmt.Errorf("change with id %s cannot be added: %w", ch.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ch := range treeChanges {
|
||||
if ch.IsACLChange() {
|
||||
res, err := d.Build()
|
||||
return res, UpdateResultRebuild, err
|
||||
}
|
||||
}
|
||||
|
||||
prevHeads := d.docContext.fullTree.Heads()
|
||||
mode := d.docContext.fullTree.Add(treeChanges...)
|
||||
switch mode {
|
||||
case Nothing:
|
||||
return d.docContext.docState, UpdateResultNoAction, nil
|
||||
case Rebuild:
|
||||
res, err := d.Build()
|
||||
return res, UpdateResultRebuild, err
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// because for every new change we know it was after any of the previous heads
|
||||
// each of previous heads must have same "Next" nodes
|
||||
// so it doesn't matter which one we choose
|
||||
// so we choose first one
|
||||
newState, err := d.docStateBuilder.appendFrom(prevHeads[0])
|
||||
if err != nil {
|
||||
res, _ := d.Build()
|
||||
return res, UpdateResultRebuild, fmt.Errorf("could not add changes to state, rebuilded")
|
||||
}
|
||||
|
||||
return newState, UpdateResultAppend, nil
|
||||
}
|
||||
|
||||
func (d *Document) Build() (DocumentState, error) {
|
||||
@ -77,7 +122,11 @@ func (d *Document) build(fromStart bool) (DocumentState, error) {
|
||||
}
|
||||
|
||||
if !fromStart {
|
||||
d.snapshotValidator.Init(d.docContext.aclTree)
|
||||
err = d.snapshotValidator.Init(d.docContext.aclTree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
valid, err := d.snapshotValidator.ValidateSnapshot(d.docContext.fullTree.root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -62,3 +62,19 @@ func (d *documentStateBuilder) build() (s DocumentState, err error) {
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
|
||||
func (d *documentStateBuilder) appendFrom(fromId string) (s DocumentState, err error) {
|
||||
d.tree.Iterate(fromId, func(c *Change) (isContinue bool) {
|
||||
if c.DecryptedDocumentChange != nil {
|
||||
s, err = s.ApplyChange(c.DecryptedDocumentChange, c.Id)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
|
||||
@ -30,6 +30,26 @@ type ThreadBuilder struct {
|
||||
keychain *Keychain
|
||||
}
|
||||
|
||||
func (t *ThreadBuilder) AddChange(change *threadmodels.RawChange) error {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *ThreadBuilder) MaybeHeads() []string {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t *ThreadBuilder) SetMaybeHeads(heads []string) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (t *ThreadBuilder) SetHeads(heads []string) {
|
||||
//TODO implement me
|
||||
}
|
||||
|
||||
func NewThreadBuilder(keychain *Keychain) *ThreadBuilder {
|
||||
return &ThreadBuilder{
|
||||
allChanges: make(map[string]*threadChange),
|
||||
|
||||
@ -2,16 +2,16 @@ package threadmodels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type Thread interface {
|
||||
ID() string
|
||||
Heads() []string
|
||||
MaybeHeads() []string
|
||||
GetChange(ctx context.Context, recordID string) (*RawChange, error)
|
||||
//SetHeads(heads []string)
|
||||
//AddChanges(*pb.ACLChange)
|
||||
PushChange(payload proto.Marshaler) (id string, err error)
|
||||
SetHeads(heads []string)
|
||||
SetMaybeHeads(heads []string)
|
||||
AddChange(change *RawChange) error
|
||||
}
|
||||
|
||||
type RawChange struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user