mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 19:50:36 +00:00
b49381821f
* done * removed sleep * f * errors.Is(err, io.EOF) instead of err == io.EOF Co-authored-by: yperbasis <andrey.ashikhmin@gmail.com>
239 lines
6.6 KiB
Go
239 lines
6.6 KiB
Go
package trie
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// WitnessStorage is an interface representing a single
|
|
type WitnessStorage interface {
|
|
GetWitnessesForBlock(uint64, uint32) ([]byte, error)
|
|
}
|
|
|
|
// WitnessVersion represents the current version of the block witness
|
|
// in case of incompatible changes it should be updated and the code to migrate the
|
|
// old witness format should be present
|
|
const WitnessVersion = uint8(1)
|
|
|
|
// WitnessHeader contains version information and maybe some future format bits
|
|
// the version is always the 1st bit.
|
|
type WitnessHeader struct {
|
|
Version uint8
|
|
}
|
|
|
|
func (h *WitnessHeader) WriteTo(out *OperatorMarshaller) error {
|
|
_, err := out.WithColumn(ColumnStructure).Write([]byte{h.Version})
|
|
return err
|
|
}
|
|
|
|
func (h *WitnessHeader) LoadFrom(input io.Reader) error {
|
|
version := make([]byte, 1)
|
|
if _, err := input.Read(version); err != nil {
|
|
return err
|
|
}
|
|
|
|
h.Version = version[0]
|
|
return nil
|
|
}
|
|
|
|
func defaultWitnessHeader() WitnessHeader {
|
|
return WitnessHeader{WitnessVersion}
|
|
}
|
|
|
|
type Witness struct {
|
|
Header WitnessHeader
|
|
Operators []WitnessOperator
|
|
}
|
|
|
|
func NewWitness(operands []WitnessOperator) *Witness {
|
|
return &Witness{
|
|
Header: defaultWitnessHeader(),
|
|
Operators: operands,
|
|
}
|
|
}
|
|
|
|
func (w *Witness) WriteInto(out io.Writer) (*BlockWitnessStats, error) {
|
|
statsCollector := NewOperatorMarshaller(out)
|
|
|
|
if err := w.Header.WriteTo(statsCollector); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, op := range w.Operators {
|
|
if err := op.WriteTo(statsCollector); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return statsCollector.GetStats(), nil
|
|
}
|
|
|
|
func NewWitnessFromReader(input io.Reader, trace bool) (*Witness, error) {
|
|
var header WitnessHeader
|
|
if err := header.LoadFrom(input); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if header.Version != WitnessVersion {
|
|
return nil, fmt.Errorf("unexpected witness version: expected %d, got %d", WitnessVersion, header.Version)
|
|
}
|
|
|
|
operatorLoader := NewOperatorUnmarshaller(input)
|
|
|
|
opcode := make([]byte, 1)
|
|
var err error
|
|
operands := make([]WitnessOperator, 0)
|
|
for _, err = input.Read(opcode); ; _, err = input.Read(opcode) {
|
|
if errors.Is(err, io.EOF) {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var op WitnessOperator
|
|
switch OperatorKindCode(opcode[0]) {
|
|
case OpHash:
|
|
op = &OperatorHash{}
|
|
case OpLeaf:
|
|
op = &OperatorLeafValue{}
|
|
case OpAccountLeaf:
|
|
op = &OperatorLeafAccount{}
|
|
case OpCode:
|
|
op = &OperatorCode{}
|
|
case OpBranch:
|
|
op = &OperatorBranch{}
|
|
case OpEmptyRoot:
|
|
op = &OperatorEmptyRoot{}
|
|
case OpExtension:
|
|
op = &OperatorExtension{}
|
|
case OpNewTrie:
|
|
/* end of the current trie, end the function */
|
|
default:
|
|
return nil, fmt.Errorf("unexpected opcode while reading witness: %x", opcode[0])
|
|
}
|
|
|
|
if op == nil {
|
|
break
|
|
}
|
|
|
|
err = op.LoadFrom(operatorLoader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if trace {
|
|
fmt.Printf("read op %T -> %+v\n", op, op)
|
|
}
|
|
|
|
operands = append(operands, op)
|
|
}
|
|
if trace {
|
|
fmt.Println("end of read ***** ")
|
|
}
|
|
if err != nil && err != io.EOF {
|
|
return nil, err
|
|
}
|
|
|
|
return &Witness{Header: header, Operators: operands}, nil
|
|
}
|
|
|
|
func (w *Witness) WriteDiff(w2 *Witness, output io.Writer) {
|
|
if w.Header.Version != w2.Header.Version {
|
|
fmt.Fprintf(output, "w1 header %d; w2 header %d\n", w.Header.Version, w2.Header.Version)
|
|
}
|
|
|
|
if len(w.Operators) != len(w2.Operators) {
|
|
fmt.Fprintf(output, "w1 operands: %d; w2 operands: %d\n", len(w.Operators), len(w2.Operators))
|
|
}
|
|
|
|
length := len(w.Operators)
|
|
if len(w2.Operators) > length {
|
|
length = len(w2.Operators)
|
|
}
|
|
|
|
for i := 0; i < length; i++ {
|
|
var op WitnessOperator
|
|
if i < len(w.Operators) {
|
|
op = w.Operators[i]
|
|
}
|
|
if i >= len(w2.Operators) {
|
|
fmt.Fprintf(output, "unexpected o1[%d] = %T %v; o2[%d] = nil\n", i, op, op, i)
|
|
continue
|
|
}
|
|
switch o1 := op.(type) {
|
|
case *OperatorBranch:
|
|
o2, ok := w2.Operators[i].(*OperatorBranch)
|
|
if !ok {
|
|
fmt.Fprintf(output, "o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
if o1.Mask != o2.Mask {
|
|
fmt.Fprintf(output, "o1[%d].Mask = %v; o2[%d].Mask = %v", i, o1.Mask, i, o2.Mask)
|
|
}
|
|
case *OperatorHash:
|
|
o2, ok := w2.Operators[i].(*OperatorHash)
|
|
if !ok {
|
|
fmt.Fprintf(output, "o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
if !bytes.Equal(o1.Hash.Bytes(), o2.Hash.Bytes()) {
|
|
fmt.Fprintf(output, "o1[%d].Hash = %s; o2[%d].Hash = %s\n", i, o1.Hash.Hex(), i, o2.Hash.Hex())
|
|
}
|
|
case *OperatorCode:
|
|
o2, ok := w2.Operators[i].(*OperatorCode)
|
|
if !ok {
|
|
fmt.Fprintf(output, "o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
if !bytes.Equal(o1.Code, o2.Code) {
|
|
fmt.Fprintf(output, "o1[%d].Code = %x; o2[%d].Code = %x\n", i, o1.Code, i, o2.Code)
|
|
}
|
|
case *OperatorEmptyRoot:
|
|
o2, ok := w2.Operators[i].(*OperatorEmptyRoot)
|
|
if !ok {
|
|
fmt.Fprintf(output, "o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
case *OperatorExtension:
|
|
o2, ok := w2.Operators[i].(*OperatorExtension)
|
|
if !ok {
|
|
fmt.Fprintf(output, "o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
if !bytes.Equal(o1.Key, o2.Key) {
|
|
fmt.Fprintf(output, "extension o1[%d].Key = %x; o2[%d].Key = %x\n", i, o1.Key, i, o2.Key)
|
|
}
|
|
case *OperatorLeafAccount:
|
|
o2, ok := w2.Operators[i].(*OperatorLeafAccount)
|
|
if !ok {
|
|
fmt.Fprintf(output, "o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
if !bytes.Equal(o1.Key, o2.Key) {
|
|
fmt.Fprintf(output, "leafAcc o1[%d].Key = %x; o2[%d].Key = %x\n", i, o1.Key, i, o2.Key)
|
|
}
|
|
if o1.Nonce != o2.Nonce {
|
|
fmt.Fprintf(output, "leafAcc o1[%d].Nonce = %v; o2[%d].Nonce = %v\n", i, o1.Nonce, i, o2.Nonce)
|
|
}
|
|
if o1.Balance.String() != o2.Balance.String() {
|
|
fmt.Fprintf(output, "leafAcc o1[%d].Balance = %v; o2[%d].Balance = %v\n", i, o1.Balance.String(), i, o2.Balance.String())
|
|
}
|
|
if o1.HasCode != o2.HasCode {
|
|
fmt.Fprintf(output, "leafAcc o1[%d].HasCode = %v; o2[%d].HasCode = %v\n", i, o1.HasCode, i, o2.HasCode)
|
|
}
|
|
if o1.HasStorage != o2.HasStorage {
|
|
fmt.Fprintf(output, "leafAcc o1[%d].HasStorage = %v; o2[%d].HasStorage = %v\n", i, o1.HasStorage, i, o2.HasStorage)
|
|
}
|
|
case *OperatorLeafValue:
|
|
o2, ok := w2.Operators[i].(*OperatorLeafValue)
|
|
if !ok {
|
|
fmt.Fprintf(output, "o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
if !bytes.Equal(o1.Key, o2.Key) {
|
|
fmt.Fprintf(output, "leafVal o1[%d].Key = %x; o2[%d].Key = %x\n", i, o1.Key, i, o2.Key)
|
|
}
|
|
if !bytes.Equal(o1.Value, o2.Value) {
|
|
fmt.Fprintf(output, "leafVal o1[%d].Value = %x; o2[%d].Value = %x\n", i, o1.Value, i, o2.Value)
|
|
}
|
|
default:
|
|
o2 := w2.Operators[i]
|
|
fmt.Fprintf(output, "unexpected o1[%d] = %T %+v; o2[%d] = %T %+v\n", i, o1, o1, i, o2, o2)
|
|
}
|
|
}
|
|
}
|