ADR 026: General Merkle Proof

Context

We are using raw []byte for merkle proofs in abci.ResponseQuery. It makes hard to handle multilayer merkle proofs and general cases. Here, new interface ProofOperator is defined. The users can defines their own Merkle proof format and layer them easily.

Goals:

  • Layer Merkle proofs without decoding/reencoding
  • Provide general way to chain proofs
  • Make the proof format extensible, allowing thirdparty proof types

Decision

ProofOperator

type ProofOperator is an interface for Merkle proofs. The definition is:

  1. type ProofOperator interface {
  2. Run([][]byte) ([][]byte, error)
  3. GetKey() []byte
  4. ProofOp() ProofOp
  5. }

Since a proof can treat various data type, Run() takes [][]byte as the argument, not []byte. For example, a range proof’s Run() can take multiple key-values as its argument. It will then return the root of the tree for the further process, calculated with the input value.

ProofOperator does not have to be a Merkle proof - it can be a function that transforms the argument for intermediate process e.g. prepending the length to the []byte.

ProofOp

type ProofOp is a protobuf message which is a triple of Type string, Key []byte, and Data []byte. ProofOperator and ProofOpare interconvertible, using ProofOperator.ProofOp() and OpDecoder(), where OpDecoder is a function that each proof type can register for their own encoding scheme. For example, we can add an byte for encoding scheme before the serialized proof, supporting JSON decoding.

Status

Consequences

Positive

  • Layering becomes easier (no encoding/decoding at each step)
  • Thirdparty proof format is available

Negative

  • Larger size for abci.ResponseQuery
  • Unintuitive proof chaining(it is not clear what Run() is doing)
  • Additional codes for registering OpDecoders