package types import ( "context" "fmt" "math" "github.com/ethereum/go-ethereum/common" "github.com/synapsecns/sanguine/core/merkle" "github.com/synapsecns/sanguine/ethergo/signer/signer" ) // Snapshot is the snapshot interface. type Snapshot interface { Encoder // States are the states of the snapshot. States() []State // SnapshotRootAndProofs returns the snapshot root, calculated from the states, as well as each state's proof. SnapshotRootAndProofs() ([32]byte, [][][]byte, error) // SignSnapshot returns the signature of the snapshot payload signed by the signer SignSnapshot(ctx context.Context, signer signer.Signer) (signer.Signature, []byte, common.Hash, error) } type snapshot struct { states []State } // NewSnapshot creates a new snapshot. func NewSnapshot(states []State) Snapshot { return &snapshot{ states: states, } } func (s snapshot) States() []State { return s.states } func (s snapshot) SnapshotRootAndProofs() ([32]byte, [][][]byte, error) { tree := merkle.NewTree(merkle.SnapshotTreeHeight) for _, state := range s.states { leftLeaf, rightLeaf, err := state.SubLeaves() if err != nil { return [32]byte{}, nil, fmt.Errorf("failed to hash state: %w", err) } tree.Insert(leftLeaf[:]) tree.Insert(rightLeaf[:]) } snapshotRoot, err := tree.Root(uint32(len(s.states) * 2)) if err != nil { return [32]byte{}, nil, fmt.Errorf("failed to get snapshot root: %w", err) } var snapshotRootB32 [32]byte copy(snapshotRootB32[:], snapshotRoot) proofs := make([][][]byte, len(s.states)*2) for i := 0; i < len(s.states)*2; i += 2 { proofs[i/2], err = tree.MerkleProof(uint32(i), uint32(len(s.states)*2)) if err != nil { return [32]byte{}, nil, fmt.Errorf("failed to get merkle proof: %w", err) } } return snapshotRootB32, proofs, nil } // TreeHeight returns the height of the merkle tree given `len(states)*2` leaves. func (s snapshot) TreeHeight() uint32 { return uint32(math.Log2(float64(len(s.states) * 2))) } func (s snapshot) SignSnapshot(ctx context.Context, signer signer.Signer) (signer.Signature, []byte, common.Hash, error) { return signEncoder(ctx, signer, s, SnapshotValidSalt) } var _ Snapshot = &snapshot{}