Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/proper mutations queries #35

Merged
merged 67 commits into from
May 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
0b03c64
service type visitor
pyramation Apr 23, 2022
bc7f8ea
build
pyramation Apr 23, 2022
ddc53a3
duration
pyramation Apr 23, 2022
f122df7
proto parser v1
pyramation Apr 26, 2022
16dbd70
simplified proto parser
pyramation Apr 27, 2022
59bbff5
protobuf yarn
pyramation Apr 27, 2022
8e146de
refactor
pyramation Apr 27, 2022
da3fea3
imports
pyramation Apr 27, 2022
6a7a20f
imports
pyramation Apr 27, 2022
ffaf9ba
nested object names
pyramation Apr 27, 2022
225de11
global fixtures
pyramation Apr 28, 2022
eafc22e
global fixtures
pyramation Apr 28, 2022
c19e533
transpiler scaffold
pyramation Apr 28, 2022
212cd09
chore(release): publish
pyramation Apr 28, 2022
cc76db2
add proto-parser
pyramation Apr 28, 2022
36df7a5
ast
pyramation Apr 28, 2022
cfe58db
chore(release): publish
pyramation Apr 28, 2022
8ba6b64
pkg
pyramation Apr 28, 2022
10da29d
pkg
pyramation Apr 28, 2022
7e82207
fixtures
pyramation Apr 28, 2022
c63c17e
ast first test
pyramation Apr 28, 2022
0a1cda0
gogoproto.nullable
pyramation Apr 28, 2022
c4df70a
traverse
pyramation Apr 28, 2022
a7e5a42
fixtures
pyramation Apr 28, 2022
2aba417
prototype spec
pyramation Apr 28, 2022
9b97ed0
enums
pyramation Apr 28, 2022
9f6ddd2
proto enums
pyramation Apr 28, 2022
d0c500b
proto
pyramation Apr 28, 2022
88a4d03
proto encoding and decoding scaffold
pyramation Apr 28, 2022
3ca6fca
fromJSON
pyramation Apr 28, 2022
bbeaf5e
toJSON method
pyramation Apr 28, 2022
d0eed25
fromPartial
pyramation Apr 28, 2022
d337f61
bytes
pyramation Apr 28, 2022
6aaa77a
Long[]
pyramation Apr 29, 2022
e2a3e31
encoding
pyramation Apr 29, 2022
bd85b9f
encode/decode
pyramation Apr 29, 2022
0e59ff0
from json
pyramation Apr 29, 2022
4c4695d
refactor
pyramation Apr 29, 2022
bd7efdf
decode
pyramation Apr 29, 2022
7ee84c5
from partial
pyramation Apr 29, 2022
aa921f4
to-json
pyramation Apr 29, 2022
1f8a59c
cleaner types
pyramation Apr 29, 2022
9d7b7ea
cleanup
pyramation Apr 29, 2022
97f8cf3
to-json
pyramation Apr 29, 2022
242607b
tests
pyramation Apr 29, 2022
a3315ca
encode
pyramation Apr 30, 2022
9880164
from-json
pyramation Apr 30, 2022
3abad09
from-partial
pyramation Apr 30, 2022
9323ce3
cleanup
pyramation Apr 30, 2022
02bd166
decode
pyramation Apr 30, 2022
6abe100
types and tags
pyramation Apr 30, 2022
399c241
wire encoding tag numbers
pyramation Apr 30, 2022
a870889
enums
pyramation Apr 30, 2022
2bb2be2
snapshots
pyramation Apr 30, 2022
bad74ec
traversal
pyramation Apr 30, 2022
a1858bc
better recur
pyramation Apr 30, 2022
99e6293
encoding with type names
pyramation Apr 30, 2022
184eb14
more messages
pyramation Apr 30, 2022
baa4487
proper names
pyramation Apr 30, 2022
99a970b
bool()
pyramation Apr 30, 2022
8256969
google syntax
pyramation Apr 30, 2022
dc6f011
timestamp and duration
pyramation Apr 30, 2022
f9c96e8
keyHash v1
pyramation Apr 30, 2022
8a3501c
test
pyramation Apr 30, 2022
fc9512f
to-json
pyramation Apr 30, 2022
f53165c
fromPartial
pyramation Apr 30, 2022
42d7a51
in32
pyramation Apr 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
234 changes: 234 additions & 0 deletions __fixtures__/chain1/confio/proofs.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
syntax = "proto3";

package ics23;
option go_package = "github.com/confio/ics23/go";

