@@ -196,6 +196,12 @@ func New() VerkleNode {
196196 return newInternalNode (0 )
197197}
198198
199+ func NewStatelessInternal () VerkleNode {
200+ node := new (InternalNode )
201+ node .children = make ([]VerkleNode , NodeWidth )
202+ return node
203+ }
204+
199205// New creates a new leaf node
200206func NewLeafNode (stem []byte , values [][]byte ) * LeafNode {
201207 cfg := GetConfig ()
@@ -296,6 +302,11 @@ func (n *InternalNode) InsertStem(stem []byte, values [][]byte, resolver NodeRes
296302 n .cowChild (nChild )
297303
298304 switch child := n .children [nChild ].(type ) {
305+ case nil :
306+ // Finding nil in a tree means that this is a stateless tree, so
307+ // some information is missing. Typically, this means that the proof
308+ // is incorrect, or that there is a bug in tree reconstruction.
309+ return errMissingNodeInStateless
299310 case Empty :
300311 n .children [nChild ] = NewLeafNode (stem , values )
301312 n .children [nChild ].setDepth (n .depth + 1 )
@@ -351,9 +362,86 @@ func (n *InternalNode) InsertStem(stem []byte, values [][]byte, resolver NodeRes
351362 return nil
352363}
353364
365+ // CreatePath inserts a given stem in the tree, placing it as
366+ // described by stemInfo. Its third parameters is the list of
367+ // commitments that have not been assigned a node. It returns
368+ // the same list, save the commitments that were consumed
369+ // during this call.
370+ func (n * InternalNode ) CreatePath (path []byte , stemInfo stemInfo , comms []* Point , values [][]byte ) ([]* Point , error ) {
371+ if len (path ) == 0 {
372+ return comms , errors .New ("invalid path" )
373+ }
374+
375+ // path is 1 byte long, the leaf node must be created
376+ if len (path ) == 1 {
377+ switch stemInfo .stemType & 3 {
378+ case extStatusAbsentEmpty :
379+ // nothing to do
380+ case extStatusAbsentOther :
381+ // insert poa stem
382+ case extStatusPresent :
383+ // insert stem
384+ newchild := & LeafNode {
385+ commitment : comms [0 ],
386+ stem : stemInfo .stem ,
387+ values : values ,
388+ depth : n .depth + 1 ,
389+ }
390+ n .children [path [0 ]] = newchild
391+ comms = comms [1 :]
392+ if stemInfo .has_c1 {
393+ newchild .c1 = comms [0 ]
394+ comms = comms [1 :]
395+ } else {
396+ newchild .c1 = new (Point )
397+ }
398+ if stemInfo .has_c2 {
399+ newchild .c2 = comms [0 ]
400+ comms = comms [1 :]
401+ } else {
402+ newchild .c2 = new (Point )
403+ }
404+ for b , value := range stemInfo .values {
405+ newchild .values [b ] = value
406+ }
407+ }
408+ return comms , nil
409+ }
410+
411+ switch child := n .children [path [0 ]].(type ) {
412+ case nil :
413+ // create the child node if missing
414+ n .children [path [0 ]] = & InternalNode {
415+ children : make ([]VerkleNode , NodeWidth ),
416+ depth : n .depth + 1 ,
417+ commitment : comms [0 ],
418+ }
419+ comms = comms [1 :]
420+ case * InternalNode :
421+ // nothing else to do
422+ case * LeafNode :
423+ return comms , fmt .Errorf ("error rebuilding the tree from a proof: stem %x leads to an already-existing leaf node at depth %x" , stemInfo .stem , n .depth )
424+ default :
425+ return comms , fmt .Errorf ("error rebuilding the tree from a proof: stem %x leads to an unsupported node type %v" , stemInfo .stem , child )
426+ }
427+
428+ // This should only be used in the context of
429+ // stateless nodes, so panic if another node
430+ // type is found.
431+ child := n .children [path [0 ]].(* InternalNode )
432+
433+ // recurse
434+ return child .CreatePath (path [1 :], stemInfo , comms , values )
435+ }
436+
354437func (n * InternalNode ) GetStem (stem []byte , resolver NodeResolverFn ) ([][]byte , error ) {
355438 nchild := offset2key (stem , n .depth ) // index of the child pointed by the next byte in the key
356439 switch child := n .children [nchild ].(type ) {
440+ case nil :
441+ // Finding nil in a tree means that this is a stateless tree, so
442+ // some information is missing. Typically, this means that the proof
443+ // is incorrect, or that there is a bug in tree reconstruction.
444+ return nil , errMissingNodeInStateless
357445 case Empty :
358446 return nil , nil
359447 case * HashedNode :
@@ -641,7 +729,11 @@ func (n *InternalNode) GetProofItems(keys keylist) (*ProofElements, []byte, [][]
641729 var points [NodeWidth ]* Point
642730 for i , child := range n .children {
643731 fiPtrs [i ] = & fi [i ]
644- points [i ] = child .Commitment ()
732+ if child != nil {
733+ points [i ] = child .Commitment ()
734+ } else {
735+ points [i ] = new (Point )
736+ }
645737 }
646738 toFrMultiple (fiPtrs [:], points [:])
647739
@@ -665,7 +757,7 @@ func (n *InternalNode) GetProofItems(keys keylist) (*ProofElements, []byte, [][]
665757
666758 // Special case of a proof of absence: no children
667759 // commitment, as the value is 0.
668- if _ , ok := n .children [childIdx ].(Empty ); ok {
760+ if _ , ok := n .children [childIdx ].(Empty ); ok || n . children [ childIdx ] == nil {
669761 // A question arises here: what if this proof of absence
670762 // corresponds to several stems? Should the ext status be
671763 // repeated as many times? It would be wasteful, so the
@@ -768,6 +860,9 @@ func (n *InternalNode) toDot(parent, path string) string {
768860 }
769861
770862 for i , child := range n .children {
863+ if child == nil {
864+ continue
865+ }
771866 ret = fmt .Sprintf ("%s%s" , ret , child .toDot (me , fmt .Sprintf ("%s%02x" , path , i )))
772867 }
773868
0 commit comments