Refactoring doc tree
This commit is contained in:
parent
a957bd3864
commit
1ea9f03f57
@ -1,6 +1,7 @@
|
|||||||
package account
|
package account
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/encryptionkey"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||||
)
|
)
|
||||||
@ -9,5 +10,5 @@ type AccountData struct { // TODO: create a convenient constructor for this
|
|||||||
Identity string // TODO: this is essentially the same as sign key
|
Identity string // TODO: this is essentially the same as sign key
|
||||||
SignKey signingkey.PrivKey
|
SignKey signingkey.PrivKey
|
||||||
EncKey encryptionkey.PrivKey
|
EncKey encryptionkey.PrivKey
|
||||||
Decoder signingkey.PubKeyDecoder
|
Decoder keys.Decoder
|
||||||
}
|
}
|
||||||
|
|||||||
@ -458,12 +458,11 @@ func (a *aclTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
aclChange, err := a.treeBuilder.makeUnverifiedACLChange(raw)
|
ch, err := NewFromRawChange(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := NewChange(id, aclChange)
|
|
||||||
rawChanges = append(rawChanges, raw)
|
rawChanges = append(rawChanges, raw)
|
||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package tree
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/symmetric"
|
||||||
@ -59,6 +61,36 @@ func NewFromRawChange(rawChange *aclpb.RawChange) (*Change, error) {
|
|||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewFromVerifiedRawChange(
|
||||||
|
rawChange *aclpb.RawChange,
|
||||||
|
identityKeys map[string]signingkey.PubKey,
|
||||||
|
decoder keys.Decoder) (*Change, error) {
|
||||||
|
unmarshalled := &aclpb.Change{}
|
||||||
|
err := proto.Unmarshal(rawChange.Payload, unmarshalled)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
identityKey, exists := identityKeys[unmarshalled.Identity]
|
||||||
|
if !exists {
|
||||||
|
key, err := decoder.DecodeFromString(unmarshalled.Identity)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
identityKey = key.(signingkey.PubKey)
|
||||||
|
identityKeys[unmarshalled.Identity] = identityKey
|
||||||
|
}
|
||||||
|
res, err := identityKey.Verify(rawChange.Payload, rawChange.Signature)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !res {
|
||||||
|
return nil, fmt.Errorf("change has incorrect signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewChange(rawChange.Id, unmarshalled), nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewChange(id string, ch *aclpb.Change) *Change {
|
func NewChange(id string, ch *aclpb.Change) *Change {
|
||||||
return &Change{
|
return &Change{
|
||||||
Next: nil,
|
Next: nil,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage/treepb"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage/treepb"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/cid"
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -38,6 +39,12 @@ type docTree struct {
|
|||||||
treeBuilder *treeBuilder
|
treeBuilder *treeBuilder
|
||||||
validator DocTreeValidator
|
validator DocTreeValidator
|
||||||
|
|
||||||
|
difSnapshotBuf []*aclpb.RawChange
|
||||||
|
tmpChangesBuf []*Change
|
||||||
|
notSeenIdxBuf []int
|
||||||
|
|
||||||
|
identityKeys map[string]signingkey.PubKey
|
||||||
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,16 +59,12 @@ func BuildDocTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountDat
|
|||||||
treeBuilder: treeBuilder,
|
treeBuilder: treeBuilder,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
updateListener: listener,
|
updateListener: listener,
|
||||||
|
tmpChangesBuf: make([]*Change, 0, 10),
|
||||||
|
difSnapshotBuf: make([]*aclpb.RawChange, 0, 10),
|
||||||
|
notSeenIdxBuf: make([]int, 0, 10),
|
||||||
|
identityKeys: make(map[string]signingkey.PubKey),
|
||||||
}
|
}
|
||||||
err := docTree.rebuildFromStorage(aclTree)
|
err := docTree.rebuildFromStorage(aclTree, nil)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = docTree.removeOrphans()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = t.SetHeads(docTree.Heads())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -81,7 +84,7 @@ func BuildDocTreeWithIdentity(t treestorage.TreeStorage, acc *account.AccountDat
|
|||||||
return docTree, nil
|
return docTree, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildDocTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, listener TreeUpdateListener, aclTree ACLTree) (DocTree, error) {
|
func BuildDocTree(t treestorage.TreeStorage, decoder keys.Decoder, listener TreeUpdateListener, aclTree ACLTree) (DocTree, error) {
|
||||||
treeBuilder := newTreeBuilder(t, decoder)
|
treeBuilder := newTreeBuilder(t, decoder)
|
||||||
validator := newTreeValidator()
|
validator := newTreeValidator()
|
||||||
|
|
||||||
@ -91,16 +94,12 @@ func BuildDocTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, l
|
|||||||
treeBuilder: treeBuilder,
|
treeBuilder: treeBuilder,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
updateListener: listener,
|
updateListener: listener,
|
||||||
|
tmpChangesBuf: make([]*Change, 0, 10),
|
||||||
|
difSnapshotBuf: make([]*aclpb.RawChange, 0, 10),
|
||||||
|
notSeenIdxBuf: make([]int, 0, 10),
|
||||||
|
identityKeys: make(map[string]signingkey.PubKey),
|
||||||
}
|
}
|
||||||
err := docTree.rebuildFromStorage(aclTree)
|
err := docTree.rebuildFromStorage(aclTree, nil)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = docTree.removeOrphans()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = t.SetHeads(docTree.Heads())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -120,29 +119,10 @@ func BuildDocTree(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder, l
|
|||||||
return docTree, nil
|
return docTree, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docTree) removeOrphans() error {
|
func (d *docTree) rebuildFromStorage(aclTree ACLTree, newChanges []*Change) (err error) {
|
||||||
// removing attached or invalid orphans
|
d.treeBuilder.Init(d.identityKeys)
|
||||||
var toRemove []string
|
|
||||||
|
|
||||||
orphans, err := d.treeStorage.Orphans()
|
d.tree, err = d.treeBuilder.Build(false, newChanges)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, orphan := range orphans {
|
|
||||||
if _, exists := d.tree.attached[orphan]; exists {
|
|
||||||
toRemove = append(toRemove, orphan)
|
|
||||||
}
|
|
||||||
if _, exists := d.tree.invalidChanges[orphan]; exists {
|
|
||||||
toRemove = append(toRemove, orphan)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return d.treeStorage.RemoveOrphans(toRemove...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *docTree) rebuildFromStorage(aclTree ACLTree) (err error) {
|
|
||||||
d.treeBuilder.Init()
|
|
||||||
|
|
||||||
d.tree, err = d.treeBuilder.Build(false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -233,29 +213,34 @@ func (d *docTree) AddContent(ctx context.Context, aclTree ACLTree, content proto
|
|||||||
return rawCh, nil
|
return rawCh, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges ...*aclpb.RawChange) (AddResult, error) {
|
func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges ...*aclpb.RawChange) (addResult AddResult, err error) {
|
||||||
// TODO: make proper error handling, because there are a lot of corner cases where this will break
|
|
||||||
var err error
|
|
||||||
var mode Mode
|
var mode Mode
|
||||||
|
|
||||||
var changes []*Change // TODO: = addChangesBuf[:0] ...
|
// resetting buffers
|
||||||
var notSeenIdx []int
|
d.tmpChangesBuf = d.tmpChangesBuf[:0]
|
||||||
|
d.notSeenIdxBuf = d.notSeenIdxBuf[:0]
|
||||||
|
d.difSnapshotBuf = d.difSnapshotBuf[:0]
|
||||||
|
|
||||||
prevHeads := d.tree.Heads()
|
prevHeads := d.tree.Heads()
|
||||||
|
|
||||||
|
// filtering changes, verifying and unmarshalling them
|
||||||
for idx, ch := range rawChanges {
|
for idx, ch := range rawChanges {
|
||||||
if d.HasChange(ch.Id) {
|
if d.HasChange(ch.Id) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
change, err := NewFromRawChange(ch)
|
var change *Change
|
||||||
// TODO: think what if we will have incorrect signatures on rawChanges, how everything will work
|
change, err = NewFromVerifiedRawChange(ch, d.identityKeys, d.treeBuilder.signingPubKeyDecoder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
return AddResult{}, err
|
||||||
}
|
}
|
||||||
changes = append(changes, change)
|
|
||||||
notSeenIdx = append(notSeenIdx, idx)
|
d.tmpChangesBuf = append(d.tmpChangesBuf, change)
|
||||||
|
d.notSeenIdxBuf = append(d.notSeenIdxBuf, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(notSeenIdx) == 0 {
|
// if no new changes, then returning
|
||||||
|
if len(d.notSeenIdxBuf) == 0 {
|
||||||
return AddResult{
|
return AddResult{
|
||||||
OldHeads: prevHeads,
|
OldHeads: prevHeads,
|
||||||
Heads: prevHeads,
|
Heads: prevHeads,
|
||||||
@ -268,11 +253,15 @@ func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.removeOrphans()
|
// adding to database all the added changes only after they are good
|
||||||
if err != nil {
|
for _, ch := range addResult.Added {
|
||||||
return
|
err = d.treeStorage.AddRawChange(ch)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setting heads
|
||||||
err = d.treeStorage.SetHeads(d.tree.Heads())
|
err = d.treeStorage.SetHeads(d.tree.Heads())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -292,9 +281,10 @@ func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// returns changes that we added to the tree
|
||||||
getAddedChanges := func() []*aclpb.RawChange {
|
getAddedChanges := func() []*aclpb.RawChange {
|
||||||
var added []*aclpb.RawChange
|
var added []*aclpb.RawChange
|
||||||
for _, idx := range notSeenIdx {
|
for _, idx := range d.notSeenIdxBuf {
|
||||||
rawChange := rawChanges[idx]
|
rawChange := rawChanges[idx]
|
||||||
if _, exists := d.tree.attached[rawChange.Id]; exists {
|
if _, exists := d.tree.attached[rawChange.Id]; exists {
|
||||||
added = append(added, rawChange)
|
added = append(added, rawChange)
|
||||||
@ -303,49 +293,37 @@ func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges
|
|||||||
return added
|
return added
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuild := func() (AddResult, error) {
|
// checking if we have some changes with different snapshot and then rebuilding
|
||||||
err = d.rebuildFromStorage(aclTree)
|
for _, ch := range d.tmpChangesBuf {
|
||||||
if err != nil {
|
if ch.SnapshotId != d.tree.RootId() && ch.SnapshotId != "" {
|
||||||
return AddResult{}, err
|
err = d.rebuildFromStorage(aclTree, d.tmpChangesBuf)
|
||||||
}
|
if err != nil {
|
||||||
|
return AddResult{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return AddResult{
|
addResult = AddResult{
|
||||||
OldHeads: prevHeads,
|
OldHeads: prevHeads,
|
||||||
Heads: d.tree.Heads(),
|
Heads: d.tree.Heads(),
|
||||||
Added: getAddedChanges(),
|
Added: getAddedChanges(),
|
||||||
Summary: AddResultSummaryRebuild,
|
Summary: AddResultSummaryRebuild,
|
||||||
}, nil
|
}
|
||||||
}
|
err = nil
|
||||||
|
return
|
||||||
for _, ch := range changes {
|
|
||||||
err = d.treeStorage.AddChange(ch)
|
|
||||||
if err != nil {
|
|
||||||
return AddResult{}, err
|
|
||||||
}
|
|
||||||
err = d.treeStorage.AddOrphans(ch.Id)
|
|
||||||
if err != nil {
|
|
||||||
return AddResult{}, err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = d.tree.Add(changes...)
|
// normal mode of operation, where we don't need to rebuild from database
|
||||||
|
mode = d.tree.Add(d.tmpChangesBuf...)
|
||||||
switch mode {
|
switch mode {
|
||||||
case Nothing:
|
case Nothing:
|
||||||
for _, ch := range changes {
|
addResult = AddResult{
|
||||||
// rebuilding if the snapshot is different from the root
|
|
||||||
if ch.SnapshotId != d.tree.RootId() && ch.SnapshotId != "" {
|
|
||||||
return rebuild()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return AddResult{
|
|
||||||
OldHeads: prevHeads,
|
OldHeads: prevHeads,
|
||||||
Heads: prevHeads,
|
Heads: prevHeads,
|
||||||
Summary: AddResultSummaryNothing,
|
Summary: AddResultSummaryNothing,
|
||||||
}, nil
|
}
|
||||||
|
err = nil
|
||||||
|
return
|
||||||
|
|
||||||
case Rebuild:
|
|
||||||
return rebuild()
|
|
||||||
default:
|
default:
|
||||||
// just rebuilding the state from start without reloading everything from tree storage
|
// just rebuilding the state from start without reloading everything from tree storage
|
||||||
// as an optimization we could've started from current heads, but I didn't implement that
|
// as an optimization we could've started from current heads, but I didn't implement that
|
||||||
@ -354,13 +332,15 @@ func (d *docTree) AddRawChanges(ctx context.Context, aclTree ACLTree, rawChanges
|
|||||||
return AddResult{}, err
|
return AddResult{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return AddResult{
|
addResult = AddResult{
|
||||||
OldHeads: prevHeads,
|
OldHeads: prevHeads,
|
||||||
Heads: d.tree.Heads(),
|
Heads: d.tree.Heads(),
|
||||||
Added: getAddedChanges(),
|
Added: getAddedChanges(),
|
||||||
Summary: AddResultSummaryAppend,
|
Summary: AddResultSummaryAppend,
|
||||||
}, nil
|
}
|
||||||
|
err = nil
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *docTree) Iterate(f func(change *Change) bool) {
|
func (d *docTree) Iterate(f func(change *Change) bool) {
|
||||||
@ -434,12 +414,11 @@ func (d *docTree) ChangesAfterCommonSnapshot(theirPath []string) ([]*aclpb.RawCh
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
aclChange, err := d.treeBuilder.makeUnverifiedACLChange(raw)
|
ch, err := NewFromRawChange(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := NewChange(id, aclChange)
|
|
||||||
rawChanges = append(rawChanges, raw)
|
rawChanges = append(rawChanges, raw)
|
||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/treestorage"
|
||||||
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/keys/asymmetric/signingkey"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
|
||||||
"github.com/gogo/protobuf/proto"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -22,38 +21,39 @@ var (
|
|||||||
type treeBuilder struct {
|
type treeBuilder struct {
|
||||||
cache map[string]*Change
|
cache map[string]*Change
|
||||||
identityKeys map[string]signingkey.PubKey
|
identityKeys map[string]signingkey.PubKey
|
||||||
signingPubKeyDecoder signingkey.PubKeyDecoder
|
signingPubKeyDecoder keys.Decoder
|
||||||
tree *Tree
|
tree *Tree
|
||||||
treeStorage treestorage.TreeStorage
|
treeStorage treestorage.TreeStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTreeBuilder(t treestorage.TreeStorage, decoder signingkey.PubKeyDecoder) *treeBuilder {
|
func newTreeBuilder(t treestorage.TreeStorage, decoder keys.Decoder) *treeBuilder {
|
||||||
return &treeBuilder{
|
return &treeBuilder{
|
||||||
signingPubKeyDecoder: decoder,
|
signingPubKeyDecoder: decoder,
|
||||||
treeStorage: t,
|
treeStorage: t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tb *treeBuilder) Init() {
|
func (tb *treeBuilder) Init(identityKeys map[string]signingkey.PubKey) {
|
||||||
tb.cache = make(map[string]*Change)
|
tb.cache = make(map[string]*Change)
|
||||||
tb.identityKeys = make(map[string]signingkey.PubKey)
|
tb.identityKeys = identityKeys
|
||||||
tb.tree = &Tree{}
|
tb.tree = &Tree{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tb *treeBuilder) Build(fromStart bool) (*Tree, error) {
|
func (tb *treeBuilder) Build(fromStart bool, newChanges []*Change) (*Tree, error) {
|
||||||
var headsAndOrphans []string
|
var headsAndOrphans []string
|
||||||
orphans, err := tb.treeStorage.Orphans()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
heads, err := tb.treeStorage.Heads()
|
heads, err := tb.treeStorage.Heads()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
headsAndOrphans = append(headsAndOrphans, orphans...)
|
|
||||||
headsAndOrphans = append(headsAndOrphans, heads...)
|
|
||||||
|
|
||||||
log.With(zap.Strings("heads", heads), zap.Strings("orphans", orphans)).Debug("building tree")
|
headsAndOrphans = append(headsAndOrphans, heads...)
|
||||||
|
tb.cache = make(map[string]*Change)
|
||||||
|
for _, ch := range newChanges {
|
||||||
|
headsAndOrphans = append(headsAndOrphans, ch.Id)
|
||||||
|
tb.cache[ch.Id] = ch
|
||||||
|
}
|
||||||
|
|
||||||
|
log.With(zap.Strings("heads", heads)).Debug("building tree")
|
||||||
if fromStart {
|
if fromStart {
|
||||||
if err := tb.buildTreeFromStart(headsAndOrphans); err != nil {
|
if err := tb.buildTreeFromStart(headsAndOrphans); err != nil {
|
||||||
return nil, fmt.Errorf("buildTree error: %v", err)
|
return nil, fmt.Errorf("buildTree error: %v", err)
|
||||||
@ -69,8 +69,6 @@ func (tb *treeBuilder) Build(fromStart bool) (*Tree, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tb.cache = make(map[string]*Change)
|
|
||||||
|
|
||||||
return tb.tree, nil
|
return tb.tree, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,53 +182,16 @@ func (tb *treeBuilder) loadChange(id string) (ch *Change, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
verifiedChange, err := tb.makeVerifiedChange(change)
|
// TODO: maybe we can use unverified changes here, because we shouldn't put bad changes in the DB in the first place
|
||||||
|
ch, err = NewFromVerifiedRawChange(change, tb.identityKeys, tb.signingPubKeyDecoder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = NewChange(id, verifiedChange)
|
|
||||||
tb.cache[id] = ch
|
tb.cache[id] = ch
|
||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tb *treeBuilder) verify(identity string, payload, signature []byte) (isVerified bool, err error) {
|
|
||||||
identityKey, exists := tb.identityKeys[identity]
|
|
||||||
if !exists {
|
|
||||||
identityKey, err = tb.signingPubKeyDecoder.DecodeFromString(identity)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tb.identityKeys[identity] = identityKey
|
|
||||||
}
|
|
||||||
return identityKey.Verify(payload, signature)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tb *treeBuilder) makeVerifiedChange(change *aclpb.RawChange) (aclChange *aclpb.Change, err error) {
|
|
||||||
aclChange = new(aclpb.Change)
|
|
||||||
|
|
||||||
// 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 = tb.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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tb *treeBuilder) makeUnverifiedACLChange(change *aclpb.RawChange) (aclChange *aclpb.Change, err error) {
|
|
||||||
aclChange = new(aclpb.Change)
|
|
||||||
err = proto.Unmarshal(change.Payload, aclChange)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tb *treeBuilder) findBreakpoint(heads []string) (breakpoint string, err error) {
|
func (tb *treeBuilder) findBreakpoint(heads []string) (breakpoint string, err error) {
|
||||||
var (
|
var (
|
||||||
ch *Change
|
ch *Change
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user