enum HashOp {
// NO_HASH is the default if no data passed. Note this is an illegal argument some places.
NO_HASH = 0;
SHA256 = 1;
SHA512 = 2;
KECCAK = 3;
RIPEMD160 = 4;
BITCOIN = 5; // ripemd160(sha256(x))
}

/**
LengthOp defines how to process the key and value of the LeafOp
to include length information. After encoding the length with the given
algorithm, the length will be prepended to the key and value bytes.
(Each one with it's own encoded length)
*/
enum LengthOp {
// NO_PREFIX don't include any length info
NO_PREFIX = 0;
// VAR_PROTO uses protobuf (and go-amino) varint encoding of the length
VAR_PROTO = 1;
// VAR_RLP uses rlp int encoding of the length
VAR_RLP = 2;
// FIXED32_BIG uses big-endian encoding of the length as a 32 bit integer
FIXED32_BIG = 3;
// FIXED32_LITTLE uses little-endian encoding of the length as a 32 bit integer
FIXED32_LITTLE = 4;
// FIXED64_BIG uses big-endian encoding of the length as a 64 bit integer
FIXED64_BIG = 5;
// FIXED64_LITTLE uses little-endian encoding of the length as a 64 bit integer
FIXED64_LITTLE = 6;
// REQUIRE_32_BYTES is like NONE, but will fail if the input is not exactly 32 bytes (sha256 output)
REQUIRE_32_BYTES = 7;
// REQUIRE_64_BYTES is like NONE, but will fail if the input is not exactly 64 bytes (sha512 output)
REQUIRE_64_BYTES = 8;
}

/**
ExistenceProof takes a key and a value and a set of steps to perform on it.
The result of peforming all these steps will provide a "root hash", which can
be compared to the value in a header.

Since it is computationally infeasible to produce a hash collission for any of the used
cryptographic hash functions, if someone can provide a series of operations to transform
a given key and value into a root hash that matches some trusted root, these key and values
must be in the referenced merkle tree.

The only possible issue is maliablity in LeafOp, such as providing extra prefix data,
which should be controlled by a spec. Eg. with lengthOp as NONE,
prefix = FOO, key = BAR, value = CHOICE
and
prefix = F, key = OOBAR, value = CHOICE
would produce the same value.

With LengthOp this is tricker but not impossible. Which is why the "leafPrefixEqual" field
in the ProofSpec is valuable to prevent this mutability. And why all trees should
length-prefix the data before hashing it.
*/
message ExistenceProof {
bytes key = 1;
bytes value = 2;
LeafOp leaf = 3;
repeated InnerOp path = 4;
}

/*
NonExistenceProof takes a proof of two neighbors, one left of the desired key,
one right of the desired key. If both proofs are valid AND they are neighbors,
then there is no valid proof for the given key.
*/
message NonExistenceProof {
bytes key = 1; // TODO: remove this as unnecessary??? we prove a range
ExistenceProof left = 2;
ExistenceProof right = 3;
}

/*
CommitmentProof is either an ExistenceProof or a NonExistenceProof, or a Batch of such messages
*/
message CommitmentProof {
oneof proof {
ExistenceProof exist = 1;
NonExistenceProof nonexist = 2;
BatchProof batch = 3;
CompressedBatchProof compressed = 4;
}
}

/**
LeafOp represents the raw key-value data we wish to prove, and
must be flexible to represent the internal transformation from
the original key-value pairs into the basis hash, for many existing
merkle trees.

key and value are passed in. So that the signature of this operation is:
leafOp(key, value) -> output

To process this, first prehash the keys and values if needed (ANY means no hash in this case):
hkey = prehashKey(key)
hvalue = prehashValue(value)

Then combine the bytes, and hash it
output = hash(prefix || length(hkey) || hkey || length(hvalue) || hvalue)
*/
message LeafOp {
HashOp hash = 1;
HashOp prehash_key = 2;
HashOp prehash_value = 3;
LengthOp length = 4;
// prefix is a fixed bytes that may optionally be included at the beginning to differentiate
// a leaf node from an inner node.
bytes prefix = 5;
}

/**
InnerOp represents a merkle-proof step that is not a leaf.
It represents concatenating two children and hashing them to provide the next result.

The result of the previous step is passed in, so the signature of this op is:
innerOp(child) -> output

The result of applying InnerOp should be:
output = op.hash(op.prefix || child || op.suffix)

where the || operator is concatenation of binary data,
and child is the result of hashing all the tree below this step.

Any special data, like prepending child with the length, or prepending the entire operation with
some value to differentiate from leaf nodes, should be included in prefix and suffix.
If either of prefix or suffix is empty, we just treat it as an empty string
*/
message InnerOp {
HashOp hash = 1;
bytes prefix = 2;
bytes suffix = 3;
}


/**
ProofSpec defines what the expected parameters are for a given proof type.
This can be stored in the client and used to validate any incoming proofs.

verify(ProofSpec, Proof) -> Proof | Error

As demonstrated in tests, if we don't fix the algorithm used to calculate the
LeafHash for a given tree, there are many possible key-value pairs that can
generate a given hash (by interpretting the preimage differently).
We need this for proper security, requires client knows a priori what
tree format server uses. But not in code, rather a configuration object.
*/
message ProofSpec {
// any field in the ExistenceProof must be the same as in this spec.
// except Prefix, which is just the first bytes of prefix (spec can be longer)
LeafOp leaf_spec = 1;
InnerSpec inner_spec = 2;
// max_depth (if > 0) is the maximum number of InnerOps allowed (mainly for fixed-depth tries)
int32 max_depth = 3;
// min_depth (if > 0) is the minimum number of InnerOps allowed (mainly for fixed-depth tries)
int32 min_depth = 4;
}

/*
InnerSpec contains all store-specific structure info to determine if two proofs from a
given store are neighbors.

This enables:

isLeftMost(spec: InnerSpec, op: InnerOp)
isRightMost(spec: InnerSpec, op: InnerOp)
isLeftNeighbor(spec: InnerSpec, left: InnerOp, right: InnerOp)
*/
message InnerSpec {
// Child order is the ordering of the children node, must count from 0
// iavl tree is [0, 1] (left then right)
// merk is [0, 2, 1] (left, right, here)
repeated int32 child_order = 1;
int32 child_size = 2;
int32 min_prefix_length = 3;
int32 max_prefix_length = 4;
// empty child is the prehash image that is used when one child is nil (eg. 20 bytes of 0)
bytes empty_child = 5;
// hash is the algorithm that must be used for each InnerOp
HashOp hash = 6;
}

/*
BatchProof is a group of multiple proof types than can be compressed
*/
message BatchProof {
repeated BatchEntry entries = 1;
}

// Use BatchEntry not CommitmentProof, to avoid recursion
message BatchEntry {
oneof proof {
ExistenceProof exist = 1;
NonExistenceProof nonexist = 2;
}
}


/****** all items here are compressed forms *******/

message CompressedBatchProof {
repeated CompressedBatchEntry entries = 1;
repeated InnerOp lookup_inners = 2;
}

// Use BatchEntry not CommitmentProof, to avoid recursion
message CompressedBatchEntry {
oneof proof {
CompressedExistenceProof exist = 1;
CompressedNonExistenceProof nonexist = 2;
}
}

message CompressedExistenceProof {
bytes key = 1;
bytes value = 2;
LeafOp leaf = 3;
// these are indexes into the lookup_inners table in CompressedBatchProof
repeated int32 path = 4;
}

message CompressedNonExistenceProof {
bytes key = 1; // TODO: remove this as unnecessary??? we prove a range
CompressedExistenceProof left = 2;
CompressedExistenceProof right = 3;
}
36 changes: 36 additions & 0 deletions __fixtures__/chain1/cosmos/app/v1alpha1/config.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
syntax = "proto3";

package cosmos.app.v1alpha1;

import "google/protobuf/any.proto";

// Config represents the configuration for a Cosmos SDK ABCI app.
// It is intended that all state machine logic including the version of
// baseapp and tx handlers (and possibly even Tendermint) that an app needs
// can be described in a config object. For compatibility, the framework should
// allow a mixture of declarative and imperative app wiring, however, apps
// that strive for the maximum ease of maintainability should be able to describe
// their state machine with a config object alone.
message Config {
// modules are the module configurations for the app.
repeated ModuleConfig modules = 1;
}

// ModuleConfig is a module configuration for an app.
message ModuleConfig {
// name is the unique name of the module within the app. It should be a name
// that persists between different versions of a module so that modules
// can be smoothly upgraded to new versions.
//
// For example, for the module cosmos.bank.module.v1.Module, we may chose
// to simply name the module "bank" in the app. When we upgrade to
// cosmos.bank.module.v2.Module, the app-specific name "bank" stays the same
// and the framework knows that the v2 module should receive all the same state
// that the v1 module had. Note: modules should provide info on which versions
// they can migrate from in the ModuleDescriptor.can_migration_from field.
string name = 1;

// config is the config object for the module. Module config messages should
// define a ModuleDescriptor using the cosmos.app.v1alpha1.is_module extension.
google.protobuf.Any config = 2;
}
93 changes: 93 additions & 0 deletions __fixtures__/chain1/cosmos/app/v1alpha1/module.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
syntax = "proto3";

package cosmos.app.v1alpha1;

import "google/protobuf/descriptor.proto";

extend google.protobuf.MessageOptions {
// module indicates that this proto type is a config object for an app module
// and optionally provides other descriptive information about the module.
// It is recommended that a new module config object and go module is versioned
// for every state machine breaking version of a module. The recommended
// pattern for doing this is to put module config objects in a separate proto
// package from the API they expose. Ex: the cosmos.group.v1 API would be
// exposed by module configs cosmos.group.module.v1, cosmos.group.module.v2, etc.
ModuleDescriptor module = 57193479;
}

// ModuleDescriptor describes an app module.
message ModuleDescriptor {
// go_import names the package that should be imported by an app to load the
// module in the runtime module registry. Either go_import must be defined here
// or the go_package option must be defined at the file level to indicate
// to users where to location the module implementation. go_import takes
// precedence over go_package when both are defined.
string go_import = 1;

// use_package refers to a protobuf package that this module
// uses and exposes to the world. In an app, only one module should "use"
// or own a single protobuf package. It is assumed that the module uses
// all of the .proto files in a single package.
repeated PackageReference use_package = 2;

// can_migrate_from defines which module versions this module can migrate
// state from. The framework will check that one module version is able to
// migrate from a previous module version before attempting to update its
// config. It is assumed that modules can transitively migrate from earlier
// versions. For instance if v3 declares it can migrate from v2, and v2
// declares it can migrate from v1, the framework knows how to migrate
// from v1 to v3, assuming all 3 module versions are registered at runtime.
repeated MigrateFromInfo can_migrate_from = 3;
}

// PackageReference is a reference to a protobuf package used by a module.
message PackageReference {
// name is the fully-qualified name of the package.
string name = 1;

// revision is the optional revision of the package that is being used.
// Protobuf packages used in Cosmos should generally have a major version
// as the last part of the package name, ex. foo.bar.baz.v1.
// The revision of a package can be thought of as the minor version of a
// package which has additional backwards compatible definitions that weren't
// present in a previous version.
//
// A package should indicate its revision with a source code comment
// above the package declaration in one of its fields containing the
// test "Revision N" where N is an integer revision. All packages start
// at revision 0 the first time they are released in a module.
//
// When a new version of a module is released and items are added to existing
// .proto files, these definitions should contain comments of the form
// "Since Revision N" where N is an integer revision.
//
// When the module runtime starts up, it will check the pinned proto
// image and panic if there are runtime protobuf definitions that are not
// in the pinned descriptor which do not have
// a "Since Revision N" comment or have a "Since Revision N" comment where
// N is <= to the revision specified here. This indicates that the protobuf
// files have been updated, but the pinned file descriptor hasn't.
//
// If there are items in the pinned file descriptor with a revision
// greater than the value indicated here, this will also cause a panic
// as it may mean that the pinned descriptor for a legacy module has been
// improperly updated or that there is some other versioning discrepancy.
// Runtime protobuf definitions will also be checked for compatibility
// with pinned file descriptors to make sure there are no incompatible changes.
//
// This behavior ensures that:
// * pinned proto images are up-to-date
// * protobuf files are carefully annotated with revision comments which
// are important good client UX
// * protobuf files are changed in backwards and forwards compatible ways
uint32 revision = 2;
}

// MigrateFromInfo is information on a module version that a newer module
// can migrate from.
message MigrateFromInfo {

// module is the fully-qualified protobuf name of the module config object
// for the previous module version, ex: "cosmos.group.module.v1.Module".
string module = 1;
}
22 changes: 22 additions & 0 deletions __fixtures__/chain1/cosmos/app/v1alpha1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
syntax = "proto3";

package cosmos.app.v1alpha1;

import "cosmos/app/v1alpha1/config.proto";

// Query is the app module query service.
service Query {

// Config returns the current app config.
rpc Config(QueryConfigRequest) returns (QueryConfigResponse) {}
}

// QueryConfigRequest is the Query/Config request type.
message QueryConfigRequest {}

// QueryConfigRequest is the Query/Config response type.
message QueryConfigResponse {

// config is the current app config.
Config config = 1;
}
Loading