From 4719e561dd6efdbc5a95213f8cc4dafdcd3eadf6 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 1 Feb 2019 15:49:57 -0500 Subject: [PATCH 01/41] WIP on spec for data module [#163655142] --- x/.gitignore | 1 + x/data/README.md | 8 ----- x/data/README.org | 74 +++++++++++++++++++++++++++++++++++++++++++++++ x/data/types.go | 44 ++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 x/.gitignore delete mode 100644 x/data/README.md create mode 100644 x/data/README.org create mode 100644 x/data/types.go diff --git a/x/.gitignore b/x/.gitignore new file mode 100644 index 000000000..0b84df0f0 --- /dev/null +++ b/x/.gitignore @@ -0,0 +1 @@ +*.html \ No newline at end of file diff --git a/x/data/README.md b/x/data/README.md deleted file mode 100644 index 49a21ac0e..000000000 --- a/x/data/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Data Module - -This module provides very basic support for hashing and time-stamping data onto -the blockchain. It serves the purpose of providing a way that any piece of data -can be tracked onto the blockchain for a fee and known to have existed at or -before some given block-height. It is intended that this module will mostly -be supplanted by other more domain specific functionality and/or -enhanced with robust, opt-in schema-validation support in the future. \ No newline at end of file diff --git a/x/data/README.org b/x/data/README.org new file mode 100644 index 000000000..1e5b128d6 --- /dev/null +++ b/x/data/README.org @@ -0,0 +1,74 @@ +#+TITLE: Data Module +*STATUS: PARTIAL* +* Overview + :PROPERTIES: + :CUSTOM_ID: overview + :END: + +This module provides very basic support for hashing and time-stamping data onto +the blockchain. It serves the purpose of providing a way that any piece of data +can be tracked onto the blockchain for a fee and known to have existed at or +before some given block-height. It is intended that this module will mostly +be supplanted by other more domain specific functionality and/or +enhanced with robust, opt-in schema-validation support in the future. + +* Requirements + :PROPERTIES: + :CUSTOM_ID: requirements + :END: + +- It should be possible to store arbitrary data on the blockchain for a fee +- It should be possible to track arbitrary off-chain data by hash on the blockchain, thus generating a proof of timestamp +- On-chain and off-chain data should be available in the index available to oracles +- There must be a robust way for dealing with hash collisions, especially with respect to off-chain data whose content is opaque + +* Transaction Messages and Types +#+BEGIN_SRC go :tangle types.go :comments link :exports none +// DO NOT EDIT THIS FILE + package data +#+END_SRC + +#+BEGIN_SRC go :tangle types.go :comments link + type DataFormat int + + const ( + Unknown DataFormat = 0 + NQuads DataFormat = 1 + JSON_LD DataFormat = 2 + JSON DataFormat = 3 + Turtle DataFormat = 4 + TRIG DataFormat = 5 + ) + + type HashAlgorithm int + + const ( + BLAKE2B_256 HashAlgorithm = 0 + SHA256 HashAlgorithm = 1 + URDNA2015 HashAlgorithm = 2 + URGNA2012 HashAlgorithm = 3 + ) + + type MsgStoreData struct { + Data []byte `json:"data"` + Format DataFormat `json:"format,omitempty"` + } + + type MsgStoreGraph struct { + NQuads string `json:"nquads"` + URDNA2015Hash []byte `json:"urdna2015_hash"` + Signers []sdk.AccAddress `json:"signers"` + } + + type MsgTrackData struct { + Hash []byte `json:"hash"` + Algorithm HashAlgorithm `json:"algorithm"` + Format DataFormat `json:"format,omitempty"` + Url string `json:"url,omitempty"` + } +#+END_SRC + +** TODO should data format (i.e. JSON/JSON-LD/etc.) and/or schema (i.e. SCHACL/SHEX/JSON-SCHEMA) be tracked and/or verified on-chain? + It might be useful to track format on-chain but not verify it. For a given format there could be multiple schemas that it satisfies. My current thoughts are that this is a type of verification/validation that can be done off chain and there can be on-chain attestations about that - ARC. + +* Queries and Indexing diff --git a/x/data/types.go b/x/data/types.go new file mode 100644 index 000000000..580454dff --- /dev/null +++ b/x/data/types.go @@ -0,0 +1,44 @@ +// [[file:~/regen-ledger/x/data/README.org::*Transaction%20Messages%20and%20Types][Transaction Messages and Types:1]] +// DO NOT EDIT THIS FILE + package data +// Transaction Messages and Types:1 ends here + +// [[file:~/regen-ledger/x/data/README.org::*Transaction%20Messages%20and%20Types][Transaction Messages and Types:2]] +type DataFormat int + +const ( + Unknown DataFormat = 0 + NQuads DataFormat = 1 + JSON_LD DataFormat = 2 + JSON DataFormat = 3 + Turtle DataFormat = 4 + TRIG DataFormat = 5 +) + +type HashAlgorithm int + +const ( + BLAKE2B_256 HashAlgorithm = 0 + SHA256 HashAlgorithm = 1 + URDNA2015 HashAlgorithm = 2 + URGNA2012 HashAlgorithm = 3 +) + +type MsgStoreData struct { + Data []byte `json:"data"` + Format DataFormat `json:"format,omitempty"` +} + +type MsgStoreGraph struct { + NQuads string `json:"nquads"` + URDNA2015Hash []byte `json:"urdna2015_hash"` + Signers []sdk.AccAddress `json:"signers"` +} + +type MsgTrackData struct { + Hash []byte `json:"hash"` + Algorithm HashAlgorithm `json:"algorithm"` + Format DataFormat `json:"format,omitempty"` + Url string `json:"url,omitempty"` +} +// Transaction Messages and Types:2 ends here -- GitLab From 7f94104d6e433522ad3931a1414ede312deaa36d Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 1 Feb 2019 17:23:17 -0500 Subject: [PATCH 02/41] WIP on data module specs [#163655142] --- docs/ucr.org | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs/ucr.org diff --git a/docs/ucr.org b/docs/ucr.org new file mode 100644 index 000000000..c814cbb94 --- /dev/null +++ b/docs/ucr.org @@ -0,0 +1,19 @@ +#+TITLE: Use Cases and Requirements +* Use Cases +* Requirements +** It should be possible to store arbitrary data on the blockchain for a fee + :PROPERTIES: + :CUSTOM_ID: R-StoreData + :END: +** It should be possible to track arbitrary off-chain data by hash on the blockchain, thus generating a proof of timestamp + :PROPERTIES: + :CUSTOM_ID: R-TrackData + :END: +** On-chain and off-chain data should be available in the index available to oracles + :PROPERTIES: + :CUSTOM_ID: R-IndexData + :END: +** There must be a robust way for dealing with hash collisions, especially with respect to off-chain data whose content is opaque + :PROPERTIES: + :CUSTOM_ID: R-HandleHashCollisions + :END: -- GitLab From ebc3774bbd5d19bc45d68e43bcb713214eb55867 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 5 Feb 2019 12:55:13 -0500 Subject: [PATCH 03/41] WIP on data, geo and oracle specs [#163655142,#163731332] --- x/data/README.org | 86 ++++++++++++++++++++++++++++++++------------- x/data/types.go | 52 +++++++++++++++------------ x/geo/README.org | 67 +++++++++++++++++++++++++++++++++++ x/geo/geo.sql | 9 +++++ x/geo/types.go | 31 ++++++++++++---- x/oracle/README.org | 38 ++++++++++++++++++++ 6 files changed, 229 insertions(+), 54 deletions(-) create mode 100644 x/geo/README.org create mode 100644 x/geo/geo.sql create mode 100644 x/oracle/README.org diff --git a/x/data/README.org b/x/data/README.org index 1e5b128d6..89be63fbd 100644 --- a/x/data/README.org +++ b/x/data/README.org @@ -12,9 +12,12 @@ before some given block-height. It is intended that this module will mostly be supplanted by other more domain specific functionality and/or enhanced with robust, opt-in schema-validation support in the future. -* Requirements +* Motivation and Rationale + + +** Requirements :PROPERTIES: - :CUSTOM_ID: requirements + :CUSTOM_ID: overview :END: - It should be possible to store arbitrary data on the blockchain for a fee @@ -23,23 +26,70 @@ enhanced with robust, opt-in schema-validation support in the future. - There must be a robust way for dealing with hash collisions, especially with respect to off-chain data whose content is opaque * Transaction Messages and Types -#+BEGIN_SRC go :tangle types.go :comments link :exports none -// DO NOT EDIT THIS FILE +#+BEGIN_SRC go :tangle types.go :exports none + // GENERATED FROM README.org + // DO NOT EDIT THIS FILE DIRECTLY!!!!! package data + + import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ) #+END_SRC - -#+BEGIN_SRC go :tangle types.go :comments link + +** Store RDF graph on-chain + +#+BEGIN_SRC go :tangle types.go + type MsgStoreGraph struct { + // RDF graph data in N-Triples text format + NTriples string `json:"ntriples"` + // Expected hash of the graph. The transaction will be rejected if this hash can't be verified. + URDNA2015_BLAKE2B_256_Hash []byte `json:"urdna2015_blake2b_256_hash"` + Signer sdk.AccAddress `json:"signer"` + } +#+END_SRC + +[[https://www.w3.org/TR/n-triples/][N-Triples]] format has been chosen as a starting point because it is easy to parse and self-contained. + +*** NOTE The reason JSON-LD has not been chosen for on-chain usage is that the way `@context` is designed explicitly requires JSON-LD processors to pull off-chain HTTP data which is indeterministic. + +*** TODO In the future, we would like to support other self-contained formats such as Turtle and binary formats. + +*** TODO Should the URDNA2015 hash be verified on chain or should this be left to indexers? + The danger with doing it on-chain now is that there currently is no known algorithm for verifying that a graph is normalized that is guaranteed to terminate in linear time: https://github.com/json-ld/normalization/issues/11. + + A short-term workaround would be to only allow graphs that have no blank nodes. Then verifying that data is normalized is simply a matter of verifying that it's sorted. Then in the future we can allow graphs with blank nodes when we have a way of verifying that blank nodes have been assigned canonically. + +*** TODO should data format (i.e. JSON/JSON-LD/etc.) and/or schema (i.e. SCHACL/SHEX/JSON-SCHEMA) be tracked and/or verified on-chain? + It might be useful to track format on-chain but not verify it. For a given format there could be multiple schemas that it satisfies. My current thoughts are that this is a type of verification/validation that can be done off chain and there can be on-chain attestations about that - ARC. + +** Store arbitrary data on-chain + +#+BEGIN_SRC go :tangle types.go type DataFormat int const ( Unknown DataFormat = 0 - NQuads DataFormat = 1 - JSON_LD DataFormat = 2 - JSON DataFormat = 3 - Turtle DataFormat = 4 - TRIG DataFormat = 5 + JSON_LD DataFormat = 1 + NQuads DataFormat = 2 + Turtle DataFormat = 3 + TriG DataFormat = 4 + JSON DataFormat = 5 + XML DataFormat = 6 + YAML DataFormat = 7 + TIFF DataFormat = 8 ) + type MsgStoreData struct { + //SchemaRef string + Data []byte `json:"data"` + Format DataFormat `json:"format,omitempty"` + Signer sdk.AccAddress `json:"signer"` + } +#+END_SRC + +** Track off-chain RDF dataset + +#+BEGIN_SRC go :tangle types.go type HashAlgorithm int const ( @@ -49,17 +99,6 @@ enhanced with robust, opt-in schema-validation support in the future. URGNA2012 HashAlgorithm = 3 ) - type MsgStoreData struct { - Data []byte `json:"data"` - Format DataFormat `json:"format,omitempty"` - } - - type MsgStoreGraph struct { - NQuads string `json:"nquads"` - URDNA2015Hash []byte `json:"urdna2015_hash"` - Signers []sdk.AccAddress `json:"signers"` - } - type MsgTrackData struct { Hash []byte `json:"hash"` Algorithm HashAlgorithm `json:"algorithm"` @@ -68,7 +107,4 @@ enhanced with robust, opt-in schema-validation support in the future. } #+END_SRC -** TODO should data format (i.e. JSON/JSON-LD/etc.) and/or schema (i.e. SCHACL/SHEX/JSON-SCHEMA) be tracked and/or verified on-chain? - It might be useful to track format on-chain but not verify it. For a given format there could be multiple schemas that it satisfies. My current thoughts are that this is a type of verification/validation that can be done off chain and there can be on-chain attestations about that - ARC. - * Queries and Indexing diff --git a/x/data/types.go b/x/data/types.go index 580454dff..4214b974f 100644 --- a/x/data/types.go +++ b/x/data/types.go @@ -1,20 +1,40 @@ -// [[file:~/regen-ledger/x/data/README.org::*Transaction%20Messages%20and%20Types][Transaction Messages and Types:1]] -// DO NOT EDIT THIS FILE - package data -// Transaction Messages and Types:1 ends here +// GENERATED FROM README.org +// DO NOT EDIT THIS FILE DIRECTLY!!!!! +package data + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type MsgStoreGraph struct { + // RDF graph data in N-Triples text format + NTriples string `json:"ntriples"` + // Expected hash of the graph. The transaction will be rejected if this hash can't be verified. + URDNA2015_Hash []byte `json:"urdna2015_hash"` + Signer sdk.AccAddress `json:"signer"` +} -// [[file:~/regen-ledger/x/data/README.org::*Transaction%20Messages%20and%20Types][Transaction Messages and Types:2]] type DataFormat int const ( Unknown DataFormat = 0 - NQuads DataFormat = 1 - JSON_LD DataFormat = 2 - JSON DataFormat = 3 - Turtle DataFormat = 4 - TRIG DataFormat = 5 + JSON_LD DataFormat = 1 + NQuads DataFormat = 2 + Turtle DataFormat = 3 + TriG DataFormat = 4 + JSON DataFormat = 5 + XML DataFormat = 6 + YAML DataFormat = 7 + TIFF DataFormat = 8 ) +type MsgStoreData struct { + //SchemaRef string + Data []byte `json:"data"` + Format DataFormat `json:"format,omitempty"` + Signer sdk.AccAddress `json:"signer"` +} + type HashAlgorithm int const ( @@ -24,21 +44,9 @@ const ( URGNA2012 HashAlgorithm = 3 ) -type MsgStoreData struct { - Data []byte `json:"data"` - Format DataFormat `json:"format,omitempty"` -} - -type MsgStoreGraph struct { - NQuads string `json:"nquads"` - URDNA2015Hash []byte `json:"urdna2015_hash"` - Signers []sdk.AccAddress `json:"signers"` -} - type MsgTrackData struct { Hash []byte `json:"hash"` Algorithm HashAlgorithm `json:"algorithm"` Format DataFormat `json:"format,omitempty"` Url string `json:"url,omitempty"` } -// Transaction Messages and Types:2 ends here diff --git a/x/geo/README.org b/x/geo/README.org new file mode 100644 index 000000000..a406f72dc --- /dev/null +++ b/x/geo/README.org @@ -0,0 +1,67 @@ +#+TITLE: Geo Module +#+BEGIN_SRC go :tangle types.go :exports none + // GENERATED FROM README.org + // DO NOT EDIT THIS FILE DIRECTLY!!!!! + package geo + + import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ) +#+END_SRC +* Overview + The `geo` module provides an efficient storage space for on-chain geographic features that can be referenced by other modules. +* Motivation and Rationale + While geographic features could be stored as literals everywhere they are needed, precise measurements of real world objects like a polygon that describes an irregularly shaped field can become quite large because of the number of points required to be precise. Having a single storage space for these objects reduces overall storage requirements. Geographic features are also referenced by hash on-chain which provides for content addressability and reduces duplication. +* Transaction Messages and Types +** Store geographic feature on-chain +#+BEGIN_SRC go :tangle types.go + type MsgStoreGeo struct { + Data Geometry `json:"data"` + Signer sdk.AccAddress `json:"signer"` + } + + type FeatureType int + + const ( + Point FeatureType = 0 + LineString + Polygon + MultiPoint + MultiLineString + MultiPolygon + ) + + type Geometry struct { + Type FeatureType `json:"type"` + // EWKB representation of the geo feature. Must be in the WGS84 coordinate + // system and represent a Point, LineString, Polygon, MultiPoint, MultiLineString or MultiPolygon + EWKB []byte `json:"ewkb,omitempty"` + } +#+END_SRC + +** Identifiers +*** Stored `GeoFeature` + Stored `GeoFeature's are referenced by the identifier `xrn:///` where `` is the bech32 encoding with prefix `geo` of the Blake2b 256-bit hash of the EWKB representation of the geographic feature. +** Indexing and Queries + Geographic features are indexed by both the Postgis and RDF indexers. +*** Postgis +#+BEGIN_SRC sql :tangle geo.sql + CREATE TABLE geo ( + hash bytea NOT NULL PRIMARY KEY, + tx bytea NOT NULL REFERENCES tx, + -- Both the Postgis geography and geometry representations are stored + geog geography NOT NULL, + geom geometry NOT NULL + ); + + CREATE INDEX geo_geom_gist ON geo USING GIST ( geom ); +#+END_SRC +*** RDF +#+BEGIN_SRC turtle +PREFIX geo: +PREFIX sf: + + + a sf:Point ; + geo:asWKT "Point(-83.38 33.95)"^^ . +#+END_SRC diff --git a/x/geo/geo.sql b/x/geo/geo.sql new file mode 100644 index 000000000..3b2db897f --- /dev/null +++ b/x/geo/geo.sql @@ -0,0 +1,9 @@ +CREATE TABLE geo ( + hash bytea NOT NULL PRIMARY KEY, + tx bytea NOT NULL REFERENCES tx, + -- Both the Postgis geography and geometry representations are stored + geog geography NOT NULL, + geom geometry NOT NULL +); + +CREATE INDEX geo_geom_gist ON geo USING GIST ( geom ); diff --git a/x/geo/types.go b/x/geo/types.go index f5a886a34..eb600a2ad 100644 --- a/x/geo/types.go +++ b/x/geo/types.go @@ -1,13 +1,30 @@ +// GENERATED FROM README.org +// DO NOT EDIT THIS FILE DIRECTLY!!!!! package geo -type GeometryType int +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) -//const ( -// Point GeometryType = 0 -// Polygon GeometryType = 1 -//) +type MsgStoreGeo struct { + Data Geometry `json:"data"` + Signer sdk.AccAddress `json:"signer"` +} + +type FeatureType int + +const ( + Point FeatureType = 0 + LineString + Polygon + MultiPoint + MultiLineString + MultiPolygon +) type Geometry struct { - //Type GeometryType `json:"type"` - EWKB []byte `json:"ewkb,omitempty"` + Type FeatureType `json:"type"` + // EWKB representation of the geo feature. Must be in the WGS84 coordinate + // system and represent a Point, LineString, Polygon, MultiPoint, MultiLineString or MultiPolygon + EWKB []byte `json:"ewkb,omitempty"` } diff --git a/x/oracle/README.org b/x/oracle/README.org new file mode 100644 index 000000000..cfa319f30 --- /dev/null +++ b/x/oracle/README.org @@ -0,0 +1,38 @@ +* Consensus Protocol +** Function Invocation +** Function Invocation Request +** Oracle Pool Contract +** Execution Results +** Round Structure +*** Select Oracle +When a compute function invocation is requested against an oracle pool, the first oracle to run the contract is chosen at +random based on the result of the block hash in which the request is transacted. Given an array of ~N~ oracles in an +oracle pool we select the array of the ~M~ oracles which have not been elected to compute this function invocation yet, +maintaining the original array order and call this resulting array the selection pool. The selected oracle is the ~i~'th +oracle in the selection pool array where $i = blockHash \bmod{M}$. A tag alerting the oracle that it has been +selected for this round may be attached to the next block or this information may simply stored in the appropriate index (TODO). +*** Commit Result + Once the selected oracle has completed the requested computation +#+BEGIN_SRC go :tangle types.go + type MsgCommitResult struct { + // The argon2 salted hash of the result, TODO specify parameters + Hash []bytes `json:"bytes"` + Signer sdk.AccAddress `json:"signer"` + } +#+END_SRC +**** Handling Timeouts +The oracle pool contract for the given function will include a timeout window. If the selected oracle cannot complete the +result in the specified timeout window, it should post a heartbeat message before the timeout block and TODO. +If the selected oracle fails to commit a result at all before the end of the timeout window, another oracle will be chosen +at random and the original selection oracle will be marked as unavailable and scheduled for its bond to be slashed accordingly, +unless, of course, all requested oracles timeout in which the curator of the function will be slashed for improper function +implementation. +*** Select Next Oracle or Finish Commit +*** Share Results +*** Vote +#+BEGIN_SRC go :tangle types.go + type MsgVoteResult struct { + Signer sdk.AccAddress `json:"signer"` + } +#+END_SRC +*** Consensus, Resolution Round or Failure -- GitLab From 0005cdc971c2e8f97b737955a44c842c6f517005 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 5 Feb 2019 12:57:03 -0500 Subject: [PATCH 04/41] Update tangling --- x/geo/README.org | 10 ++++++++-- x/geo/geo.sql | 3 +++ x/geo/types.go | 5 +++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/x/geo/README.org b/x/geo/README.org index a406f72dc..abf2516e0 100644 --- a/x/geo/README.org +++ b/x/geo/README.org @@ -1,13 +1,19 @@ #+TITLE: Geo Module #+BEGIN_SRC go :tangle types.go :exports none - // GENERATED FROM README.org - // DO NOT EDIT THIS FILE DIRECTLY!!!!! + /* GENERATED FROM README.org + DO NOT EDIT THIS FILE DIRECTLY!!!!! */ + package geo import ( sdk "github.com/cosmos/cosmos-sdk/types" ) #+END_SRC +#+BEGIN_SRC sql :tangle geo.sql :exports none + /* GENERATED FROM README.org + DO NOT EDIT THIS FILE DIRECTLY!!!!! */ + +#+END_SRC * Overview The `geo` module provides an efficient storage space for on-chain geographic features that can be referenced by other modules. * Motivation and Rationale diff --git a/x/geo/geo.sql b/x/geo/geo.sql index 3b2db897f..be0ff087e 100644 --- a/x/geo/geo.sql +++ b/x/geo/geo.sql @@ -1,3 +1,6 @@ +/* GENERATED FROM README.org + DO NOT EDIT THIS FILE DIRECTLY!!!!! */ + CREATE TABLE geo ( hash bytea NOT NULL PRIMARY KEY, tx bytea NOT NULL REFERENCES tx, diff --git a/x/geo/types.go b/x/geo/types.go index eb600a2ad..d7a0b4171 100644 --- a/x/geo/types.go +++ b/x/geo/types.go @@ -1,5 +1,6 @@ -// GENERATED FROM README.org -// DO NOT EDIT THIS FILE DIRECTLY!!!!! +/* GENERATED FROM README.org + DO NOT EDIT THIS FILE DIRECTLY!!!!! */ + package geo import ( -- GitLab From b495b8524076e2749b4cb46591415305f693daa7 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 5 Feb 2019 12:59:02 -0500 Subject: [PATCH 05/41] Fix org mode syntax --- x/geo/README.org | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/geo/README.org b/x/geo/README.org index abf2516e0..0d47291f7 100644 --- a/x/geo/README.org +++ b/x/geo/README.org @@ -15,7 +15,7 @@ #+END_SRC * Overview - The `geo` module provides an efficient storage space for on-chain geographic features that can be referenced by other modules. + The ~geo~ module provides an efficient storage space for on-chain geographic features that can be referenced by other modules. * Motivation and Rationale While geographic features could be stored as literals everywhere they are needed, precise measurements of real world objects like a polygon that describes an irregularly shaped field can become quite large because of the number of points required to be precise. Having a single storage space for these objects reduces overall storage requirements. Geographic features are also referenced by hash on-chain which provides for content addressability and reduces duplication. * Transaction Messages and Types @@ -46,8 +46,8 @@ #+END_SRC ** Identifiers -*** Stored `GeoFeature` - Stored `GeoFeature's are referenced by the identifier `xrn:///` where `` is the bech32 encoding with prefix `geo` of the Blake2b 256-bit hash of the EWKB representation of the geographic feature. +*** Stored ~GeoFeature~ + Stored ~GeoFeature~'s are referenced by the identifier ~xrn:///~ where ~~ is the bech32 encoding with prefix ~geo~ of the Blake2b 256-bit hash of the EWKB representation of the geographic feature. ** Indexing and Queries Geographic features are indexed by both the Postgis and RDF indexers. *** Postgis -- GitLab From 27a24ef227890c6720085dd00e15723f3069b6f1 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 5 Feb 2019 13:19:07 -0500 Subject: [PATCH 06/41] Added TODO states and more description to geo spec [#163731332] --- x/geo/README.org | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/x/geo/README.org b/x/geo/README.org index 0d47291f7..b137b586b 100644 --- a/x/geo/README.org +++ b/x/geo/README.org @@ -19,7 +19,7 @@ * Motivation and Rationale While geographic features could be stored as literals everywhere they are needed, precise measurements of real world objects like a polygon that describes an irregularly shaped field can become quite large because of the number of points required to be precise. Having a single storage space for these objects reduces overall storage requirements. Geographic features are also referenced by hash on-chain which provides for content addressability and reduces duplication. * Transaction Messages and Types -** Store geographic feature on-chain +** TODO Store geographic feature on-chain #+BEGIN_SRC go :tangle types.go type MsgStoreGeo struct { Data Geometry `json:"data"` @@ -46,11 +46,12 @@ #+END_SRC ** Identifiers -*** Stored ~GeoFeature~ - Stored ~GeoFeature~'s are referenced by the identifier ~xrn:///~ where ~~ is the bech32 encoding with prefix ~geo~ of the Blake2b 256-bit hash of the EWKB representation of the geographic feature. +*** TODO ~Geometry~ URI's + Stored ~Geometry~'s are referenced by the URI created by the bech32 encoding of the Blake2b 256-bit hash of the EWKB representation of the geographic feature prefixed with ~xrn:///geo/~. ** Indexing and Queries Geographic features are indexed by both the Postgis and RDF indexers. -*** Postgis +*** TODO Postgis + ~Geometry~'s will be indexed in the table ~geo~ defined as: #+BEGIN_SRC sql :tangle geo.sql CREATE TABLE geo ( hash bytea NOT NULL PRIMARY KEY, @@ -62,12 +63,13 @@ CREATE INDEX geo_geom_gist ON geo USING GIST ( geom ); #+END_SRC -*** RDF +*** TODO RDF + ~Geometry~'s will be indexed in the RDF store as below and available in both the default graph and the named graph identified by the ~Geometry~ URI. #+BEGIN_SRC turtle PREFIX geo: PREFIX sf: - + a sf:Point ; geo:asWKT "Point(-83.38 33.95)"^^ . #+END_SRC -- GitLab From a2ce3a94060e794a004436ede78da9026edddc06 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 5 Feb 2019 14:47:11 -0500 Subject: [PATCH 07/41] WIP on geo, data and other module specs [#163731332,#163655142] --- x/agent/README.md | 6 ------ x/agent/README.org | 17 +++++++++++++++++ x/data/README.org | 33 ++++++++++++++++++++++++++++++++- x/esp/README.md | 10 ---------- x/esp/README.org | 21 +++++++++++++++++++++ x/geo/README.org | 4 ++-- x/proposal/README.org | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 106 insertions(+), 19 deletions(-) delete mode 100644 x/agent/README.md create mode 100644 x/agent/README.org delete mode 100644 x/esp/README.md create mode 100644 x/esp/README.org create mode 100644 x/proposal/README.org diff --git a/x/agent/README.md b/x/agent/README.md deleted file mode 100644 index b6fe5674f..000000000 --- a/x/agent/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Agent Module - -The agent module provides a mechanism that can be used to support basic -multi-party organizations and to allow individuals to facilitate authorization -via multiple keys. In the future, it may be extended to support more sophisticated -multi-party authorization schemes. \ No newline at end of file diff --git a/x/agent/README.org b/x/agent/README.org new file mode 100644 index 000000000..a6603d8f5 --- /dev/null +++ b/x/agent/README.org @@ -0,0 +1,17 @@ +#+TITLE: Agent Module + +* Overview + +The agent module provides a mechanism that can be used to support basic +multi-party organizations and to allow individuals to facilitate authorization +via multiple keys. In the future, it may be extended to support more sophisticated +multi-party authorization schemes. + +* Motivation and Rationale + +* Transaction Messages and Types + +* Identifiers + Agents are identified by the URI formed by taking the bech32 encoding of the agent's integer ID with the prefix ~xrn:agt/~. + +* Indexing and Queries diff --git a/x/data/README.org b/x/data/README.org index 89be63fbd..ee8c45e9e 100644 --- a/x/data/README.org +++ b/x/data/README.org @@ -106,5 +106,36 @@ enhanced with robust, opt-in schema-validation support in the future. Url string `json:"url,omitempty"` } #+END_SRC +* Identifiers +** On-chain graphs + On-chain graphs are identified by the URI formed by encoding the URNDNA2015_BLAKE2B_256 hash of the graph with the prefix ~xrn:///g/~. +** Off-chain datasets + Off-chain datasets are identified by the URI formed by encoding the URNDNA2015_BLAKE2B_256 hash of the dataset with the prefix ~xrn:///ds/~. +** On-chain raw data + On-chain raw data is identified by the URI formed by encoding the Blake2b 256-bit hash of the data prefixed with ~xrn:///da/~. +** Off-chain raw data + Off-chain raw data is identified by the URI formed by encoding the Blake2b 256-bit hash of the data prefixed with ~xrn:///dt/~. +* Indexing and Queries +** Postgresql +#+BEGIN_SRC sql :tangle data.sql + CREATE TABLE "data" ( + uri text NOT NULL PRIMARY KEY, + tx bytea NOT NULL REFERENCES tx, + graph jsonb, + raw_data bytea + ); + + COMMENT ON COLUMN graph.graph IS 'The JSON-LD expanded form representation of an on-chain graph'; + + COMMENT ON COLUMN graph.raw_data IS 'Raw data bytes for on-chain raw data'; +#+END_SRC +** RDF +*** On-chain graphs + On chain graphs are indexed in the RDF store in the named graph identified with the graph identifier URI. They are annotated in the default graph as follows (where ~xrn://12345/g/1xq52sutm~ is an example graph URI): + +#+BEGIN_SRC turtle +PREFIX xrn: -* Queries and Indexing + + xrn:tx . +#+END_SRC diff --git a/x/esp/README.md b/x/esp/README.md deleted file mode 100644 index 36f665c20..000000000 --- a/x/esp/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# ESP module - -The ESP (ecological state protocol) module provides a global geo-tagged, ledger of ecological health. - -ESP's are managed by curating organizations (managed by the [agent](../agent/README.md) module) and can evolve through -various versions as the curating organization refines its verification methodology. Curators are responsible for -defining approved verifiers and a schema for ESP results. - -All ESP results include a geo-polygon that allows the data stored in the ESP result registry to be projected onto a map - for visualization of global ecological health. \ No newline at end of file diff --git a/x/esp/README.org b/x/esp/README.org new file mode 100644 index 000000000..641d5ce31 --- /dev/null +++ b/x/esp/README.org @@ -0,0 +1,21 @@ +#+TITLE: ESP module + +* Overview + +The ESP (ecological state protocol) module provides a global geo-tagged, ledger of ecological health. + +ESP's are managed by curating organizations (managed by the [[../agent/README.org][agent]] module) and can evolve through +various versions as the curating organization refines its verification methodology. Curators are responsible for +defining approved verifiers and a schema for ESP results. + +All ESP results include a geo-polygon that allows the data stored in the ESP result registry to be projected onto a map +for visualization of global ecological health. + +* Motivation and Rationale + +* Transaction Messages and Types + +* Identifiers + ESP's are identified by the URI formed by taking the agent URI and appending ~/esp//+~. + +* Indexing and Queries diff --git a/x/geo/README.org b/x/geo/README.org index b137b586b..2cd4eb20c 100644 --- a/x/geo/README.org +++ b/x/geo/README.org @@ -47,14 +47,14 @@ ** Identifiers *** TODO ~Geometry~ URI's - Stored ~Geometry~'s are referenced by the URI created by the bech32 encoding of the Blake2b 256-bit hash of the EWKB representation of the geographic feature prefixed with ~xrn:///geo/~. + Stored ~Geometry~'s are referenced by the URI created by the bech32 encoding of the Blake2b 256-bit hash of the EWKB representation of the geographic feature prefixed with ~xrn:///geo/~. ** Indexing and Queries Geographic features are indexed by both the Postgis and RDF indexers. *** TODO Postgis ~Geometry~'s will be indexed in the table ~geo~ defined as: #+BEGIN_SRC sql :tangle geo.sql CREATE TABLE geo ( - hash bytea NOT NULL PRIMARY KEY, + uri text NOT NULL PRIMARY KEY, tx bytea NOT NULL REFERENCES tx, -- Both the Postgis geography and geometry representations are stored geog geography NOT NULL, diff --git a/x/proposal/README.org b/x/proposal/README.org new file mode 100644 index 000000000..354207c6f --- /dev/null +++ b/x/proposal/README.org @@ -0,0 +1,34 @@ +#+TITLE: Proposal Module +#+BEGIN_SRC sql :tangle proposal.sql :exports none + /* GENERATED FROM README.org + DO NOT EDIT THIS FILE DIRECTLY!!!!! */ + +#+END_SRC + +* Overview + +* Motivation and Rationale + +* Transaction Messages and Types + +* Identifiers + +* Indexing and Queries + +** Postgresql +#+BEGIN_SRC sql :tangle proposal.sql + CREATE TABLE proposal ( + uri text NOT NULL PRIMARY KEY, + proposer bytea NOT NULL REFERENCES account, + proposed_at bytea NOT NULL REFERENCES tx, + "action" jsonb NOT NULL + ); + + CREATE TABLE proposal_approvals ( + uri text NOT NULL REFERENCES proposal, + approver bytea NOT NULL REFERENCES account, + voted_at bytea NOT NULL REFERENCES tx + ); +#+END_SRC +** RDF + Proposals aren't indexed in the RDF store. -- GitLab From 7daf008747f094f56f6b9f55dec59a83375bcf77 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 5 Feb 2019 16:38:24 -0500 Subject: [PATCH 08/41] WIP on data spec, started on schema spec [#163655142] --- x/data/README.org | 78 ++++++++++++++++++++++----------------------- x/schema/README.org | 62 +++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 39 deletions(-) create mode 100644 x/schema/README.org diff --git a/x/data/README.org b/x/data/README.org index ee8c45e9e..4575eeb61 100644 --- a/x/data/README.org +++ b/x/data/README.org @@ -40,7 +40,7 @@ enhanced with robust, opt-in schema-validation support in the future. #+BEGIN_SRC go :tangle types.go type MsgStoreGraph struct { - // RDF graph data in N-Triples text format + // RDF graph data in N-Triples text format with no blank nodes allowed! NTriples string `json:"ntriples"` // Expected hash of the graph. The transaction will be rejected if this hash can't be verified. URDNA2015_BLAKE2B_256_Hash []byte `json:"urdna2015_blake2b_256_hash"` @@ -48,46 +48,26 @@ enhanced with robust, opt-in schema-validation support in the future. } #+END_SRC -[[https://www.w3.org/TR/n-triples/][N-Triples]] format has been chosen as a starting point because it is easy to parse and self-contained. +[[https://www.w3.org/TR/n-triples/][N-Triples]] format has been chosen as a starting point because it is easy to parse and self-contained. **Blank nodes are not allowed in on-chain graphs!** This restriction makes it easy to verify that the dataset is canonicalized and that the hash matches, without having to run the full canonicalization algorithm on-chain. The N-Triples data passed in must be in canonicalized form which essentially means that it is sorted because blank nodes are not allowed. *** NOTE The reason JSON-LD has not been chosen for on-chain usage is that the way `@context` is designed explicitly requires JSON-LD processors to pull off-chain HTTP data which is indeterministic. -*** TODO In the future, we would like to support other self-contained formats such as Turtle and binary formats. +*** TODO In the future, we would like to support a compact binary format. -*** TODO Should the URDNA2015 hash be verified on chain or should this be left to indexers? - The danger with doing it on-chain now is that there currently is no known algorithm for verifying that a graph is normalized that is guaranteed to terminate in linear time: https://github.com/json-ld/normalization/issues/11. - - A short-term workaround would be to only allow graphs that have no blank nodes. Then verifying that data is normalized is simply a matter of verifying that it's sorted. Then in the future we can allow graphs with blank nodes when we have a way of verifying that blank nodes have been assigned canonically. - -*** TODO should data format (i.e. JSON/JSON-LD/etc.) and/or schema (i.e. SCHACL/SHEX/JSON-SCHEMA) be tracked and/or verified on-chain? +*** TODO should data schema (i.e. SCHACL/SHEX/JSON-SCHEMA) be tracked and/or verified on-chain? It might be useful to track format on-chain but not verify it. For a given format there could be multiple schemas that it satisfies. My current thoughts are that this is a type of verification/validation that can be done off chain and there can be on-chain attestations about that - ARC. -** Store arbitrary data on-chain +** Track off-chain RDF dataset #+BEGIN_SRC go :tangle types.go - type DataFormat int - - const ( - Unknown DataFormat = 0 - JSON_LD DataFormat = 1 - NQuads DataFormat = 2 - Turtle DataFormat = 3 - TriG DataFormat = 4 - JSON DataFormat = 5 - XML DataFormat = 6 - YAML DataFormat = 7 - TIFF DataFormat = 8 - ) - - type MsgStoreData struct { - //SchemaRef string - Data []byte `json:"data"` - Format DataFormat `json:"format,omitempty"` - Signer sdk.AccAddress `json:"signer"` + type MsgTrackDataset struct { + URDNA2015_BLAKE2B_256_Hash []byte `json:"urdna2015_blake2b_256_hash"` + Url string `json:"url,omitempty"` + Signer sdk.AccAddress `json:"signer"` } #+END_SRC - -** Track off-chain RDF dataset + +** Track arbitrary off-chain data #+BEGIN_SRC go :tangle types.go type HashAlgorithm int @@ -95,34 +75,42 @@ enhanced with robust, opt-in schema-validation support in the future. const ( BLAKE2B_256 HashAlgorithm = 0 SHA256 HashAlgorithm = 1 - URDNA2015 HashAlgorithm = 2 - URGNA2012 HashAlgorithm = 3 ) type MsgTrackData struct { Hash []byte `json:"hash"` Algorithm HashAlgorithm `json:"algorithm"` - Format DataFormat `json:"format,omitempty"` Url string `json:"url,omitempty"` + Signer sdk.AccAddress `json:"signer"` } #+END_SRC + +** TODO Store arbitrary data on-chain + This is a use case we may want to support but for now are not supporting it because it is questionable whether we should encourage storing data on-chain that can't be interpreted by other on-chain infrastructure. + +** TODO allow for tracking off-chain data which has a salt/nonce introduced + +** TODO allow for multiple URL's to be provided for off-chain data and to allow possible ways to deal with hash collisions + +** TODO possibly make URL's for off-chain data optional + * Identifiers ** On-chain graphs On-chain graphs are identified by the URI formed by encoding the URNDNA2015_BLAKE2B_256 hash of the graph with the prefix ~xrn:///g/~. ** Off-chain datasets Off-chain datasets are identified by the URI formed by encoding the URNDNA2015_BLAKE2B_256 hash of the dataset with the prefix ~xrn:///ds/~. -** On-chain raw data - On-chain raw data is identified by the URI formed by encoding the Blake2b 256-bit hash of the data prefixed with ~xrn:///da/~. ** Off-chain raw data Off-chain raw data is identified by the URI formed by encoding the Blake2b 256-bit hash of the data prefixed with ~xrn:///dt/~. +** On-chain raw data?? + On-chain raw data is identified by the URI formed by encoding the Blake2b 256-bit hash of the data prefixed with ~xrn:///da/~. * Indexing and Queries ** Postgresql #+BEGIN_SRC sql :tangle data.sql CREATE TABLE "data" ( uri text NOT NULL PRIMARY KEY, tx bytea NOT NULL REFERENCES tx, - graph jsonb, - raw_data bytea + graph jsonb + --raw_data bytea ); COMMENT ON COLUMN graph.graph IS 'The JSON-LD expanded form representation of an on-chain graph'; @@ -130,6 +118,17 @@ enhanced with robust, opt-in schema-validation support in the future. COMMENT ON COLUMN graph.raw_data IS 'Raw data bytes for on-chain raw data'; #+END_SRC ** RDF +*** Schema +#+BEGIN_SRC turtle +PREFIX rdf: +PREFIX rdfs: +PREFIX xsd: +PREFIX xrn: + +xrn:urdna2015Blake2b256Hash a rdf:Property ; + rdfs:range xsd:base64Binary . + +#+END_SRC *** On-chain graphs On chain graphs are indexed in the RDF store in the named graph identified with the graph identifier URI. They are annotated in the default graph as follows (where ~xrn://12345/g/1xq52sutm~ is an example graph URI): @@ -137,5 +136,6 @@ enhanced with robust, opt-in schema-validation support in the future. PREFIX xrn: - xrn:tx . + xrn:tx ; + xrn:urdna2015Blake2b256Hash "sdgbhABN38dsfgn23t=" . #+END_SRC diff --git a/x/schema/README.org b/x/schema/README.org new file mode 100644 index 000000000..3a4879b17 --- /dev/null +++ b/x/schema/README.org @@ -0,0 +1,62 @@ +#+TITLE: Schema + +* Overview + + +* Motivation and Rationale + +* Transaction Messages and Types + +** Define Property + +#+BEGIN_SRC go :tangle types.go + type PropertyType int + + const ( + OBJECT PropertyType = 0 + STRING + INTEGER + DECIMAL + BOOL + DOUBLE + DATETIME + DATE + TIME + DURATION + BASE64 + ANYURI + WKT + ) + + type PropertyID int64 + + type ClassID int64 + + type ActionDefineProperty struct { + Agent agent.AgentID `json:"agent"` + Name String `json:"name"` + Many Bool `json:"many,omitempty"` + Type PropertyType `json:"type,omitempty"` + Class ClassID `json:"class,omitempty"` + Label []LangString `json:"label,omitempty"` + Comment []LangString `json:"label,omitempty"` + } + + type ActionDefineClass struct { + Agent agent.AgentID `json:"agent"` + Name String `json:"name"` + Properties []PropertyRef `json:"properties,omitempty"` + Label []LangString `json:"label,omitempty"` + Comment []LangString `json:"label,omitempty"` + } + + type PropertyRef struct { + Property PropertyID `json:"property"` + Required Bool `json:"required,omitempty"` + } + + type LangString struct { + Text String `json:"text,omitempty"` + Language String `json:"lang,omitempty"` + } +#+END_SRC -- GitLab From 9d553a3864b65460da950e49afe57ad89a1694d2 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 6 Feb 2019 17:07:54 -0500 Subject: [PATCH 09/41] WIP on schema and contract specs --- x/contracts/README.org | 68 ++++++++++++++++++++++++++++++++++++++++++ x/schema/README.org | 66 +++++++++++++++++++++++++++++++++++----- 2 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 x/contracts/README.org diff --git a/x/contracts/README.org b/x/contracts/README.org new file mode 100644 index 000000000..c675b213e --- /dev/null +++ b/x/contracts/README.org @@ -0,0 +1,68 @@ +* FSM approach + +#+BEGIN_SRC go + // A contract template + type Contract struct { + States []State + } + + type State struct { + Name string + // Sparql CONSTRUCT's that should be executed + // when entering this state + OnEnter []string + // Sparql CONSTRUCT's that should be executed + // when re-entering this state + OnReEnter []string + // Sparql select that should be executed when entering or + // re-entering this state to get the next transition time + // (the time when the transition clauses should be executed + // until one of them succeeds or they all fail and a re-enter + // occurs) + GetTransitionTime string + Transitions []Transition + } + + type Transition struct { + // state this transition would go to + To string + // Sparql ASK query that returns true if the state + // transition should go forward + ShouldTransition string + // Sparql CONSTRUCT's that should be executed + // when exiting this state on this transition branch + OnExit []string + } + + type ContractState struct { + balance sdk.Coins + state string + // The parameters the contract instance was initialized with + parameters string + nextTransitionTime time.Time + } +#+END_SRC go + +#+BEGIN_SRC trig +_:a a xrn:DepositRecepit ; + xrn:to ; + xrn:coins [ + xrn:denom "XRN" . + xrn:amount 1234 . + ]. + +_:b a xrn:EscrowInitializer ; + xrn:contractTemplate ; + xrn:contractParams _:params ; + xrn:coins [ + xrn:denom "XRN" . + xrn:amount 2345 . + ]. + +_:params { + +} +#+END_SRC + +** Sparql ASK and CONSTRUCT + Sparql ASK and CONSTRUCT are basic building blocks of this approach to constructs, with ASK queries being the boolean condition that guards transition between states and CONSTRUCT expressions being used to create events such as payments, minting, contract creation, and claim signing on state transitions. diff --git a/x/schema/README.org b/x/schema/README.org index 3a4879b17..97455f9fe 100644 --- a/x/schema/README.org +++ b/x/schema/README.org @@ -2,18 +2,17 @@ * Overview - * Motivation and Rationale * Transaction Messages and Types - -** Define Property - + +** Supported Property Types #+BEGIN_SRC go :tangle types.go type PropertyType int const ( OBJECT PropertyType = 0 + ENUM STRING INTEGER DECIMAL @@ -27,36 +26,87 @@ ANYURI WKT ) +#+END_SRC + +** Class, Property and Label Integer ID's + Classes, properties and labels receive an auto-incremented integer ID. This ID is used in references in class and property definitions and can also used for saving storage space in a binary RDF serialization format. +#+BEGIN_SRC go :tangle types.go type PropertyID int64 type ClassID int64 + type LabelID int64 +#+END_SRC + +** Define Property + +#+BEGIN_SRC go :tangle types.go type ActionDefineProperty struct { Agent agent.AgentID `json:"agent"` - Name String `json:"name"` - Many Bool `json:"many,omitempty"` + Name string `json:"name"` + Many bool `json:"many,omitempty"` Type PropertyType `json:"type,omitempty"` Class ClassID `json:"class,omitempty"` + SuperProperties []PropertyID `json:"super_properties,omitempty"` + SubProperties []PropertyID `json:"sub,omitempty"` + EnumLabels []LabelID `json:"enum_labels,omitempty"` + IntegerMin *big.Int `json:"integer_min,omitempty"` + IntegerMax *big.Int `json:"integer_max,omitempty"` + DoubleMin *double `json:"double_min,omitempty"` + DoubleMax *double `json:"double_max,omitempty"` Label []LangString `json:"label,omitempty"` Comment []LangString `json:"label,omitempty"` } +#+END_SRC + +** Define Class + +#+BEGIN_SRC go :tangle types.go + type ActionDefineClass struct { Agent agent.AgentID `json:"agent"` - Name String `json:"name"` + Name string `json:"name"` Properties []PropertyRef `json:"properties,omitempty"` + SuperClasses []ClassID `json:"super_classes,omitempty"` + SubClasses []ClassID `json:"sub_classes,omitempty"` Label []LangString `json:"label,omitempty"` Comment []LangString `json:"label,omitempty"` } type PropertyRef struct { Property PropertyID `json:"property"` - Required Bool `json:"required,omitempty"` + Required bool `json:"required,omitempty"` + } + +#+END_SRC + +** Define Label + Labels are IRI's whose sole purpose is to serve as an enum value. + +#+BEGIN_SRC go :tangle types.go + + type ActionDefineLabel struct { + Agent agent.AgentID `json:"agent"` + Name string `json:"name"` + Label []LangString `json:"label,omitempty"` + Comment []LangString `json:"label,omitempty"` } +#+END_SRC +** Human-readable labels and descriptions + + Human-readable and localized labels and descriptions can be defined using the ~Label~ and ~Comment~ fields of property and class definitions which map to ~rdfs:label~ and ~rdfs:comment~ properties respectively. Their values like in RDF Schema are an array of ~LangString~'s to support localization. + +#+BEGIN_SRC go :tangle types.go type LangString struct { Text String `json:"text,omitempty"` Language String `json:"lang,omitempty"` } #+END_SRC +** TODO bulk insertions +** TODO updates to classes (adding optional properties), human-readable text? + +* Identifiers + Properties and classes are identified by the URI formed by taking the agent URI and appending ~s/~. -- GitLab From d985226729ddf86278d8414e7e7d307b3341f867 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 7 Feb 2019 13:42:02 -0500 Subject: [PATCH 10/41] WIP on contract, action, and esp specs --- x/action/README.org | 122 +++++++++++++++++++++++++++++++++++++++++ x/contracts/README.org | 90 ++++++++++++++++++++++++++++++ x/esp/README.org | 32 +++++++++++ 3 files changed, 244 insertions(+) create mode 100644 x/action/README.org diff --git a/x/action/README.org b/x/action/README.org new file mode 100644 index 000000000..b6712c357 --- /dev/null +++ b/x/action/README.org @@ -0,0 +1,122 @@ + +#+BEGIN_SRC go + + type CapabilityKeeper interface { + // Store capabilities under the key actor-id/capability-id + // Grant stores a root flag, and delegate + GrantRootCapability(actor ActorID, capability ActionCapability) + RevokeRootCapability(actor ActorID, capability ActionCapability) + Delegate(grantor ActorID, actor ActorID, capability ActionCapability) + Undelegate(grantor ActorID, actor ActorID, capability ActionCapability) + HasCapability(actor ActorID, capability ActionCapability) bool + } + + type capabilityGrant { + // set if this is actor should be granted the capability at a "root" level + root bool + // all the actors that delegated this capability to the actor + // the capability should be cleared if root is false and this array is cleared + delegatedBy []ActorID + + // whenever this capability is undelegated or revoked, these delegations + // need to be cleared recursively + delegatedTo []ActorID + } + + type ActorID []byte + + type Actor interface { + ActorID() ActorID + } + + type Action interface { + RequiredCapability() ActionCapability + // Return the message type. + // Must be alphanumeric or empty. + Route() string + + // Returns a human-readable string for the message, intended for utilization + // within tags + Type() string + + // ValidateBasic does a simple validation check that + // doesn't require access to any other information. + ValidateBasic() sdk.Error + + // Get the canonical byte representation of the Msg. + GetSignBytes() []byte + + //HandleProposal(ctx sdk.Context, votes []sdk.AccAddress) sdk.Result + } + + type ActionDispatcher interface { + DispatchAction(ctx sdk.Context, actor Actor, action Action) ActionResult + } + + type ActionResult interface { + } + + // Wraps both agents and contracts which can have capabilities + type ActorKeeper interface { + Delegate(actor ActorID, capabilities []ActionCapability) + // TODO Undelegate + } + + type Action interface { + } + + type ActionCapability interface { + // Every capability should be have a system wide unique ID that includes + // both the type of capability and any params associated with it + CapabilityID () String + // Whether the specified action is allowed by this capability + Accept(action Action) Bool + // Whether capability is a sub-capability of this capability + IsSubCapability(capability ActionCapability) Bool + // TODO return who delegated the capability so it can be undelegated + Delegator() interface{} + // or maybe: + CanUndelegate (credential interface{}) Bool + } + + type SendAction struct { + } + + type SendActionCapability struct { + Account sdk.AccAddress + } + + type IssueESPResultAction struct { + Geo GeoID + ESP ESP_ID + Claim DataID + } + + type IssueESPResultActionCapability struct { + ESP ESP_ID + } + + // issues a credential to some identity (key or address), probably just sdk.AccAddress + type IssueCredentialAction struct { + Subject sdk.AccAddress + Credential CredentialID + Claim DataID + } + + type MintAction struct { + } + + type CreateContractAction struct { + Code data.DataID + InitialState data.DataID + Capabilities []ActionCapability + // TODO initial coins + } + + type DelegateAction struct { + Capabilities []ActionCapability + } + + type UndelegateAction struct { + } +#+END_SRC go diff --git a/x/contracts/README.org b/x/contracts/README.org index c675b213e..4da28a2c5 100644 --- a/x/contracts/README.org +++ b/x/contracts/README.org @@ -66,3 +66,93 @@ _:params { ** Sparql ASK and CONSTRUCT Sparql ASK and CONSTRUCT are basic building blocks of this approach to constructs, with ASK queries being the boolean condition that guards transition between states and CONSTRUCT expressions being used to create events such as payments, minting, contract creation, and claim signing on state transitions. +* Minimum Knowledge State Machine Approach + This approach could work with the above state machine approach but offloads the whole knowledge of code to just some data that gets pointed to and maybe has a schema. There needs to be specification on what valid code formats are for oracle consensus, but the blockchain itself only needs to know pointers to the code and current state and receive the actions that occur on transitions. + +#+BEGIN_SRC go + type ProcessingState int + + const ( + CanAcceptInput ProcessingState = 0 + Transitioning + ChallengeWindow + Finalized + ) + + type ContractState struct { + balance sdk.Coins + code data.DataID + contractState data.DataID + processingState ProcessingState + capabilities []ActionCapability + // TODO transition/challenge time window + // TODO oracle requirements + // TODO arbiter + } +#+END_SRC go + +** Contract Actions + +#+BEGIN_SRC go + type ActorID []byte + + // Wraps both agents and contracts which can have capabilities + type ActorKeeper interface { + func Delegate(actor ActorID, capabilities []ActionCapability) + // TODO Undelegate + } + + type Action interface { + } + + type ActionCapability { + // Whether the specified action is allowed by this capability + func Accept(action Action) Bool + // Whether capability is a sub-capability of this capability + func IsSubCapability(capability ActionCapability) Bool + // TODO return who delegated the capability so it can be undelegated + func Delegator() interface{} + // or maybe: + func CanUndelegate (credential interface{}) Bool + } + + type SendAction struct { + } + + type SendActionCapability struct { + Account sdk.AccAddress + } + + type IssueESPResultAction struct { + Geo GeoID + ESP ESP_ID + Claim DataID + } + + type IssueESPResultActionCapability struct { + } + + // issues a credential to some identity (key or address), probably just sdk.AccAddress + type IssueCredentialAction struct { + Subject sdk.AccAddress + Credential CredentialID + Claim DataID + } + + type MintAction struct { + } + + type CreateContractAction struct { + Code data.DataID + InitialState data.DataID + Capabilities []ActionCapability + // TODO initial coins + } + + type DelegateAction struct { + Capabilities []ActionCapability + } + + type UndelegateAction struct { + } +#+END_SRC go diff --git a/x/esp/README.org b/x/esp/README.org index 641d5ce31..7c47127fe 100644 --- a/x/esp/README.org +++ b/x/esp/README.org @@ -14,6 +14,38 @@ for visualization of global ecological health. * Motivation and Rationale * Transaction Messages and Types + +#+BEGIN_SRC go +type ESPVersionID []byte + +type ESPVersionSpec { + Curator agent.AgentID `json:"curator"` + Name string `json:"name"` + Version string `json:"version"` + Verifiers []action.ActorID `json:"verifiers"` + // TODO ClaimSchema schema.SchemaID?? +} + +type ESPResult struct { + ESP ESPVersionID + Verifier action.ActorID `json:"verifier"` + Geo geo.GeoID + Claim data.DataID +} + +type ActionRegisterESPVersion struct { + Curator agent.AgentID `json:"curator"` + Name string `json:"name"` + Version string `json:"version"` + Verifiers []action.ActorID `json:"verifiers"` +} + +type ActionReportESPResult struct { + ESP ESPVersionID + Geo geo.GeoID + Claim data.DataID +} +#+END_SRC go * Identifiers ESP's are identified by the URI formed by taking the agent URI and appending ~/esp//+~. -- GitLab From 45cc90dd44afc886f727e6a685287729ed579626 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 7 Feb 2019 13:47:31 -0500 Subject: [PATCH 11/41] Aligning action spec with proposal spec --- x/action/README.org | 1 - x/proposal/README.org | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/x/action/README.org b/x/action/README.org index b6712c357..7aa017c7d 100644 --- a/x/action/README.org +++ b/x/action/README.org @@ -1,4 +1,3 @@ - #+BEGIN_SRC go type CapabilityKeeper interface { diff --git a/x/proposal/README.org b/x/proposal/README.org index 354207c6f..0013b836c 100644 --- a/x/proposal/README.org +++ b/x/proposal/README.org @@ -11,6 +11,41 @@ * Transaction Messages and Types +#+BEGIN_SRC go +type ProposalID []byte + +type MsgCreateProposal struct { + Proposers []sdk.AccAddress `json:"proposer"` + Agent agent.AgentID + Action ProposalAction `json:"action"` + TryExec bool `json:"try_exec"` +} + +type MsgVote struct { + ID ProposalID `json:"id"` + Voters []sdk.AccAddress `json:"voters"` + Vote bool `json:"vote"` +} + +type MsgTryExecuteProposal struct { + ProposalId []byte `json:"proposal_id"` + Signer sdk.AccAddress `json:"signer"` +} + +type MsgWithdrawProposal struct { + ProposalId []byte `json:"proposal_id"` + Proposer sdk.AccAddress `json:"proposer"` +} + +type Proposal struct { + Proposer sdk.AccAddress `json:"proposer"` + Agent agent.AgentID + Action action.Action `json:"action"` + Approvers []sdk.AccAddress `json:"approvers,omitempty"` +} + +#+END_SRC go + * Identifiers * Indexing and Queries -- GitLab From 07b95f7aaf9d047e7eafe669ab543f699046bcfb Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 12 Feb 2019 21:23:26 -0500 Subject: [PATCH 12/41] WIP on spec's --- x/action/README.org | 48 ++++++++++++++++++--------------------------- x/agent/README.org | 37 ++++++++++++++++++++++++++++++---- x/agent/types.go | 1 - x/esp/README.org | 10 +++++----- x/schema/README.org | 6 +++--- x/token/README.org | 23 ++++++++++++++++++++++ 6 files changed, 83 insertions(+), 42 deletions(-) create mode 100644 x/token/README.org diff --git a/x/action/README.org b/x/action/README.org index 7aa017c7d..bcc69e305 100644 --- a/x/action/README.org +++ b/x/action/README.org @@ -1,13 +1,16 @@ #+BEGIN_SRC go + type ActionDispatcher interface { + DispatchAction(ctx sdk.Context, actor Actor, action Action) ActionResult + } type CapabilityKeeper interface { // Store capabilities under the key actor-id/capability-id // Grant stores a root flag, and delegate - GrantRootCapability(actor ActorID, capability ActionCapability) - RevokeRootCapability(actor ActorID, capability ActionCapability) - Delegate(grantor ActorID, actor ActorID, capability ActionCapability) - Undelegate(grantor ActorID, actor ActorID, capability ActionCapability) - HasCapability(actor ActorID, capability ActionCapability) bool + GrantRootCapability(ctx sdk.Context, actor sdk.AccAddress, capability ActionCapability) + RevokeRootCapability(ctx sdk.Context, actor sdk.AccAddress, capability ActionCapability) + Delegate(ctx sdk.Context, grantor sdk.AccAddress, actor sdk.AccAddress, capability ActionCapability) + Undelegate(ctx sdk.Context, grantor sdk.AccAddress, actor sdk.AccAddress, capability ActionCapability) + HasCapability(ctx sdk.Context, actor sdk.AccAddress, capability ActionCapability) bool } type capabilityGrant { @@ -15,21 +18,21 @@ root bool // all the actors that delegated this capability to the actor // the capability should be cleared if root is false and this array is cleared - delegatedBy []ActorID + delegatedBy []sdk.AccAddress // whenever this capability is undelegated or revoked, these delegations // need to be cleared recursively - delegatedTo []ActorID + delegatedTo []sdk.AccAddress } - type ActorID []byte + type sdk.AccAddress []byte type Actor interface { - ActorID() ActorID + sdk.AccAddress() sdk.AccAddress } type Action interface { - RequiredCapability() ActionCapability + RequiredCapabilities() []ActionCapability // Return the message type. // Must be alphanumeric or empty. Route() string @@ -48,34 +51,21 @@ //HandleProposal(ctx sdk.Context, votes []sdk.AccAddress) sdk.Result } - type ActionDispatcher interface { - DispatchAction(ctx sdk.Context, actor Actor, action Action) ActionResult - } - type ActionResult interface { } - // Wraps both agents and contracts which can have capabilities - type ActorKeeper interface { - Delegate(actor ActorID, capabilities []ActionCapability) - // TODO Undelegate - } - - type Action interface { - } - type ActionCapability interface { // Every capability should be have a system wide unique ID that includes // both the type of capability and any params associated with it CapabilityID () String // Whether the specified action is allowed by this capability Accept(action Action) Bool - // Whether capability is a sub-capability of this capability - IsSubCapability(capability ActionCapability) Bool - // TODO return who delegated the capability so it can be undelegated - Delegator() interface{} - // or maybe: - CanUndelegate (credential interface{}) Bool + //// Whether capability is a sub-capability of this capability + //IsSubCapability(capability ActionCapability) Bool + //// TODO return who delegated the capability so it can be undelegated + //Delegator() interface{} + //// or maybe: + //CanUndelegate (credential interface{}) Bool } type SendAction struct { diff --git a/x/agent/README.org b/x/agent/README.org index a6603d8f5..d9fcc74bd 100644 --- a/x/agent/README.org +++ b/x/agent/README.org @@ -1,17 +1,46 @@ -#+TITLE: Agent Module +#+TITLE: Group Module * Overview -The agent module provides a mechanism that can be used to support basic +The group module provides a mechanism that can be used to support basic multi-party organizations and to allow individuals to facilitate authorization -via multiple keys. In the future, it may be extended to support more sophisticated +via multiple keys (key groups). In the future, it may be extended to support more sophisticated multi-party authorization schemes. * Motivation and Rationale * Transaction Messages and Types +#+BEGIN_SRC go +type AuthPolicy int + +const ( + MultiSig AuthPolicy = 0 +) + +// A group can be used to abstract over users and groups +// It could be used by a single user to manage multiple devices and setup a multisig policy +// It could be used to group individuals into a group or several groups/users into a larger group +type Group struct { + AuthPolicy AuthPolicy `json:"auth_policy"` + // An Group can have any Account with an AccAddress as a member, including other groups + Members []Member `json:"addresses,omitempty"` + // A big integer is used here to avoid any potential vulnerabilities from overflow errors + // where large power and threshold values are used + MultisigThreshold big.Int `json:"multisig_threshold"` + // TODO maybe make this something more specific to a domain name or a claim on identity? or Memo leave it generic + Memo string `json:"memo,omitempty"` +} + +type Member struct { + Address sdk.AccAddress `json:"address"` + Power big.Int `json:"power,omitempty"` +} + + + +#+END_SRC go * Identifiers - Agents are identified by the URI formed by taking the bech32 encoding of the agent's integer ID with the prefix ~xrn:agt/~. + Groups implement the ~Account~ interface and thus have an ~AccAddress~. Internally an group ID is an ~uint64~ which is assigned on an auto-increment basis. The ~AccAddress~ for an group is made by concatenating the prefix ~G~ (as ~[]byte~) and the [[https://golang.org/pkg/encoding/binary/#PutUvarint][varint]] encoding of the ~uint64~ account ID. The textual representation of an group account is obtained by taking the bech32 encoding of this ~AccAddress~ with the prefix ~xrn:~ which also is a valid URI. * Indexing and Queries diff --git a/x/agent/types.go b/x/agent/types.go index b95aa166f..58c081e81 100644 --- a/x/agent/types.go +++ b/x/agent/types.go @@ -24,4 +24,3 @@ type AgentInfo struct { MultisigThreshold int `json:"multisig_threshold"` Memo string `json:"memo,omitempty"` } - diff --git a/x/esp/README.org b/x/esp/README.org index 7c47127fe..13af8cab6 100644 --- a/x/esp/README.org +++ b/x/esp/README.org @@ -19,25 +19,25 @@ for visualization of global ecological health. type ESPVersionID []byte type ESPVersionSpec { - Curator agent.AgentID `json:"curator"` + Curator sdk.AccAddress `json:"curator"` Name string `json:"name"` Version string `json:"version"` - Verifiers []action.ActorID `json:"verifiers"` + Verifiers []sdk.AccAddress `json:"verifiers"` // TODO ClaimSchema schema.SchemaID?? } type ESPResult struct { ESP ESPVersionID - Verifier action.ActorID `json:"verifier"` + Verifier sdk.AccAddress `json:"verifier"` Geo geo.GeoID Claim data.DataID } type ActionRegisterESPVersion struct { - Curator agent.AgentID `json:"curator"` + Curator sdk.AccAddress `json:"curator"` Name string `json:"name"` Version string `json:"version"` - Verifiers []action.ActorID `json:"verifiers"` + Verifiers []sdk.AccAddress `json:"verifiers"` } type ActionReportESPResult struct { diff --git a/x/schema/README.org b/x/schema/README.org index 97455f9fe..06e39fc12 100644 --- a/x/schema/README.org +++ b/x/schema/README.org @@ -32,11 +32,11 @@ Classes, properties and labels receive an auto-incremented integer ID. This ID is used in references in class and property definitions and can also used for saving storage space in a binary RDF serialization format. #+BEGIN_SRC go :tangle types.go - type PropertyID int64 + type PropertyID uint64 - type ClassID int64 + type ClassID uint64 - type LabelID int64 + type LabelID uint64 #+END_SRC ** Define Property diff --git a/x/token/README.org b/x/token/README.org new file mode 100644 index 000000000..1d2917e19 --- /dev/null +++ b/x/token/README.org @@ -0,0 +1,23 @@ +#+BEGIN_SRC go +type InitialBalance interface { + Address sdk.AccAddress + Balance sdk.Int +} + +type TokenId []byte + +type TokenKeeper interface { + CreateToken(ctx sdk.Context, denom string, minter sdk.AccAddress, initialBalances []InitialBalance) + GetSupply(ctx sdk.Context, denom string) sdk.Int +} + +type ActionMint interface { + Denom string + Amount sdk.Int + Address sdk.AccAddress +} + +type MintCapability interface { + Denom string +} +#+END_SRC go -- GitLab From 0c4a03ddf9341efda08f1a813b4cdf04167e44a0 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 14 Feb 2019 11:18:42 -0500 Subject: [PATCH 13/41] Wrote first draft of writing_specs.org [#163536259], updates to other specs --- docs/writing_specs.org | 74 ++++++++++++++++++++++++++++++++++++++++++ x/data/README.org | 6 ++++ x/geo/README.org | 3 ++ 3 files changed, 83 insertions(+) create mode 100644 docs/writing_specs.org diff --git a/docs/writing_specs.org b/docs/writing_specs.org new file mode 100644 index 000000000..00ab63fa5 --- /dev/null +++ b/docs/writing_specs.org @@ -0,0 +1,74 @@ +#+TITLE: Writing Specification Documents + +* Overview and Goals + + This document describes guidelines for writing specification documents. These documents are intended to serve the following purposes: + +- provide the necessary structure to discuss designs while they are in progress before they are built +- provide the blueprints for developers to implement the specified functionality +- serve as documentation once functionality has been implemented + +With these three purposes in mind, specification documents are designed to be useful before, during, and after development. They are intended to be living documents that are upgraded as new use cases are discovered and as the actual implementation changes. + +* General + +** Specifications are written in [[https://orgmode.org][Org Mode]] format + *Rationale:* While org mode is less ubiquitous than Markdown and most well supported in Emacs (though not exclusively), it has some advantages. In particular, we want to leverage Org Babel tangling to keep interface level code in the specification document itself and then have it generated into code. In addition, org mode provides a number of other potentially useful features such as integrated Latex and bibliography support and is in general well supported by Github and Gitlab. Overall it is believed that the benefits, in particular Org Babel, outweigh the learning curve compared to Markdown. + +** Specifications should indicate the implementation status of the specified functionality + As specifications are intended to be living documents that are useful both before and after functionality has been implemented, and as they are intended to be upgraded as new functionality is planned and added, they should indicate the actual implementation status. +*** TODO how should status be indicated + +* Organization + Specification documents are to be written for both components and modules. In this context components are defined as individual software artifacts in the build process whereas modules are specific modules specified in Regen Ledger. + +** TODO there should be a root spec file or "table of contents" in the `docs/` folder + +* Component Specifications + Each component (defined as an independent build artifact or separate running process) should have its own ~README.org~ file. We expect have the following components so far: + * Server + * ~xrnd~ blockchain node + * Postgis index of blockchain data + * Jena index of blockchain data + * Client + * ~xrncli~ blockchain client. (Documentation shouldn't duplicate what is available in CLI help) + * Mobile client SDK's - javascript, android, iOS + +* Regen Ledger Module Specifications + Each module in Regen Ledger should have a ~README.org~ document at the root of its folder. This file should contain at a minimum the following sections: + +** Overview + This section describes at a high-level what the module does and possibly contains some tutorial walk-through of the functionality, usually with the ~xrncli~ command line tool. + +** Motivation + The motivation section should document why this module ever came into being. What use cases where considered that led to this module being created. Where possible this section should link to other use case and requirements documentation. + +** Transaction Messages and Types + This section defines the public-facing interface for making blockchain transactions. These are the Cosmos SDK messages and other related types that an SDK consumer will use to interact with the module transactionally. Each transaction message as well as important shared types should be documented in a separate section which describes: + - what this message/type does + - any important behavioral notes for both implementers and users + - transaction fees and their rationale + - what ~Tags~ and/or ~Data~ to expect in the transaction response + +*** Org Babel source code + The code for each message/type should be specified in an [[https://orgmode.org/worg/org-contrib/babel/][Org Babel]] code block that gets tangled into ~types.go~. In the preamble to the ~README.org~ file code block (usually with ~:exports none~) should specify a preamble to ~types.go~ that looks something like this (this code block can and should be used as a snippet to start from): + +#+BEGIN_SRC go :tangle types.go :exports none + // GENERATED FROM README.org + // DO NOT EDIT THIS FILE DIRECTLY!!!!! + package data + + import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ) +#+END_SRC + +** Identifiers + + Any identifiers such as blockchain addresses and URL's related to this module should be specified in this section. + +** Indexing and Queries + The projection of module data module to indexes (like Postgresql) as well as queries that should be supported directly against the blockchain should be specified here at a level of rigor comparable to the *Transaction Messages and Types* specifications, including Org Babel code blocks to be tangled into ~types.go~ or other relevant source code files (like SQL schema definitions). + +** Rationale + The rationale for why the implementation described above was chosen should be documented in this section. Where necessary a *Rationale:* paragraph should be included inline in other sections to provide clarity on more specific behavioral choices. diff --git a/x/data/README.org b/x/data/README.org index 4575eeb61..b304bc112 100644 --- a/x/data/README.org +++ b/x/data/README.org @@ -66,6 +66,9 @@ enhanced with robust, opt-in schema-validation support in the future. Signer sdk.AccAddress `json:"signer"` } #+END_SRC + +*** TODO should data stores that reference off-chain data have their own on-chain reference and data tracking instead of a URL just reference the service via which it can be retrieved by hash? + i.e. if we know the service ID we can just do an HTTP GET for ~/~. ** Track arbitrary off-chain data @@ -93,6 +96,9 @@ enhanced with robust, opt-in schema-validation support in the future. ** TODO allow for multiple URL's to be provided for off-chain data and to allow possible ways to deal with hash collisions ** TODO possibly make URL's for off-chain data optional + +** TODO support for tracking the merkle roots of off-chain data stores + This should probably be coordinated with the IBC spec * Identifiers ** On-chain graphs diff --git a/x/geo/README.org b/x/geo/README.org index 2cd4eb20c..2082d0fa9 100644 --- a/x/geo/README.org +++ b/x/geo/README.org @@ -44,6 +44,9 @@ EWKB []byte `json:"ewkb,omitempty"` } #+END_SRC +*** TODO we probably don't need to store points here, no use for anything other than polygons here +*** TODO should this module provide support for off-chain geo-features for protecting privacy?? + Should this support include some sort of nonce support like in data? ** Identifiers *** TODO ~Geometry~ URI's -- GitLab From 5f1ddf36ec6d3359f4965daca317052db2644173 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 14 Feb 2019 11:40:53 -0500 Subject: [PATCH 14/41] [finishes #163983969] group module spec --- x/agent/README.org | 82 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/x/agent/README.org b/x/agent/README.org index d9fcc74bd..07dd802c8 100644 --- a/x/agent/README.org +++ b/x/agent/README.org @@ -1,46 +1,86 @@ #+TITLE: Group Module +#+BEGIN_SRC go :tangle types.go :exports none + // GENERATED FROM README.org + // DO NOT EDIT THIS FILE DIRECTLY!!!!! + package data + + import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ) +#+END_SRC * Overview -The group module provides a mechanism that can be used to support basic -multi-party organizations and to allow individuals to facilitate authorization -via multiple keys (key groups). In the future, it may be extended to support more sophisticated -multi-party authorization schemes. + The group module provides a mechanism that can be used to support basic multi-party organizations and to allow individuals to authorize their own transactions via multiple keys on different devices (key groups). In the future, it may be extended to support more sophisticated multi-party authorization schemes. -* Motivation and Rationale +* Motivation + There are a number of scenarios where we want to model a group or organization concept on the blockchain. Here are some hypothesized groups that this module should serve: -* Transaction Messages and Types -#+BEGIN_SRC go -type AuthPolicy int +** Regen Consortium and its member organizations + The Regen Consortium is intended to be the group of organizations that govern the Regen Ledger blockchain. They get to choose the validator set, decide on major upgrades to the blockchain as well as a number of parameters like transaction fees. Each consortium member itself must be an organization that likely has its own decision making policy. + +** Protocol and Contract Curators + Ecological state protocols (ESPs) and contracts (ECs) have been theorized to specify some organization or group that "curates" them. Curation has a number of different benefits and responsibilities. ESP curators have the responsibility of upgrading the protocols over time and may also receive curator fees when ESPs are run. EC curators may also receive a fee and/or be required to intervene to arbitrate terms of a contract. -const ( - MultiSig AuthPolicy = 0 -) +** Verifiers + It is hypothesized that verifiers may likely be multi-party organizations that have their own governance protocol for approving verification claims. -// A group can be used to abstract over users and groups -// It could be used by a single user to manage multiple devices and setup a multisig policy -// It could be used to group individuals into a group or several groups/users into a larger group +* Transaction Messages and Types +** Basic Types +#+BEGIN_SRC go :tangle types.go +// A group can be used to abstract over users and groups. +// It could be used to group individuals into a group or several groups/users into a larger group. +// It could be used by a single user to manage multiple devices and setup a multisig policy. type Group struct { - AuthPolicy AuthPolicy `json:"auth_policy"` - // An Group can have any Account with an AccAddress as a member, including other groups + // The members of the group and their associated power Members []Member `json:"addresses,omitempty"` + // Specifies the number of votes that must be accumulated in order for a decision to be made by the group. + // A member gets as many votes as is indicated by their Power field. // A big integer is used here to avoid any potential vulnerabilities from overflow errors - // where large power and threshold values are used - MultisigThreshold big.Int `json:"multisig_threshold"` + // where large power and threshold values are used. + Threshold big.Int `json:"threshold"` // TODO maybe make this something more specific to a domain name or a claim on identity? or Memo leave it generic Memo string `json:"memo,omitempty"` } +// A member specifies a address and a power for a group member type Member struct { + // The address of a group member. Can be another group or a contract Address sdk.AccAddress `json:"address"` + // The integral power of this member with respect to other members and the decision threshold Power big.Int `json:"power,omitempty"` } - - - #+END_SRC go +** ~MsgCreateAgent~ + +#+BEGIN_SRC go :tangle types.go +// Creates a group on the blockchain +// Should return a tag "group.id" with the bech32 address of the group +type MsgCreateGroup struct { + Data Group `json:"data"` + Signer sdk.AccAddress `json:"signer"` +} +#+END_SRC go +*** TODO transaction fee * Identifiers Groups implement the ~Account~ interface and thus have an ~AccAddress~. Internally an group ID is an ~uint64~ which is assigned on an auto-increment basis. The ~AccAddress~ for an group is made by concatenating the prefix ~G~ (as ~[]byte~) and the [[https://golang.org/pkg/encoding/binary/#PutUvarint][varint]] encoding of the ~uint64~ account ID. The textual representation of an group account is obtained by taking the bech32 encoding of this ~AccAddress~ with the prefix ~xrn:~ which also is a valid URI. * Indexing and Queries +** ~get~ + The ~get~ query command should take the group address as a single parameter retrieve the current ~Group~ struct (as JSON) associated with that address +** Postgresql + Groups and their members should be indexed to the tables below which should allow members to look up any groups they are directly or transitively part of: + +#+BEGIN_SRC sql :tangle group.sql + CREATE TABLE group ( + address text NOT NULL PRIMARY KEY, + threshold NUMERIC NOT NULL + ); + + CREATE TABLE group_member ( + group text NOT NULL REFERENCES group, + address text NOT NULL, + power NUMERIC NOT NULL + ) +#+END_SRC go -- GitLab From 8cd0145ba50d97e7e69619a963f73c56ece878d6 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 14 Feb 2019 11:41:15 -0500 Subject: [PATCH 15/41] mv x/agent -> x/group --- x/{agent => group}/README.org | 0 x/{agent => group}/client/cli/tx.go | 0 x/{agent => group}/client/module_client.go | 0 x/{agent => group}/codec.go | 0 x/{agent => group}/handler.go | 0 x/{agent => group}/keeper.go | 0 x/{agent => group}/msgs.go | 0 x/{agent => group}/querier.go | 0 x/{agent => group}/types.go | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename x/{agent => group}/README.org (100%) rename x/{agent => group}/client/cli/tx.go (100%) rename x/{agent => group}/client/module_client.go (100%) rename x/{agent => group}/codec.go (100%) rename x/{agent => group}/handler.go (100%) rename x/{agent => group}/keeper.go (100%) rename x/{agent => group}/msgs.go (100%) rename x/{agent => group}/querier.go (100%) rename x/{agent => group}/types.go (100%) diff --git a/x/agent/README.org b/x/group/README.org similarity index 100% rename from x/agent/README.org rename to x/group/README.org diff --git a/x/agent/client/cli/tx.go b/x/group/client/cli/tx.go similarity index 100% rename from x/agent/client/cli/tx.go rename to x/group/client/cli/tx.go diff --git a/x/agent/client/module_client.go b/x/group/client/module_client.go similarity index 100% rename from x/agent/client/module_client.go rename to x/group/client/module_client.go diff --git a/x/agent/codec.go b/x/group/codec.go similarity index 100% rename from x/agent/codec.go rename to x/group/codec.go diff --git a/x/agent/handler.go b/x/group/handler.go similarity index 100% rename from x/agent/handler.go rename to x/group/handler.go diff --git a/x/agent/keeper.go b/x/group/keeper.go similarity index 100% rename from x/agent/keeper.go rename to x/group/keeper.go diff --git a/x/agent/msgs.go b/x/group/msgs.go similarity index 100% rename from x/agent/msgs.go rename to x/group/msgs.go diff --git a/x/agent/querier.go b/x/group/querier.go similarity index 100% rename from x/agent/querier.go rename to x/group/querier.go diff --git a/x/agent/types.go b/x/group/types.go similarity index 100% rename from x/agent/types.go rename to x/group/types.go -- GitLab From 0c74e72b9b7179f231c06227e873f4fb9c2b0044 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 14 Feb 2019 11:52:47 -0500 Subject: [PATCH 16/41] Added Rationale to group spec [#163983969] --- x/group/README.org | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/group/README.org b/x/group/README.org index 07dd802c8..72aec2b71 100644 --- a/x/group/README.org +++ b/x/group/README.org @@ -84,3 +84,5 @@ type MsgCreateGroup struct { power NUMERIC NOT NULL ) #+END_SRC go +* Rationale + Groups are designed with a simple power/threshold voting mechanism. Other voting mechanisms could be added to the ~Group~ type in the future, but for now this simple mechanism is theorized to be sufficient for most of our immediate use cases. To begin with ~Threshold~ allows for any sort of majority of super-majority voting system where all members have equal power. It also allows for minority voting systems where say we are managing our own keys and have several devices but only need say two at a time to approve a transaction. The addition of the ~Power~ parameter for each member allows for managing voting scenarios where power is distributed unequally - say in ownership shares of a company. So if persons A, B, and C each had 1000 shares and person D had 2000 shares, we could set their ~Power~'s to their share count and ~Threshold~ to 2500 for simply majority approval. Many other governance mechanisms that are more complex could actually be handled by nesting groups with different responsibilities. For instance say we had a reporter/approver approval mechanism for an ESP report. We could have a group of reporters in a group with equal power and ~Threshold~ 1, and a similar group for approvers, and then join them into a reporter/approver group where the reporter group and approver group are each members with ~Power~ 1 and ~Threshold~ 2. This arrangements specifies that we need one reporter and one approver to sign off on a report. While there are scenarios that definitely can't be handled with this type of governance definition, there are a surprisingly large number that can and so our hypothesis is that this is sufficient to start until more scenarios are encountered. -- GitLab From 77ed05e79a48175f7ce57444f4fa758a6f466897 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 14 Feb 2019 13:22:58 -0500 Subject: [PATCH 17/41] Updated group spec as per working group updates [finishes #163983969] --- x/group/README.org | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/x/group/README.org b/x/group/README.org index 72aec2b71..3685e47c3 100644 --- a/x/group/README.org +++ b/x/group/README.org @@ -11,7 +11,7 @@ * Overview - The group module provides a mechanism that can be used to support basic multi-party organizations and to allow individuals to authorize their own transactions via multiple keys on different devices (key groups). In the future, it may be extended to support more sophisticated multi-party authorization schemes. + A ~Group~ is an aggregation of Regen Ledger addresses - which themselves can be individual keys, other groups, or contracts - each with an associated voting ~Weight~ and a ~DecisionThreshold~. This allows for specifying on-chain organizations as well as arbitrary groups of keys that have a governance structure that includes simple majority, super-majority, minority approval, and weighted ownership. In the future, it may be extended to support more sophisticated multi-party authorization schemes. * Motivation There are a number of scenarios where we want to model a group or organization concept on the blockchain. Here are some hypothesized groups that this module should serve: @@ -32,23 +32,23 @@ // It could be used to group individuals into a group or several groups/users into a larger group. // It could be used by a single user to manage multiple devices and setup a multisig policy. type Group struct { - // The members of the group and their associated power + // The members of the group and their associated weight Members []Member `json:"addresses,omitempty"` // Specifies the number of votes that must be accumulated in order for a decision to be made by the group. - // A member gets as many votes as is indicated by their Power field. + // A member gets as many votes as is indicated by their Weight field. // A big integer is used here to avoid any potential vulnerabilities from overflow errors - // where large power and threshold values are used. - Threshold big.Int `json:"threshold"` + // where large weight and threshold values are used. + DecisionThreshold big.Int `json:"decision_threshold"` // TODO maybe make this something more specific to a domain name or a claim on identity? or Memo leave it generic Memo string `json:"memo,omitempty"` } -// A member specifies a address and a power for a group member +// A member specifies a address and a weight for a group member type Member struct { // The address of a group member. Can be another group or a contract Address sdk.AccAddress `json:"address"` - // The integral power of this member with respect to other members and the decision threshold - Power big.Int `json:"power,omitempty"` + // The integral weight of this member with respect to other members and the decision threshold + Weight big.Int `json:"weight,omitempty"` } #+END_SRC go ** ~MsgCreateAgent~ @@ -81,8 +81,8 @@ type MsgCreateGroup struct { CREATE TABLE group_member ( group text NOT NULL REFERENCES group, address text NOT NULL, - power NUMERIC NOT NULL + weight NUMERIC NOT NULL ) #+END_SRC go * Rationale - Groups are designed with a simple power/threshold voting mechanism. Other voting mechanisms could be added to the ~Group~ type in the future, but for now this simple mechanism is theorized to be sufficient for most of our immediate use cases. To begin with ~Threshold~ allows for any sort of majority of super-majority voting system where all members have equal power. It also allows for minority voting systems where say we are managing our own keys and have several devices but only need say two at a time to approve a transaction. The addition of the ~Power~ parameter for each member allows for managing voting scenarios where power is distributed unequally - say in ownership shares of a company. So if persons A, B, and C each had 1000 shares and person D had 2000 shares, we could set their ~Power~'s to their share count and ~Threshold~ to 2500 for simply majority approval. Many other governance mechanisms that are more complex could actually be handled by nesting groups with different responsibilities. For instance say we had a reporter/approver approval mechanism for an ESP report. We could have a group of reporters in a group with equal power and ~Threshold~ 1, and a similar group for approvers, and then join them into a reporter/approver group where the reporter group and approver group are each members with ~Power~ 1 and ~Threshold~ 2. This arrangements specifies that we need one reporter and one approver to sign off on a report. While there are scenarios that definitely can't be handled with this type of governance definition, there are a surprisingly large number that can and so our hypothesis is that this is sufficient to start until more scenarios are encountered. + Groups are designed with a simple weight/threshold voting mechanism. Other voting mechanisms could be added to the ~Group~ type in the future, but for now this simple mechanism is theorized to be sufficient for most of our immediate use cases. To begin with ~DecisionThreshold~ allows for any sort of majority of super-majority voting system where all members have equal weight. It also allows for minority voting systems where say we are managing our own keys and have several devices but only need say two at a time to approve a transaction. The addition of the ~Weight~ parameter for each member allows for managing voting scenarios where weight is distributed unequally - say in ownership shares of a company. So if persons A, B, and C each had 1000 shares and person D had 2000 shares, we could set their ~Weight~'s to their share count and ~DecisionThreshold~ to 2501 for simply majority approval. Many other governance mechanisms that are more complex could actually be handled by nesting groups with different responsibilities. For instance say we had a reporter/approver approval mechanism for an ESP report. We could have a group of reporters in a group with equal weight and ~DecisionThreshold~ 1, and a similar group for approvers, and then join them into a reporter/approver group where the reporter group and approver group are each members with ~Weight~ 1 and ~DecisionThreshold~ 2. This arrangements specifies that we need one reporter and one approver to sign off on a report. While there are scenarios that definitely can't be handled with this type of governance definition, there are a surprisingly large number that can and so our hypothesis is that this is sufficient to start until more scenarios are encountered. -- GitLab From a413d1a14c66bb24568c5ab20f224f6ab70b5820 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 14 Feb 2019 13:32:11 -0500 Subject: [PATCH 18/41] Updated writing_specs.org as per working group discussion and added status to group spec [finishes #163536259] --- docs/writing_specs.org | 15 ++++++++++++--- x/group/README.org | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/writing_specs.org b/docs/writing_specs.org index 00ab63fa5..688a69552 100644 --- a/docs/writing_specs.org +++ b/docs/writing_specs.org @@ -16,8 +16,13 @@ With these three purposes in mind, specification documents are designed to be us *Rationale:* While org mode is less ubiquitous than Markdown and most well supported in Emacs (though not exclusively), it has some advantages. In particular, we want to leverage Org Babel tangling to keep interface level code in the specification document itself and then have it generated into code. In addition, org mode provides a number of other potentially useful features such as integrated Latex and bibliography support and is in general well supported by Github and Gitlab. Overall it is believed that the benefits, in particular Org Babel, outweigh the learning curve compared to Markdown. ** Specifications should indicate the implementation status of the specified functionality - As specifications are intended to be living documents that are useful both before and after functionality has been implemented, and as they are intended to be upgraded as new functionality is planned and added, they should indicate the actual implementation status. -*** TODO how should status be indicated + As specifications are intended to be living documents that are useful both before and after functionality has been implemented, and as they are intended to be upgraded as new functionality is planned and added, they should indicate the actual implementation status. Status should be indicated under the title using *STATUS:* with one of the following three states: + + - *In Process* to indicate that a specification is being worked on + - *Approved* indicating that a specification has discussed and consensus has been achieved amongst the team + - *Implemented* indicating that the specification reflects the state of the actual code and can thus be used as documentation + + Whenever a specification is out-of-sync with the actual code, a message indicating this can be included next to the status such as "(out of sync with implementation)" to indicate that there is some implementation that differs from this spec. Maintainers should aim not to tag any commit as a release that is out of sync with the implementation because then the documentation is messed up. * Organization Specification documents are to be written for both components and modules. In this context components are defined as individual software artifacts in the build process whereas modules are specific modules specified in Regen Ledger. @@ -38,7 +43,7 @@ With these three purposes in mind, specification documents are designed to be us Each module in Regen Ledger should have a ~README.org~ document at the root of its folder. This file should contain at a minimum the following sections: ** Overview - This section describes at a high-level what the module does and possibly contains some tutorial walk-through of the functionality, usually with the ~xrncli~ command line tool. + This section describes what the module does at a high-level and includes the definition of any pertinent terms as a source of truth for clarity across the team. ** Motivation The motivation section should document why this module ever came into being. What use cases where considered that led to this module being created. Where possible this section should link to other use case and requirements documentation. @@ -72,3 +77,7 @@ With these three purposes in mind, specification documents are designed to be us ** Rationale The rationale for why the implementation described above was chosen should be documented in this section. Where necessary a *Rationale:* paragraph should be included inline in other sections to provide clarity on more specific behavioral choices. + +** CLI Tutorial (optional) + A tutorial walk-through of using the module using the ~xrncli~ command line tool. + diff --git a/x/group/README.org b/x/group/README.org index 3685e47c3..717e58e76 100644 --- a/x/group/README.org +++ b/x/group/README.org @@ -1,4 +1,6 @@ #+TITLE: Group Module +*STATUS: In Process* (out of sync with implementation) + #+BEGIN_SRC go :tangle types.go :exports none // GENERATED FROM README.org // DO NOT EDIT THIS FILE DIRECTLY!!!!! -- GitLab From b1213efc76bae557a21935e6378670464e2ee109 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 14 Feb 2019 16:39:22 -0500 Subject: [PATCH 19/41] Added gherkin feature specs for group create and get features [#163990020] --- go.mod | 1 + go.sum | 2 ++ x/group/README.org | 7 ++++++- x/group/features/create.feature | 6 ++++++ x/group/features/get.feature | 5 +++++ 5 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 x/group/features/create.feature create mode 100644 x/group/features/get.feature diff --git a/go.mod b/go.mod index 58633c6e7..fd06c2dd9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ module gitlab.com/regen-network/regen-ledger require ( + github.com/DATA-DOG/godog v0.7.10 // indirect github.com/ZondaX/hid-go v0.4.0 github.com/ZondaX/ledger-go v0.4.0 github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d diff --git a/go.sum b/go.sum index 585246ace..747373489 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/DATA-DOG/godog v0.7.10 h1:BRaQdCOsFth//Ep/J6gtb3xOeDh+sAVjL44ZdK1E9aI= +github.com/DATA-DOG/godog v0.7.10/go.mod h1:z2OZ6a3X0/YAKVqLfVzYBwFt3j6uSt3Xrqa7XTtcQE0= github.com/ZondaX/hid-go v0.4.0/go.mod h1:eaChKpVjUVdM78f1sM/TSFedameXSbNXGiLNvl6sKsA= github.com/ZondaX/ledger-go v0.4.0/go.mod h1:9Q7YMPYFR7tKocUfb8layi5V2tLqZbMs3q0ArLGDFWw= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= diff --git a/x/group/README.org b/x/group/README.org index 717e58e76..7cb6df93c 100644 --- a/x/group/README.org +++ b/x/group/README.org @@ -4,7 +4,7 @@ #+BEGIN_SRC go :tangle types.go :exports none // GENERATED FROM README.org // DO NOT EDIT THIS FILE DIRECTLY!!!!! - package data + package group import ( sdk "github.com/cosmos/cosmos-sdk/types" @@ -54,6 +54,8 @@ type Member struct { } #+END_SRC go ** ~MsgCreateAgent~ + + /[[./features/create.feature][Test spec]]/ #+BEGIN_SRC go :tangle types.go // Creates a group on the blockchain @@ -70,6 +72,9 @@ type MsgCreateGroup struct { * Indexing and Queries ** ~get~ + + /[[./features/get.feature][Test spec]]/ + The ~get~ query command should take the group address as a single parameter retrieve the current ~Group~ struct (as JSON) associated with that address ** Postgresql Groups and their members should be indexed to the tables below which should allow members to look up any groups they are directly or transitively part of: diff --git a/x/group/features/create.feature b/x/group/features/create.feature new file mode 100644 index 000000000..4748f8d65 --- /dev/null +++ b/x/group/features/create.feature @@ -0,0 +1,6 @@ +Feature: Create group + Scenario: Create a group from a single key + Given a public key address + When a user creates a group with that address + And a decision threshold of 1 + Then they should get a new group address back \ No newline at end of file diff --git a/x/group/features/get.feature b/x/group/features/get.feature new file mode 100644 index 000000000..632eb4632 --- /dev/null +++ b/x/group/features/get.feature @@ -0,0 +1,5 @@ +Feature: Get group details + Scenario: + Given a group ID + When a user gets the group details on the command line + Then they should get back the group details in JSON format \ No newline at end of file -- GitLab From da5d05e3fd17882710891389ed04cf3114b2f41f Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 10:18:41 -0500 Subject: [PATCH 20/41] Checked out x/agent again to get this branch building, WIP on group godog tests --- {x/group/features => features}/create.feature | 0 {x/group/features => features}/get.feature | 0 go.mod | 2 +- x/agent/README.org | 86 ++++++++++ x/agent/client/cli/tx.go | 85 ++++++++++ x/agent/client/module_client.go | 47 ++++++ x/agent/codec.go | 10 ++ x/agent/handler.go | 37 +++++ x/agent/keeper.go | 153 ++++++++++++++++++ x/agent/msgs.go | 79 +++++++++ x/agent/querier.go | 46 ++++++ x/agent/types.go | 26 +++ x/data/schema.json | 10 -- x/data/types.go | 52 ------ x/group/README.org | 14 +- x/group/codec.go | 2 +- x/group/group_test.go | 37 +++++ x/group/handler.go | 2 +- x/group/keeper.go | 2 +- x/group/msgs.go | 2 +- x/group/querier.go | 2 +- x/group/types.go | 2 +- 22 files changed, 625 insertions(+), 71 deletions(-) rename {x/group/features => features}/create.feature (100%) rename {x/group/features => features}/get.feature (100%) create mode 100644 x/agent/README.org create mode 100644 x/agent/client/cli/tx.go create mode 100644 x/agent/client/module_client.go create mode 100644 x/agent/codec.go create mode 100644 x/agent/handler.go create mode 100644 x/agent/keeper.go create mode 100644 x/agent/msgs.go create mode 100644 x/agent/querier.go create mode 100644 x/agent/types.go delete mode 100644 x/data/schema.json delete mode 100644 x/data/types.go create mode 100644 x/group/group_test.go diff --git a/x/group/features/create.feature b/features/create.feature similarity index 100% rename from x/group/features/create.feature rename to features/create.feature diff --git a/x/group/features/get.feature b/features/get.feature similarity index 100% rename from x/group/features/get.feature rename to features/get.feature diff --git a/go.mod b/go.mod index fd06c2dd9..9270f8eac 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module gitlab.com/regen-network/regen-ledger require ( - github.com/DATA-DOG/godog v0.7.10 // indirect + github.com/DATA-DOG/godog v0.7.10 github.com/ZondaX/hid-go v0.4.0 github.com/ZondaX/ledger-go v0.4.0 github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d diff --git a/x/agent/README.org b/x/agent/README.org new file mode 100644 index 000000000..07dd802c8 --- /dev/null +++ b/x/agent/README.org @@ -0,0 +1,86 @@ +#+TITLE: Group Module +#+BEGIN_SRC go :tangle types.go :exports none + // GENERATED FROM README.org + // DO NOT EDIT THIS FILE DIRECTLY!!!!! + package data + + import ( + sdk "github.com/cosmos/cosmos-sdk/types" + ) +#+END_SRC + +* Overview + + The group module provides a mechanism that can be used to support basic multi-party organizations and to allow individuals to authorize their own transactions via multiple keys on different devices (key groups). In the future, it may be extended to support more sophisticated multi-party authorization schemes. + +* Motivation + There are a number of scenarios where we want to model a group or organization concept on the blockchain. Here are some hypothesized groups that this module should serve: + +** Regen Consortium and its member organizations + The Regen Consortium is intended to be the group of organizations that govern the Regen Ledger blockchain. They get to choose the validator set, decide on major upgrades to the blockchain as well as a number of parameters like transaction fees. Each consortium member itself must be an organization that likely has its own decision making policy. + +** Protocol and Contract Curators + Ecological state protocols (ESPs) and contracts (ECs) have been theorized to specify some organization or group that "curates" them. Curation has a number of different benefits and responsibilities. ESP curators have the responsibility of upgrading the protocols over time and may also receive curator fees when ESPs are run. EC curators may also receive a fee and/or be required to intervene to arbitrate terms of a contract. + +** Verifiers + It is hypothesized that verifiers may likely be multi-party organizations that have their own governance protocol for approving verification claims. + +* Transaction Messages and Types +** Basic Types +#+BEGIN_SRC go :tangle types.go +// A group can be used to abstract over users and groups. +// It could be used to group individuals into a group or several groups/users into a larger group. +// It could be used by a single user to manage multiple devices and setup a multisig policy. +type Group struct { + // The members of the group and their associated power + Members []Member `json:"addresses,omitempty"` + // Specifies the number of votes that must be accumulated in order for a decision to be made by the group. + // A member gets as many votes as is indicated by their Power field. + // A big integer is used here to avoid any potential vulnerabilities from overflow errors + // where large power and threshold values are used. + Threshold big.Int `json:"threshold"` + // TODO maybe make this something more specific to a domain name or a claim on identity? or Memo leave it generic + Memo string `json:"memo,omitempty"` +} + +// A member specifies a address and a power for a group member +type Member struct { + // The address of a group member. Can be another group or a contract + Address sdk.AccAddress `json:"address"` + // The integral power of this member with respect to other members and the decision threshold + Power big.Int `json:"power,omitempty"` +} +#+END_SRC go +** ~MsgCreateAgent~ + +#+BEGIN_SRC go :tangle types.go +// Creates a group on the blockchain +// Should return a tag "group.id" with the bech32 address of the group +type MsgCreateGroup struct { + Data Group `json:"data"` + Signer sdk.AccAddress `json:"signer"` +} +#+END_SRC go +*** TODO transaction fee + +* Identifiers + Groups implement the ~Account~ interface and thus have an ~AccAddress~. Internally an group ID is an ~uint64~ which is assigned on an auto-increment basis. The ~AccAddress~ for an group is made by concatenating the prefix ~G~ (as ~[]byte~) and the [[https://golang.org/pkg/encoding/binary/#PutUvarint][varint]] encoding of the ~uint64~ account ID. The textual representation of an group account is obtained by taking the bech32 encoding of this ~AccAddress~ with the prefix ~xrn:~ which also is a valid URI. + +* Indexing and Queries +** ~get~ + The ~get~ query command should take the group address as a single parameter retrieve the current ~Group~ struct (as JSON) associated with that address +** Postgresql + Groups and their members should be indexed to the tables below which should allow members to look up any groups they are directly or transitively part of: + +#+BEGIN_SRC sql :tangle group.sql + CREATE TABLE group ( + address text NOT NULL PRIMARY KEY, + threshold NUMERIC NOT NULL + ); + + CREATE TABLE group_member ( + group text NOT NULL REFERENCES group, + address text NOT NULL, + power NUMERIC NOT NULL + ) +#+END_SRC go diff --git a/x/agent/client/cli/tx.go b/x/agent/client/cli/tx.go new file mode 100644 index 000000000..23b5d1ee3 --- /dev/null +++ b/x/agent/client/cli/tx.go @@ -0,0 +1,85 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/utils" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" + "github.com/spf13/cobra" + utils2 "gitlab.com/regen-network/regen-ledger/utils" + "gitlab.com/regen-network/regen-ledger/x/agent" +) + +func addrsFromBech32Array(arr []string) []sdk.AccAddress { + n := len(arr) + res := make([]sdk.AccAddress, n) + for i := 0; i < n; i++ { + str := arr[i] + acc, err := sdk.AccAddressFromBech32(str) + if err != nil { + panic(err) + } + res[i] = acc + } + return res +} + +func AgentsFromArray(arr []string) []agent.AgentID { + n := len(arr) + res := make([]agent.AgentID, n) + for i := 0; i < n; i++ { + res[i] = agent.MustDecodeBech32AgentID(arr[i]) + } + return res +} + +func GetCmdCreateAgent(cdc *codec.Codec) *cobra.Command { + var threshold int + var addrs []string + var agents []string + + cmd := &cobra.Command{ + Use: "create", + Short: "create an agent", + //Args: cobra.MinimumNArgs(1), + PreRun: func(cmd *cobra.Command, args []string) { + + }, + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(cdc) + + txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + + if err := cliCtx.EnsureAccountExists(); err != nil { + return err + } + + account := cliCtx.GetFromAddress() + + info := agent.AgentInfo{ + AuthPolicy: agent.MultiSig, + MultisigThreshold: threshold, + Addresses: addrsFromBech32Array(addrs), + Agents: AgentsFromArray(agents), + } + + msg := agent.NewMsgCreateAgent(info, account) + err := msg.ValidateBasic() + if err != nil { + return err + } + + cliCtx.PrintResponse = true + cliCtx.ResponseHandler = utils2.PrintCLIResponse_StringData + + return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) + }, + } + + cmd.Flags().IntVar(&threshold, "threshold", 0, "Multisig threshold") + cmd.Flags().StringArrayVar(&addrs, "addrs", []string{}, "Address") + cmd.Flags().StringArrayVar(&agents, "agents", []string{}, "Agents") + + return cmd +} diff --git a/x/agent/client/module_client.go b/x/agent/client/module_client.go new file mode 100644 index 000000000..00dcb10cd --- /dev/null +++ b/x/agent/client/module_client.go @@ -0,0 +1,47 @@ +package client + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/spf13/cobra" + "github.com/tendermint/go-amino" + agentcmd "gitlab.com/regen-network/regen-ledger/x/agent/client/cli" +) + +// ModuleClient exports all client functionality from this module +type ModuleClient struct { + storeKey string + cdc *amino.Codec +} + +func NewModuleClient(storeKey string, cdc *amino.Codec) ModuleClient { + return ModuleClient{storeKey, cdc} +} + +// GetQueryCmd returns the cli query commands for this module +func (mc ModuleClient) GetQueryCmd() *cobra.Command { + agentQueryCmd := &cobra.Command{ + Use: "agent", + Short: "Querying commands for the agent module", + } + + //dataQueryCmd.AddCommand(client.GetCommands( + // datacmd.GetCmdGetData(mc.storeKey, mc.cdc), + //)...) + + return agentQueryCmd +} + +// GetTxCmd returns the transaction commands for this module +func (mc ModuleClient) GetTxCmd() *cobra.Command { + agentTxCmd := &cobra.Command{ + Use: "agent", + Short: "Agent transactions subcommands", + } + + agentTxCmd.AddCommand(client.PostCommands( + agentcmd.GetCmdCreateAgent(mc.cdc), + )...) + + return agentTxCmd +} + diff --git a/x/agent/codec.go b/x/agent/codec.go new file mode 100644 index 000000000..b54e9ad80 --- /dev/null +++ b/x/agent/codec.go @@ -0,0 +1,10 @@ +package agent + +import "github.com/cosmos/cosmos-sdk/codec" + + +func RegisterCodec(cdc *codec.Codec) { + cdc.RegisterConcrete(MsgCreateAgent{}, "agent/MsgCreateAgent", nil) + cdc.RegisterConcrete(MsgUpdateAgent{}, "agent/MsgUpdateAgent", nil) + cdc.RegisterConcrete(AgentInfo{}, "agent/AgentInfo", nil) +} diff --git a/x/agent/handler.go b/x/agent/handler.go new file mode 100644 index 000000000..5f58abe79 --- /dev/null +++ b/x/agent/handler.go @@ -0,0 +1,37 @@ +package agent + +import ( +"fmt" + +sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NewHandler returns a handler for "data" type messages. +func NewHandler(keeper Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + switch msg := msg.(type) { + case MsgCreateAgent: + return handleMsgCreateAgent(ctx, keeper, msg) + case MsgUpdateAgent: + return handleMsgUpdateAgent(ctx, keeper, msg) + default: + errMsg := fmt.Sprintf("Unrecognized data Msg type: %v", msg.Type()) + return sdk.ErrUnknownRequest(errMsg).Result() + } + } +} + + +func handleMsgCreateAgent(ctx sdk.Context, keeper Keeper, msg MsgCreateAgent) sdk.Result { + id := keeper.CreateAgent(ctx, msg.Data) + return sdk.Result{ + Tags: sdk.NewTags("agent.id", []byte(MustEncodeBech32AgentID(id))), + } +} + +func handleMsgUpdateAgent(ctx sdk.Context, keeper Keeper, msg MsgUpdateAgent) sdk.Result { + keeper.UpdateAgentInfo(ctx, msg.Id, msg.Signers, msg.Data) + return sdk.Result{ + Tags: sdk.NewTags("agent.id", []byte(MustEncodeBech32AgentID(msg.Id))), + } +} diff --git a/x/agent/keeper.go b/x/agent/keeper.go new file mode 100644 index 000000000..6f98cbbe2 --- /dev/null +++ b/x/agent/keeper.go @@ -0,0 +1,153 @@ +package agent + +import ( + "bytes" + "encoding/binary" + "fmt" + "github.com/cosmos/cosmos-sdk/codec" + "gitlab.com/regen-network/regen-ledger/utils" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type Keeper struct { + agentStoreKey sdk.StoreKey + + cdc *codec.Codec +} + +func NewKeeper(agentStoreKey sdk.StoreKey, cdc *codec.Codec) Keeper { + return Keeper{ + agentStoreKey: agentStoreKey, + cdc: cdc, + } +} + +var ( + keyNewAgentID = []byte("newAgentID") +) + +func keyAgentID(id AgentID) []byte { + return []byte(fmt.Sprintf("#%d", id)) +} + +func (keeper Keeper) GetAgentInfo(ctx sdk.Context, id AgentID) (info AgentInfo, err sdk.Error) { + store := ctx.KVStore(keeper.agentStoreKey) + bz := store.Get(keyAgentID(id)) + if bz == nil { + return info, sdk.ErrUnknownRequest("Not found") + } + info = AgentInfo{} + marshalErr := keeper.cdc.UnmarshalBinaryBare(bz, &info) + if marshalErr != nil { + return info, sdk.ErrUnknownRequest(marshalErr.Error()) + } + return info, nil +} + +const ( + Bech32Prefix = "xrnagt" +) + + +func MustEncodeBech32AgentID(id AgentID) string { + buf := make([]byte, binary.MaxVarintLen64) + n := binary.PutUvarint(buf, id) + return utils.MustEncodeBech32(Bech32Prefix, buf[:n]) +} + +func MustDecodeBech32AgentID(bech string) AgentID { + var id AgentID + hrp, bz := utils.MustDecodeBech32(bech) + if hrp != Bech32Prefix { + panic(fmt.Sprintf("Bech32 AgentID must start with %s", Bech32Prefix)) + } + id, n := binary.Uvarint(bz) + if n <= 0 { + panic("Error decoding AgentID") + } + return id +} + +func (keeper Keeper) getNewAgentId(ctx sdk.Context) (agentId AgentID) { + store := ctx.KVStore(keeper.agentStoreKey) + bz := store.Get(keyNewAgentID) + if bz == nil { + agentId = 0 + } else { + keeper.cdc.MustUnmarshalBinaryBare(bz, &agentId) + } + bz = keeper.cdc.MustMarshalBinaryBare(agentId + 1) + store.Set(keyNewAgentID, bz) + return agentId +} + +func (keeper Keeper) CreateAgent(ctx sdk.Context, info AgentInfo) AgentID { + id := keeper.getNewAgentId(ctx) + keeper.setAgentInfo(ctx, id, info) + return id +} + +func (keeper Keeper) setAgentInfo(ctx sdk.Context, id AgentID, info AgentInfo) { + store := ctx.KVStore(keeper.agentStoreKey) + bz, err := keeper.cdc.MarshalBinaryBare(info) + if err != nil { + panic(err) + } + store.Set(keyAgentID(id), bz) +} + +func (keeper Keeper) UpdateAgentInfo(ctx sdk.Context, id AgentID, signers []sdk.AccAddress, info AgentInfo) bool { + if !keeper.Authorize(ctx, id, signers) { + return false + } + keeper.setAgentInfo(ctx, id, info) + return true +} + +func (keeper Keeper) Authorize(ctx sdk.Context, id AgentID, signers []sdk.AccAddress) bool { + ctx.GasMeter().ConsumeGas(10, "agent auth") + info, err := keeper.GetAgentInfo(ctx, id) + if err != nil { + return false + } + return keeper.AuthorizeAgentInfo(ctx, &info, signers) +} + +func (keeper Keeper) AuthorizeAgentInfo(ctx sdk.Context, info *AgentInfo, signers []sdk.AccAddress) bool { + if info.AuthPolicy != MultiSig { + panic("Unknown auth policy") + } + + sigCount := 0 + sigThreshold := info.MultisigThreshold + + nAddrs := len(info.Addresses) + nSigners := len(signers) + for i := 0; i < nAddrs; i++ { + addr := info.Addresses[i] + // TODO Use a hash map to optimize this + for j := 0; j < nSigners; j++ { + ctx.GasMeter().ConsumeGas(10, "check addr") + if bytes.Compare(addr, signers[j]) == 0 { + sigCount++ + if sigCount >= sigThreshold { + return true + } + break + } + } + } + + nAgents := len(info.Agents) + for i := 0; i < nAgents; i++ { + agentId := info.Agents[i] + if keeper.Authorize(ctx, agentId, signers) { + sigCount++ + if sigCount >= sigThreshold { + return true + } + } + } + return false +} diff --git a/x/agent/msgs.go b/x/agent/msgs.go new file mode 100644 index 000000000..d46d4221e --- /dev/null +++ b/x/agent/msgs.go @@ -0,0 +1,79 @@ +package agent + +import ( + "encoding/json" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type MsgCreateAgent struct { + Data AgentInfo `json:"data"` + Signer sdk.AccAddress `json:"signer"` +} + +type MsgUpdateAgent struct { + Id AgentID `json:"id"` + Data AgentInfo `json:"data"` + Signers []sdk.AccAddress `json:"signers"` +} + +func NewMsgCreateAgent(info AgentInfo, signer sdk.AccAddress) MsgCreateAgent { + return MsgCreateAgent{ + Data: info, + Signer:signer, + } +} + +func (msg MsgCreateAgent) Route() string { return "agent" } + +func (msg MsgCreateAgent) Type() string { return "agent.create" } + +func (info AgentInfo) ValidateBasic() sdk.Error { + if len(info.Agents) <= 0 && len(info.Addresses) <= 0 { + return sdk.ErrUnknownRequest("Agent info must reference a non-empty set of members") + } + if info.AuthPolicy != MultiSig { + return sdk.ErrUnknownRequest("Only multi-sig auth policies are currently supported") + } + if info.MultisigThreshold <= 0 { + return sdk.ErrUnknownRequest("MultisigThreshold must be a positive integer") + } + return nil +} + +func (msg MsgCreateAgent) ValidateBasic() sdk.Error { + // TODO what are valid agent ID's + return msg.Data.ValidateBasic() +} + +func (msg MsgCreateAgent) GetSignBytes() []byte { + b, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return sdk.MustSortJSON(b) +} + +func (msg MsgCreateAgent) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +func (msg MsgUpdateAgent) Route() string { return "agent" } + +func (msg MsgUpdateAgent) Type() string { return "agent.update" } + +func (msg MsgUpdateAgent) ValidateBasic() sdk.Error { + return msg.Data.ValidateBasic() +} + +func (msg MsgUpdateAgent) GetSignBytes() []byte { + b, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return sdk.MustSortJSON(b) +} + +func (msg MsgUpdateAgent) GetSigners() []sdk.AccAddress { + return msg.Signers +} + diff --git a/x/agent/querier.go b/x/agent/querier.go new file mode 100644 index 000000000..c9d0aee92 --- /dev/null +++ b/x/agent/querier.go @@ -0,0 +1,46 @@ +package agent + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" + "strconv" +) + +// query endpoints supported by the governance Querier +const ( + QueryAgent = "get" +) + +func NewQuerier(keeper Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case QueryAgent: + return queryAgent(ctx, path[1:], req, keeper) + default: + return nil, sdk.ErrUnknownRequest("unknown data query endpoint") + } + } +} + + +func queryAgent(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { + idStr := path[0] + + id, parseErr := strconv.ParseUint(idStr, 10, 64) + if parseErr != nil { + return []byte{}, sdk.ErrUnknownRequest("Can't parse id") + } + + info, err := keeper.GetAgentInfo(ctx, AgentID(id)) + + if err != nil { + return []byte{}, sdk.ErrUnknownRequest("could not resolve id") + } + + res, jsonErr := codec.MarshalJSONIndent(keeper.cdc, info) + if jsonErr != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", jsonErr.Error())) + } + return res, nil +} diff --git a/x/agent/types.go b/x/agent/types.go new file mode 100644 index 000000000..58c081e81 --- /dev/null +++ b/x/agent/types.go @@ -0,0 +1,26 @@ +package agent + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TODO change to auto-increment uint64 +type AgentID = uint64 + +type AuthPolicy int + +const ( + MultiSig AuthPolicy = 0 +) + +// An agent can be used to abstract over users and groups +// It could be used by a single user to manage multiple devices and setup a multisig policy +// It could be used to group individuals into a group or several groups/users into a larger group +type AgentInfo struct { + AuthPolicy AuthPolicy `json:"auth_policy"` + // An Agent can have either addresses or other agents as members + Addresses []sdk.AccAddress `json:"addresses,omitempty"` + Agents []AgentID `json:"agents,omitempty"` + MultisigThreshold int `json:"multisig_threshold"` + Memo string `json:"memo,omitempty"` +} diff --git a/x/data/schema.json b/x/data/schema.json deleted file mode 100644 index e1f0ab43c..000000000 --- a/x/data/schema.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "definitions":{ - "MsgRegisterSchema":{ - "title":"MsgRegisterSchema", - "type":"Object", - "properties":{ - } - } - } -} diff --git a/x/data/types.go b/x/data/types.go deleted file mode 100644 index 4214b974f..000000000 --- a/x/data/types.go +++ /dev/null @@ -1,52 +0,0 @@ -// GENERATED FROM README.org -// DO NOT EDIT THIS FILE DIRECTLY!!!!! -package data - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type MsgStoreGraph struct { - // RDF graph data in N-Triples text format - NTriples string `json:"ntriples"` - // Expected hash of the graph. The transaction will be rejected if this hash can't be verified. - URDNA2015_Hash []byte `json:"urdna2015_hash"` - Signer sdk.AccAddress `json:"signer"` -} - -type DataFormat int - -const ( - Unknown DataFormat = 0 - JSON_LD DataFormat = 1 - NQuads DataFormat = 2 - Turtle DataFormat = 3 - TriG DataFormat = 4 - JSON DataFormat = 5 - XML DataFormat = 6 - YAML DataFormat = 7 - TIFF DataFormat = 8 -) - -type MsgStoreData struct { - //SchemaRef string - Data []byte `json:"data"` - Format DataFormat `json:"format,omitempty"` - Signer sdk.AccAddress `json:"signer"` -} - -type HashAlgorithm int - -const ( - BLAKE2B_256 HashAlgorithm = 0 - SHA256 HashAlgorithm = 1 - URDNA2015 HashAlgorithm = 2 - URGNA2012 HashAlgorithm = 3 -) - -type MsgTrackData struct { - Hash []byte `json:"hash"` - Algorithm HashAlgorithm `json:"algorithm"` - Format DataFormat `json:"format,omitempty"` - Url string `json:"url,omitempty"` -} diff --git a/x/group/README.org b/x/group/README.org index 7cb6df93c..e50de976b 100644 --- a/x/group/README.org +++ b/x/group/README.org @@ -64,7 +64,16 @@ type MsgCreateGroup struct { Data Group `json:"data"` Signer sdk.AccAddress `json:"signer"` } -#+END_SRC go +#+END_SRC + +#+BEGIN_SRC gherkin :tangle features/create.features +Feature: Create group + Scenario: Create a group from a single key + Given a public key address + When a user creates a group with that address + And a decision threshold of 1 + Then they should get a new group address back +#+END_SRC *** TODO transaction fee * Identifiers @@ -90,6 +99,7 @@ type MsgCreateGroup struct { address text NOT NULL, weight NUMERIC NOT NULL ) -#+END_SRC go +#+END_SRC + * Rationale Groups are designed with a simple weight/threshold voting mechanism. Other voting mechanisms could be added to the ~Group~ type in the future, but for now this simple mechanism is theorized to be sufficient for most of our immediate use cases. To begin with ~DecisionThreshold~ allows for any sort of majority of super-majority voting system where all members have equal weight. It also allows for minority voting systems where say we are managing our own keys and have several devices but only need say two at a time to approve a transaction. The addition of the ~Weight~ parameter for each member allows for managing voting scenarios where weight is distributed unequally - say in ownership shares of a company. So if persons A, B, and C each had 1000 shares and person D had 2000 shares, we could set their ~Weight~'s to their share count and ~DecisionThreshold~ to 2501 for simply majority approval. Many other governance mechanisms that are more complex could actually be handled by nesting groups with different responsibilities. For instance say we had a reporter/approver approval mechanism for an ESP report. We could have a group of reporters in a group with equal weight and ~DecisionThreshold~ 1, and a similar group for approvers, and then join them into a reporter/approver group where the reporter group and approver group are each members with ~Weight~ 1 and ~DecisionThreshold~ 2. This arrangements specifies that we need one reporter and one approver to sign off on a report. While there are scenarios that definitely can't be handled with this type of governance definition, there are a surprisingly large number that can and so our hypothesis is that this is sufficient to start until more scenarios are encountered. diff --git a/x/group/codec.go b/x/group/codec.go index b54e9ad80..94e14ec54 100644 --- a/x/group/codec.go +++ b/x/group/codec.go @@ -1,4 +1,4 @@ -package agent +package group import "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/group/group_test.go b/x/group/group_test.go new file mode 100644 index 000000000..24a55314c --- /dev/null +++ b/x/group/group_test.go @@ -0,0 +1,37 @@ +package group + +import ( + "flag" + "github.com/DATA-DOG/godog" + "github.com/DATA-DOG/godog/colors" + "os" + "testing" +) + +var opt = godog.Options{ + Output: colors.Colored(os.Stdout), + Format: "progress", // can define default values +} + +func init() { + godog.BindFlags("godog.", flag.CommandLine, &opt) +} + +func TestMain(m *testing.M) { + flag.Parse() + opt.Paths = flag.Args() + + status := godog.RunWithOptions("godogs", func(s *godog.Suite) { + FeatureContext(s) + }, opt) + + if st := m.Run(); st > status { + status = st + } + os.Exit(status) +} + + +func FeatureContext(s *godog.Suite) { + +} diff --git a/x/group/handler.go b/x/group/handler.go index 5f58abe79..277cf501d 100644 --- a/x/group/handler.go +++ b/x/group/handler.go @@ -1,4 +1,4 @@ -package agent +package group import ( "fmt" diff --git a/x/group/keeper.go b/x/group/keeper.go index 6f98cbbe2..0d1b06375 100644 --- a/x/group/keeper.go +++ b/x/group/keeper.go @@ -1,4 +1,4 @@ -package agent +package group import ( "bytes" diff --git a/x/group/msgs.go b/x/group/msgs.go index d46d4221e..9f739323e 100644 --- a/x/group/msgs.go +++ b/x/group/msgs.go @@ -1,4 +1,4 @@ -package agent +package group import ( "encoding/json" diff --git a/x/group/querier.go b/x/group/querier.go index c9d0aee92..913eb99aa 100644 --- a/x/group/querier.go +++ b/x/group/querier.go @@ -1,4 +1,4 @@ -package agent +package group import ( "github.com/cosmos/cosmos-sdk/codec" diff --git a/x/group/types.go b/x/group/types.go index 58c081e81..a824169aa 100644 --- a/x/group/types.go +++ b/x/group/types.go @@ -1,4 +1,4 @@ -package agent +package group import ( sdk "github.com/cosmos/cosmos-sdk/types" -- GitLab From ff37d37ba4f123be2e8cc337f0b0d70a9e32148c Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 12:30:37 -0500 Subject: [PATCH 21/41] Working test command that calls godog underneath [#163831110] --- .editorconfig | 2 + Makefile | 5 ++- {features => x/group/features}/create.feature | 0 {features => x/group/features}/get.feature | 0 x/group/group_test.go | 39 ++++++++++++++++++- 5 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 .editorconfig rename {features => x/group/features}/create.feature (100%) rename {features => x/group/features}/get.feature (100%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..f60c0d39e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[Makefile] +indent_style = tab \ No newline at end of file diff --git a/Makefile b/Makefile index c44118ff3..9b9dcd968 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,7 @@ export GO111MODULE=on install: go install ./cmd/xrnd - go install ./cmd/xrncli \ No newline at end of file + go install ./cmd/xrncli + +test: + go test ./... -godog.strict \ No newline at end of file diff --git a/features/create.feature b/x/group/features/create.feature similarity index 100% rename from features/create.feature rename to x/group/features/create.feature diff --git a/features/get.feature b/x/group/features/get.feature similarity index 100% rename from features/get.feature rename to x/group/features/get.feature diff --git a/x/group/group_test.go b/x/group/group_test.go index 24a55314c..634e54ee4 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -18,6 +18,7 @@ func init() { } func TestMain(m *testing.M) { + println("TEST") flag.Parse() opt.Paths = flag.Args() @@ -31,7 +32,43 @@ func TestMain(m *testing.M) { os.Exit(status) } +func aPublicKeyAddress() error { + return godog.ErrPending +} -func FeatureContext(s *godog.Suite) { +func aUserCreatesAGroupWithThatAddress() error { + return godog.ErrPending +} + +func aDecisionThresholdOf(arg1 int) error { + return godog.ErrPending +} + +func theyShouldGetANewGroupAddressBack() error { + return godog.ErrPending +} + +func aGroupID() error { + return godog.ErrPending +} +func aUserGetsTheGroupDetailsOnTheCommandLine() error { + return godog.ErrPending } + +func theyShouldGetBackTheGroupDetailsInJSONFormat() error { + return godog.ErrPending +} + + + +func FeatureContext(s *godog.Suite) { + s.Step(`^a public key address$`, aPublicKeyAddress) + s.Step(`^a user creates a group with that address$`, aUserCreatesAGroupWithThatAddress) + s.Step(`^a decision threshold of (\d+)$`, aDecisionThresholdOf) + s.Step(`^they should get a new group address back$`, theyShouldGetANewGroupAddressBack) + s.Step(`^a group ID$`, aGroupID) + s.Step(`^a user gets the group details on the command line$`, aUserGetsTheGroupDetailsOnTheCommandLine) + s.Step(`^they should get back the group details in JSON format$`, theyShouldGetBackTheGroupDetailsInJSONFormat) +} + -- GitLab From c7d3974bc9bc2480d69aff1a11ae7607b5030ddf Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 12:31:40 -0500 Subject: [PATCH 22/41] Add test command to CI --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd1052e33..f4155a575 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,3 +2,4 @@ build: image: golang:1.11.5 script: - make install + - make test -- GitLab From 2f7130fd7cbab43c0c77629bcc86350704e368a7 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 14:50:41 -0500 Subject: [PATCH 23/41] Adding test results to CI --- .gitignore | 1 + .gitlab-ci.yml | 11 +++++++++++ x/group/group_test.go | 10 +++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 90c326000..b037af5cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +test_output.xml # Created by https://www.gitignore.io/api/go,vim,emacs,intellij # Edit at https://www.gitignore.io/?templates=go,vim,emacs,intellij diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f4155a575..6ed0ff8e2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,16 @@ +stages: + - build + - test + - build: image: golang:1.11.5 script: - make install + +test: + image: golang:1.11.5 + script: - make test + artifacts: + reports: + junit: "**/test_output.xml" diff --git a/x/group/group_test.go b/x/group/group_test.go index 634e54ee4..0540cdfcf 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -18,7 +18,15 @@ func init() { } func TestMain(m *testing.M) { - println("TEST") + ci, found := os.LookupEnv("CI") + if found && len(ci) != 0 { + f, err := os.Create("test_output.xml") + if err == nil { + opt.Output = f + opt.Format = "junit" + } + } + flag.Parse() opt.Paths = flag.Args() -- GitLab From 39f146e7412f60505726f2b3021548eee31b01a5 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 14:51:32 -0500 Subject: [PATCH 24/41] Fix CI yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6ed0ff8e2..bfdf02bf0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ stages: - build - test - - + build: image: golang:1.11.5 script: -- GitLab From 4f7fab689ae634c19e4a1395c961615d8ff76ef9 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 15:06:14 -0500 Subject: [PATCH 25/41] WIP on CI test reports [#163831108] --- x/group/group_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x/group/group_test.go b/x/group/group_test.go index 0540cdfcf..6d6d48f26 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -2,6 +2,7 @@ package group import ( "flag" + "fmt" "github.com/DATA-DOG/godog" "github.com/DATA-DOG/godog/colors" "os" @@ -18,9 +19,10 @@ func init() { } func TestMain(m *testing.M) { + const suiteName = "group" ci, found := os.LookupEnv("CI") if found && len(ci) != 0 { - f, err := os.Create("test_output.xml") + f, err := os.Create(fmt.Sprintf("%s/build/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName)) if err == nil { opt.Output = f opt.Format = "junit" @@ -68,8 +70,6 @@ func theyShouldGetBackTheGroupDetailsInJSONFormat() error { return godog.ErrPending } - - func FeatureContext(s *godog.Suite) { s.Step(`^a public key address$`, aPublicKeyAddress) s.Step(`^a user creates a group with that address$`, aUserCreatesAGroupWithThatAddress) @@ -79,4 +79,3 @@ func FeatureContext(s *godog.Suite) { s.Step(`^a user gets the group details on the command line$`, aUserGetsTheGroupDetailsOnTheCommandLine) s.Step(`^they should get back the group details in JSON format$`, theyShouldGetBackTheGroupDetailsInJSONFormat) } - -- GitLab From 5e9fb41877b173d495bcd4992c809dc2396d4b3b Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 15:07:55 -0500 Subject: [PATCH 26/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bfdf02bf0..1470bb843 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,4 +13,4 @@ test: - make test artifacts: reports: - junit: "**/test_output.xml" + junit: "build/TEST_*.xml" -- GitLab From 7b3d8a3dacbd5eb84de5b6dbafc7de7db3d46406 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 15:13:06 -0500 Subject: [PATCH 27/41] WIP on CI test reports [#163831108] --- x/group/group_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/group/group_test.go b/x/group/group_test.go index 6d6d48f26..5ca2a0fa5 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -22,6 +22,8 @@ func TestMain(m *testing.M) { const suiteName = "group" ci, found := os.LookupEnv("CI") if found && len(ci) != 0 { + println("In CI") + println(os.Getenv("CI_PROJECT_DIR")) f, err := os.Create(fmt.Sprintf("%s/build/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName)) if err == nil { opt.Output = f -- GitLab From ad08bc8b48d8cb4cb658b066001dbc2f9a226722 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 15:24:44 -0500 Subject: [PATCH 28/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 9 ++++++--- x/group/group_test.go | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1470bb843..b3002f847 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,9 @@ -stages: - - build - - test +variables: + GOPATH: .go + +cache: + paths: + .go/pkg/mod build: image: golang:1.11.5 diff --git a/x/group/group_test.go b/x/group/group_test.go index 5ca2a0fa5..48db8c635 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -23,9 +23,12 @@ func TestMain(m *testing.M) { ci, found := os.LookupEnv("CI") if found && len(ci) != 0 { println("In CI") - println(os.Getenv("CI_PROJECT_DIR")) - f, err := os.Create(fmt.Sprintf("%s/build/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName)) - if err == nil { + testfileName := fmt.Sprintf("%s/build/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName) + println(os.Getenv(testfileName)) + f, err := os.Create(testfileName) + if err != nil { + fmt.Printf("Error creating test output file: %+v", err) + } else { opt.Output = f opt.Format = "junit" } -- GitLab From 768dd93fa77291d036822e1e0dc26beabb8c6fff Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 15:25:13 -0500 Subject: [PATCH 29/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b3002f847..d22616194 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,7 @@ variables: cache: paths: - .go/pkg/mod + - .go/pkg/mod build: image: golang:1.11.5 -- GitLab From b90830a989a4e9fda08aaab4159901ed6504a37a Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 15:27:42 -0500 Subject: [PATCH 30/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d22616194..e4da65e7f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - GOPATH: .go + GOPATH: "$CI_PROJECT_DIR/.go" cache: paths: -- GitLab From df09ab1bb525f9418ef5ca87e1f34e8eafd5f77e Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 15:31:46 -0500 Subject: [PATCH 31/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 2 +- x/group/group_test.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e4da65e7f..ad3f8269f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,4 +16,4 @@ test: - make test artifacts: reports: - junit: "build/TEST_*.xml" + junit: "TEST_*.xml" diff --git a/x/group/group_test.go b/x/group/group_test.go index 48db8c635..831aaa66c 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -23,11 +23,10 @@ func TestMain(m *testing.M) { ci, found := os.LookupEnv("CI") if found && len(ci) != 0 { println("In CI") - testfileName := fmt.Sprintf("%s/build/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName) - println(os.Getenv(testfileName)) + testfileName := fmt.Sprintf("%s/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName) f, err := os.Create(testfileName) if err != nil { - fmt.Printf("Error creating test output file: %+v", err) + fmt.Printf("Error creating test output file %s: %+v", testfileName, err) } else { opt.Output = f opt.Format = "junit" -- GitLab From 5e62433d2f1ec9bbe2f8df5b32b720d644cd8551 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:08:17 -0500 Subject: [PATCH 32/41] Update to fork of godog --- .gitlab-ci.yml | 5 ++ Makefile | 5 +- go.mod | 12 +++-- go.sum | 117 ++++++++++++++++++++++++++++++++++++++++++ x/group/group_test.go | 1 - 5 files changed, 133 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ad3f8269f..8113b3b31 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,3 +17,8 @@ test: artifacts: reports: junit: "TEST_*.xml" + +lint: + image: golang:1.11.5 + script: + - make lint diff --git a/Makefile b/Makefile index 9b9dcd968..eb28f2d92 100644 --- a/Makefile +++ b/Makefile @@ -5,4 +5,7 @@ install: go install ./cmd/xrncli test: - go test ./... -godog.strict \ No newline at end of file + go test ./... -godog.strict + +lint: + golint ./... diff --git a/go.mod b/go.mod index 9270f8eac..8c2c002b1 100644 --- a/go.mod +++ b/go.mod @@ -54,15 +54,17 @@ require ( github.com/tendermint/tendermint v0.29.1 github.com/twpayne/go-geom v1.0.4 github.com/zondax/ledger-cosmos-go v0.9.2 - golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44 - golang.org/x/net v0.0.0-20181106065722-10aee1819953 + golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 + golang.org/x/net v0.0.0-20190213061140-3a22650c66bd golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 - golang.org/x/text v0.3.0 - google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898 - google.golang.org/grpc v1.16.0 + golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 + google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 + google.golang.org/grpc v1.17.0 gopkg.in/yaml.v2 v2.2.2 ) replace golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5 replace github.com/cosmos/cosmos-sdk => github.com/regen-network/cosmos-sdk v0.19.1-0.20190129211355-6e1f27eea179 // indirect + +replace github.com/DATA-DOG/godog => github.com/regen-network/godog v0.0.0-0.20190215155814-31cb7bc0e9a6bdc4c3116e54eecbc6ce453d9a2b diff --git a/go.sum b/go.sum index 747373489..895297b0c 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,26 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DATA-DOG/go-txdb v0.1.2/go.mod h1:aDC9AAfOY+kLbhVTKKXOwkqr2844my+djxj+Ou4wNb4= github.com/DATA-DOG/godog v0.7.10 h1:BRaQdCOsFth//Ep/J6gtb3xOeDh+sAVjL44ZdK1E9aI= github.com/DATA-DOG/godog v0.7.10/go.mod h1:z2OZ6a3X0/YAKVqLfVzYBwFt3j6uSt3Xrqa7XTtcQE0= github.com/ZondaX/hid-go v0.4.0/go.mod h1:eaChKpVjUVdM78f1sM/TSFedameXSbNXGiLNvl6sKsA= github.com/ZondaX/ledger-go v0.4.0/go.mod h1:9Q7YMPYFR7tKocUfb8layi5V2tLqZbMs3q0ArLGDFWw= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/btcsuite/btcd v0.0.0-20181130015935-7d2daa5bfef2 h1:LPHpTTuR7vj3kD7YDRZnrDnFAoj1Ov4cpiO3jN8RnW4= github.com/btcsuite/btcd v0.0.0-20181130015935-7d2daa5bfef2/go.mod h1:Jr9bmNVGZ7TH2Ux1QuP0ec+yGgh0gE9FIlkzQiI5bR0= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= @@ -22,6 +33,7 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cosmos/cosmos-sdk v0.0.0-20190110184329-915ef12facc9/go.mod h1:JrX/JpJunJQXBI5PEX2zELHMFzQr/159jDjIhesOh2c= github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI= github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= @@ -29,12 +41,17 @@ github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkE github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-kit/kit v0.6.0 h1:wTifptAGIyIuir4bRyN4h7+kAa2a4eepLYVmRe5qqQ8= github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo= @@ -42,25 +59,43 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmhodges/levigo v0.0.0-20161115193449-c42d9e0ca023/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -68,20 +103,27 @@ github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1 h1:K47Rk0v/fkEfwfQet2KWhscE0cJzjgCCDBG2KHZoVno= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181129180645-aa55a523dc0a h1:Z2GBQ7wAiTCixJhSGK4sMO/FHYlvFvUBBK0M0FSsxeU= github.com/prometheus/procfs v0.0.0-20181129180645-aa55a523dc0a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rakyll/statik v0.1.4 h1:zCS/YQCxfo/fQjCtGVGIyWGFnRbQ18Y55mhS3XPE+Oo= @@ -95,8 +137,38 @@ github.com/regen-network/cosmos-sdk v0.19.1-0.20190129210756-64554b6839f2/go.mod github.com/regen-network/cosmos-sdk v0.19.1-0.20190129211355-6e1f27eea179 h1:YQCak8qFbbv+qgAe4nfJpzevQBwC4hRU/gmMDC5D1c0= github.com/regen-network/cosmos-sdk v0.19.1-0.20190129211355-6e1f27eea179/go.mod h1:NlvB7hxh2AcqplzmTCqBuuRDIb0qYqRo/e/f+0e7BhE= github.com/regen-network/cosmos-sdk v0.25.0 h1:kN3AldBj2T7iFAbuVAWp0gUoT+LkSoWoPNFec3EWXxo= +github.com/regen-network/godog v0.0.0-0.20190129211355-31cb7bc0e9a6bdc4c3116e54eecbc6ce453d9a2b h1:ooHtFX8t08wbC3MoR6wWNC+uwJ9lv1ExrIvcNPtxKvs= +github.com/regen-network/godog v0.0.0-0.20190129211355-31cb7bc0e9a6bdc4c3116e54eecbc6ce453d9a2b/go.mod h1:tZx0qfvDOzsmFkvWYZI/JNPPqQb77S76qZKwH31KQl0= +github.com/regen-network/godog v0.0.0-0.20190215155814-31cb7bc0e9a6bdc4c3116e54eecbc6ce453d9a2b h1:6/0kKxUPEwmwC6nPN8oq+9idO3ll5kzhqoqukdvAGTs= +github.com/regen-network/godog v0.0.0-0.20190215155814-31cb7bc0e9a6bdc4c3116e54eecbc6ce453d9a2b/go.mod h1:tZx0qfvDOzsmFkvWYZI/JNPPqQb77S76qZKwH31KQl0= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= @@ -114,6 +186,7 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2 h1:GnOzE5fEFN3b2zDhJJABEofdb51uMRNb8eqIVtdducs= github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tendermint/btcd v0.0.0-20180816174608-e5840949ff4f h1:R0wLxgASGMoRQTF/dCSk4N+M3j9DLyPDzDff2WtCg/I= github.com/tendermint/btcd v0.0.0-20180816174608-e5840949ff4f/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5 h1:u8i49c+BxloX3XQ55cvzFNXplizZP/q00i+IlttUjAU= @@ -133,28 +206,72 @@ github.com/twpayne/go-geom v1.0.4/go.mod h1:Xt2LAX0JiP94UWCnKKpDtx/d5g94AQNOCbms github.com/twpayne/go-kml v1.0.0/go.mod h1:LlvLIQSfMqYk2O7Nx8vYAbSLv4K9rjMvLlEdUKWdjq0= github.com/twpayne/go-polyline v1.0.0/go.mod h1:ICh24bcLYBX8CknfvNPKqoTbe+eg+MX1NPyJmSBo7pU= github.com/zondax/ledger-cosmos-go v0.9.2/go.mod h1:uhu/ldrtzhUH7RoWoTKK4MxBi/CXfyViVA0OCYTiHdM= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 h1:rJm0LuqUjoDhSk2zO9ISMSToQxGz7Os2jRiOL8AWu4c= +golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180710023853-292b43bbf7cb/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953 h1:LuZIitY8waaxUfNIdtajyE/YzA/zyf0YxXG27VpLrkg= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU= golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 h1:JG/0uqcGdTNgq7FdU+61l5Pdmb8putNZlXb65bJBROs= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190214204934-8dcb7bc8c7fe/go.mod h1:E6PF97AdD6v0s+fPshSmumCW1S1Ne85RbPQxELkKa44= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898 h1:yvw+zsSmSM02Z5H3ZdEV7B7Ql7eFrjQTnmByJvK+3J8= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 h1:mBVYJnbrXLA/ZCBTCe7PtEgAUP+1bg92qTaFoPHdz+8= +google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0 h1:dz5IJGuC2BB7qXR5AyHNwAUBhZscK2xVez7mznh72sY= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/x/group/group_test.go b/x/group/group_test.go index 831aaa66c..32838983e 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -22,7 +22,6 @@ func TestMain(m *testing.M) { const suiteName = "group" ci, found := os.LookupEnv("CI") if found && len(ci) != 0 { - println("In CI") testfileName := fmt.Sprintf("%s/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName) f, err := os.Create(testfileName) if err != nil { -- GitLab From a2004bf0180553456d7e34fe8f0232a336ea0a12 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:16:44 -0500 Subject: [PATCH 33/41] Install golint in Makefile --- Makefile | 1 + go.sum | 1 + 2 files changed, 2 insertions(+) diff --git a/Makefile b/Makefile index eb28f2d92..36f3ccbba 100644 --- a/Makefile +++ b/Makefile @@ -8,4 +8,5 @@ test: go test ./... -godog.strict lint: + @[ -x $(which golint) ] || go get -u golang.org/x/lint/golint golint ./... diff --git a/go.sum b/go.sum index 895297b0c..899d671a5 100644 --- a/go.sum +++ b/go.sum @@ -244,6 +244,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 h1:JG/0uqcGdTNgq7FdU+61l5Pdmb8putNZlXb65bJBROs= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190214204934-8dcb7bc8c7fe h1:oou9Na+8DBZO/hrVPAjBTaHXmuDq0284mwGwfmQ4ids= golang.org/x/tools v0.0.0-20190214204934-8dcb7bc8c7fe/go.mod h1:E6PF97AdD6v0s+fPshSmumCW1S1Ne85RbPQxELkKa44= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -- GitLab From 2f7641339a857377b9ed53afa8cb083be28a18a0 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:21:07 -0500 Subject: [PATCH 34/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8113b3b31..65f603e34 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,6 @@ variables: GOPATH: "$CI_PROJECT_DIR/.go" + PATH: "$PATH:$GOPATH/bin" cache: paths: -- GitLab From 1367700e379e98b78b0c148402b4cbd7964f9462 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:23:27 -0500 Subject: [PATCH 35/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 65f603e34..b0f7b4877 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,5 @@ variables: GOPATH: "$CI_PROJECT_DIR/.go" - PATH: "$PATH:$GOPATH/bin" cache: paths: @@ -22,4 +21,5 @@ test: lint: image: golang:1.11.5 script: + - export PATH=$PATH:$GOPATH/bin - make lint -- GitLab From e8a91cddf8ee7b52ab5b713e2a924eae38f73099 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:27:16 -0500 Subject: [PATCH 36/41] WIP on CI test reports [#163831108] --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 36f3ccbba..cc460cfd4 100644 --- a/Makefile +++ b/Makefile @@ -8,5 +8,5 @@ test: go test ./... -godog.strict lint: - @[ -x $(which golint) ] || go get -u golang.org/x/lint/golint + [ -x $(which golint) ] || go get -u golang.org/x/lint/golint golint ./... -- GitLab From c93275ae43f93f869a62fde6b5f0488bae551708 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:44:26 -0500 Subject: [PATCH 37/41] WIP on CI test reports [#163831108] --- .gitlab-ci.yml | 1 - Makefile | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b0f7b4877..8113b3b31 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,5 +21,4 @@ test: lint: image: golang:1.11.5 script: - - export PATH=$PATH:$GOPATH/bin - make lint diff --git a/Makefile b/Makefile index cc460cfd4..e644e7c10 100644 --- a/Makefile +++ b/Makefile @@ -8,5 +8,5 @@ test: go test ./... -godog.strict lint: - [ -x $(which golint) ] || go get -u golang.org/x/lint/golint - golint ./... + go get -u golang.org/x/lint/golint + ${GOPATH}/bin/golint ./... -- GitLab From f4267a1a453cd0def775aef19dc8742fc512f26d Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:49:35 -0500 Subject: [PATCH 38/41] WIP on CI test reports [#163831108] --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e644e7c10..8ba80d807 100644 --- a/Makefile +++ b/Makefile @@ -9,4 +9,4 @@ test: lint: go get -u golang.org/x/lint/golint - ${GOPATH}/bin/golint ./... + ${GOPATH}/bin/golint -set_exit_status ./... -- GitLab From 2b1fa275ac77626f319d80bb396e19f88b1f0706 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 15 Feb 2019 16:53:47 -0500 Subject: [PATCH 39/41] Disabling Junit reporting because Gitlab isn't reporting useful results. https://gitlab.com/gitlab-org/gitlab-ce/issues/50964 may be related [delivers #163831108] --- x/group/group_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/group/group_test.go b/x/group/group_test.go index 32838983e..d16203576 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -19,7 +19,7 @@ func init() { } func TestMain(m *testing.M) { - const suiteName = "group" + /*const suiteName = "group" ci, found := os.LookupEnv("CI") if found && len(ci) != 0 { testfileName := fmt.Sprintf("%s/TEST_%s.xml", os.Getenv("CI_PROJECT_DIR"), suiteName) @@ -30,7 +30,7 @@ func TestMain(m *testing.M) { opt.Output = f opt.Format = "junit" } - } + }*/ flag.Parse() opt.Paths = flag.Args() -- GitLab From 36ef5bb11c06ab61ce0efb6bb515472d18191202 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 18 Feb 2019 09:20:57 -0500 Subject: [PATCH 40/41] Fix imports --- go.mod | 2 +- x/group/group_test.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 8c2c002b1..c4d628178 100644 --- a/go.mod +++ b/go.mod @@ -67,4 +67,4 @@ replace golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-2018082004570 replace github.com/cosmos/cosmos-sdk => github.com/regen-network/cosmos-sdk v0.19.1-0.20190129211355-6e1f27eea179 // indirect -replace github.com/DATA-DOG/godog => github.com/regen-network/godog v0.0.0-0.20190215155814-31cb7bc0e9a6bdc4c3116e54eecbc6ce453d9a2b +// replace github.com/DATA-DOG/godog => github.com/regen-network/godog v0.0.0-0.20190215155814-31cb7bc0e9a6bdc4c3116e54eecbc6ce453d9a2b diff --git a/x/group/group_test.go b/x/group/group_test.go index d16203576..c4b5fa947 100644 --- a/x/group/group_test.go +++ b/x/group/group_test.go @@ -2,7 +2,6 @@ package group import ( "flag" - "fmt" "github.com/DATA-DOG/godog" "github.com/DATA-DOG/godog/colors" "os" -- GitLab From efa6ff594d888f8d2e30b4a60e762bee24dfd910 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 18 Feb 2019 09:23:04 -0500 Subject: [PATCH 41/41] Move all group stuff back to agent so we can refactor gracefully --- x/agent/README.org | 43 ++++-- x/{group => agent}/features/create.feature | 0 x/{group => agent}/features/get.feature | 0 x/{group => agent}/group_test.go | 2 +- x/group/README.org | 105 -------------- x/group/client/cli/tx.go | 85 ------------ x/group/client/module_client.go | 47 ------- x/group/codec.go | 10 -- x/group/handler.go | 37 ----- x/group/keeper.go | 153 --------------------- x/group/msgs.go | 79 ----------- x/group/querier.go | 46 ------- x/group/types.go | 26 ---- 13 files changed, 32 insertions(+), 601 deletions(-) rename x/{group => agent}/features/create.feature (100%) rename x/{group => agent}/features/get.feature (100%) rename x/{group => agent}/group_test.go (99%) delete mode 100644 x/group/README.org delete mode 100644 x/group/client/cli/tx.go delete mode 100644 x/group/client/module_client.go delete mode 100644 x/group/codec.go delete mode 100644 x/group/handler.go delete mode 100644 x/group/keeper.go delete mode 100644 x/group/msgs.go delete mode 100644 x/group/querier.go delete mode 100644 x/group/types.go diff --git a/x/agent/README.org b/x/agent/README.org index 07dd802c8..e50de976b 100644 --- a/x/agent/README.org +++ b/x/agent/README.org @@ -1,8 +1,10 @@ #+TITLE: Group Module +*STATUS: In Process* (out of sync with implementation) + #+BEGIN_SRC go :tangle types.go :exports none // GENERATED FROM README.org // DO NOT EDIT THIS FILE DIRECTLY!!!!! - package data + package group import ( sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,7 +13,7 @@ * Overview - The group module provides a mechanism that can be used to support basic multi-party organizations and to allow individuals to authorize their own transactions via multiple keys on different devices (key groups). In the future, it may be extended to support more sophisticated multi-party authorization schemes. + A ~Group~ is an aggregation of Regen Ledger addresses - which themselves can be individual keys, other groups, or contracts - each with an associated voting ~Weight~ and a ~DecisionThreshold~. This allows for specifying on-chain organizations as well as arbitrary groups of keys that have a governance structure that includes simple majority, super-majority, minority approval, and weighted ownership. In the future, it may be extended to support more sophisticated multi-party authorization schemes. * Motivation There are a number of scenarios where we want to model a group or organization concept on the blockchain. Here are some hypothesized groups that this module should serve: @@ -32,26 +34,28 @@ // It could be used to group individuals into a group or several groups/users into a larger group. // It could be used by a single user to manage multiple devices and setup a multisig policy. type Group struct { - // The members of the group and their associated power + // The members of the group and their associated weight Members []Member `json:"addresses,omitempty"` // Specifies the number of votes that must be accumulated in order for a decision to be made by the group. - // A member gets as many votes as is indicated by their Power field. + // A member gets as many votes as is indicated by their Weight field. // A big integer is used here to avoid any potential vulnerabilities from overflow errors - // where large power and threshold values are used. - Threshold big.Int `json:"threshold"` + // where large weight and threshold values are used. + DecisionThreshold big.Int `json:"decision_threshold"` // TODO maybe make this something more specific to a domain name or a claim on identity? or Memo leave it generic Memo string `json:"memo,omitempty"` } -// A member specifies a address and a power for a group member +// A member specifies a address and a weight for a group member type Member struct { // The address of a group member. Can be another group or a contract Address sdk.AccAddress `json:"address"` - // The integral power of this member with respect to other members and the decision threshold - Power big.Int `json:"power,omitempty"` + // The integral weight of this member with respect to other members and the decision threshold + Weight big.Int `json:"weight,omitempty"` } #+END_SRC go ** ~MsgCreateAgent~ + + /[[./features/create.feature][Test spec]]/ #+BEGIN_SRC go :tangle types.go // Creates a group on the blockchain @@ -60,7 +64,16 @@ type MsgCreateGroup struct { Data Group `json:"data"` Signer sdk.AccAddress `json:"signer"` } -#+END_SRC go +#+END_SRC + +#+BEGIN_SRC gherkin :tangle features/create.features +Feature: Create group + Scenario: Create a group from a single key + Given a public key address + When a user creates a group with that address + And a decision threshold of 1 + Then they should get a new group address back +#+END_SRC *** TODO transaction fee * Identifiers @@ -68,6 +81,9 @@ type MsgCreateGroup struct { * Indexing and Queries ** ~get~ + + /[[./features/get.feature][Test spec]]/ + The ~get~ query command should take the group address as a single parameter retrieve the current ~Group~ struct (as JSON) associated with that address ** Postgresql Groups and their members should be indexed to the tables below which should allow members to look up any groups they are directly or transitively part of: @@ -81,6 +97,9 @@ type MsgCreateGroup struct { CREATE TABLE group_member ( group text NOT NULL REFERENCES group, address text NOT NULL, - power NUMERIC NOT NULL + weight NUMERIC NOT NULL ) -#+END_SRC go +#+END_SRC + +* Rationale + Groups are designed with a simple weight/threshold voting mechanism. Other voting mechanisms could be added to the ~Group~ type in the future, but for now this simple mechanism is theorized to be sufficient for most of our immediate use cases. To begin with ~DecisionThreshold~ allows for any sort of majority of super-majority voting system where all members have equal weight. It also allows for minority voting systems where say we are managing our own keys and have several devices but only need say two at a time to approve a transaction. The addition of the ~Weight~ parameter for each member allows for managing voting scenarios where weight is distributed unequally - say in ownership shares of a company. So if persons A, B, and C each had 1000 shares and person D had 2000 shares, we could set their ~Weight~'s to their share count and ~DecisionThreshold~ to 2501 for simply majority approval. Many other governance mechanisms that are more complex could actually be handled by nesting groups with different responsibilities. For instance say we had a reporter/approver approval mechanism for an ESP report. We could have a group of reporters in a group with equal weight and ~DecisionThreshold~ 1, and a similar group for approvers, and then join them into a reporter/approver group where the reporter group and approver group are each members with ~Weight~ 1 and ~DecisionThreshold~ 2. This arrangements specifies that we need one reporter and one approver to sign off on a report. While there are scenarios that definitely can't be handled with this type of governance definition, there are a surprisingly large number that can and so our hypothesis is that this is sufficient to start until more scenarios are encountered. diff --git a/x/group/features/create.feature b/x/agent/features/create.feature similarity index 100% rename from x/group/features/create.feature rename to x/agent/features/create.feature diff --git a/x/group/features/get.feature b/x/agent/features/get.feature similarity index 100% rename from x/group/features/get.feature rename to x/agent/features/get.feature diff --git a/x/group/group_test.go b/x/agent/group_test.go similarity index 99% rename from x/group/group_test.go rename to x/agent/group_test.go index c4b5fa947..4361b20c0 100644 --- a/x/group/group_test.go +++ b/x/agent/group_test.go @@ -1,4 +1,4 @@ -package group +package agent import ( "flag" diff --git a/x/group/README.org b/x/group/README.org deleted file mode 100644 index e50de976b..000000000 --- a/x/group/README.org +++ /dev/null @@ -1,105 +0,0 @@ -#+TITLE: Group Module -*STATUS: In Process* (out of sync with implementation) - -#+BEGIN_SRC go :tangle types.go :exports none - // GENERATED FROM README.org - // DO NOT EDIT THIS FILE DIRECTLY!!!!! - package group - - import ( - sdk "github.com/cosmos/cosmos-sdk/types" - ) -#+END_SRC - -* Overview - - A ~Group~ is an aggregation of Regen Ledger addresses - which themselves can be individual keys, other groups, or contracts - each with an associated voting ~Weight~ and a ~DecisionThreshold~. This allows for specifying on-chain organizations as well as arbitrary groups of keys that have a governance structure that includes simple majority, super-majority, minority approval, and weighted ownership. In the future, it may be extended to support more sophisticated multi-party authorization schemes. - -* Motivation - There are a number of scenarios where we want to model a group or organization concept on the blockchain. Here are some hypothesized groups that this module should serve: - -** Regen Consortium and its member organizations - The Regen Consortium is intended to be the group of organizations that govern the Regen Ledger blockchain. They get to choose the validator set, decide on major upgrades to the blockchain as well as a number of parameters like transaction fees. Each consortium member itself must be an organization that likely has its own decision making policy. - -** Protocol and Contract Curators - Ecological state protocols (ESPs) and contracts (ECs) have been theorized to specify some organization or group that "curates" them. Curation has a number of different benefits and responsibilities. ESP curators have the responsibility of upgrading the protocols over time and may also receive curator fees when ESPs are run. EC curators may also receive a fee and/or be required to intervene to arbitrate terms of a contract. - -** Verifiers - It is hypothesized that verifiers may likely be multi-party organizations that have their own governance protocol for approving verification claims. - -* Transaction Messages and Types -** Basic Types -#+BEGIN_SRC go :tangle types.go -// A group can be used to abstract over users and groups. -// It could be used to group individuals into a group or several groups/users into a larger group. -// It could be used by a single user to manage multiple devices and setup a multisig policy. -type Group struct { - // The members of the group and their associated weight - Members []Member `json:"addresses,omitempty"` - // Specifies the number of votes that must be accumulated in order for a decision to be made by the group. - // A member gets as many votes as is indicated by their Weight field. - // A big integer is used here to avoid any potential vulnerabilities from overflow errors - // where large weight and threshold values are used. - DecisionThreshold big.Int `json:"decision_threshold"` - // TODO maybe make this something more specific to a domain name or a claim on identity? or Memo leave it generic - Memo string `json:"memo,omitempty"` -} - -// A member specifies a address and a weight for a group member -type Member struct { - // The address of a group member. Can be another group or a contract - Address sdk.AccAddress `json:"address"` - // The integral weight of this member with respect to other members and the decision threshold - Weight big.Int `json:"weight,omitempty"` -} -#+END_SRC go -** ~MsgCreateAgent~ - - /[[./features/create.feature][Test spec]]/ - -#+BEGIN_SRC go :tangle types.go -// Creates a group on the blockchain -// Should return a tag "group.id" with the bech32 address of the group -type MsgCreateGroup struct { - Data Group `json:"data"` - Signer sdk.AccAddress `json:"signer"` -} -#+END_SRC - -#+BEGIN_SRC gherkin :tangle features/create.features -Feature: Create group - Scenario: Create a group from a single key - Given a public key address - When a user creates a group with that address - And a decision threshold of 1 - Then they should get a new group address back -#+END_SRC -*** TODO transaction fee - -* Identifiers - Groups implement the ~Account~ interface and thus have an ~AccAddress~. Internally an group ID is an ~uint64~ which is assigned on an auto-increment basis. The ~AccAddress~ for an group is made by concatenating the prefix ~G~ (as ~[]byte~) and the [[https://golang.org/pkg/encoding/binary/#PutUvarint][varint]] encoding of the ~uint64~ account ID. The textual representation of an group account is obtained by taking the bech32 encoding of this ~AccAddress~ with the prefix ~xrn:~ which also is a valid URI. - -* Indexing and Queries -** ~get~ - - /[[./features/get.feature][Test spec]]/ - - The ~get~ query command should take the group address as a single parameter retrieve the current ~Group~ struct (as JSON) associated with that address -** Postgresql - Groups and their members should be indexed to the tables below which should allow members to look up any groups they are directly or transitively part of: - -#+BEGIN_SRC sql :tangle group.sql - CREATE TABLE group ( - address text NOT NULL PRIMARY KEY, - threshold NUMERIC NOT NULL - ); - - CREATE TABLE group_member ( - group text NOT NULL REFERENCES group, - address text NOT NULL, - weight NUMERIC NOT NULL - ) -#+END_SRC - -* Rationale - Groups are designed with a simple weight/threshold voting mechanism. Other voting mechanisms could be added to the ~Group~ type in the future, but for now this simple mechanism is theorized to be sufficient for most of our immediate use cases. To begin with ~DecisionThreshold~ allows for any sort of majority of super-majority voting system where all members have equal weight. It also allows for minority voting systems where say we are managing our own keys and have several devices but only need say two at a time to approve a transaction. The addition of the ~Weight~ parameter for each member allows for managing voting scenarios where weight is distributed unequally - say in ownership shares of a company. So if persons A, B, and C each had 1000 shares and person D had 2000 shares, we could set their ~Weight~'s to their share count and ~DecisionThreshold~ to 2501 for simply majority approval. Many other governance mechanisms that are more complex could actually be handled by nesting groups with different responsibilities. For instance say we had a reporter/approver approval mechanism for an ESP report. We could have a group of reporters in a group with equal weight and ~DecisionThreshold~ 1, and a similar group for approvers, and then join them into a reporter/approver group where the reporter group and approver group are each members with ~Weight~ 1 and ~DecisionThreshold~ 2. This arrangements specifies that we need one reporter and one approver to sign off on a report. While there are scenarios that definitely can't be handled with this type of governance definition, there are a surprisingly large number that can and so our hypothesis is that this is sufficient to start until more scenarios are encountered. diff --git a/x/group/client/cli/tx.go b/x/group/client/cli/tx.go deleted file mode 100644 index 23b5d1ee3..000000000 --- a/x/group/client/cli/tx.go +++ /dev/null @@ -1,85 +0,0 @@ -package cli - -import ( - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/utils" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" - "github.com/spf13/cobra" - utils2 "gitlab.com/regen-network/regen-ledger/utils" - "gitlab.com/regen-network/regen-ledger/x/agent" -) - -func addrsFromBech32Array(arr []string) []sdk.AccAddress { - n := len(arr) - res := make([]sdk.AccAddress, n) - for i := 0; i < n; i++ { - str := arr[i] - acc, err := sdk.AccAddressFromBech32(str) - if err != nil { - panic(err) - } - res[i] = acc - } - return res -} - -func AgentsFromArray(arr []string) []agent.AgentID { - n := len(arr) - res := make([]agent.AgentID, n) - for i := 0; i < n; i++ { - res[i] = agent.MustDecodeBech32AgentID(arr[i]) - } - return res -} - -func GetCmdCreateAgent(cdc *codec.Codec) *cobra.Command { - var threshold int - var addrs []string - var agents []string - - cmd := &cobra.Command{ - Use: "create", - Short: "create an agent", - //Args: cobra.MinimumNArgs(1), - PreRun: func(cmd *cobra.Command, args []string) { - - }, - RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(cdc) - - txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) - - if err := cliCtx.EnsureAccountExists(); err != nil { - return err - } - - account := cliCtx.GetFromAddress() - - info := agent.AgentInfo{ - AuthPolicy: agent.MultiSig, - MultisigThreshold: threshold, - Addresses: addrsFromBech32Array(addrs), - Agents: AgentsFromArray(agents), - } - - msg := agent.NewMsgCreateAgent(info, account) - err := msg.ValidateBasic() - if err != nil { - return err - } - - cliCtx.PrintResponse = true - cliCtx.ResponseHandler = utils2.PrintCLIResponse_StringData - - return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg}) - }, - } - - cmd.Flags().IntVar(&threshold, "threshold", 0, "Multisig threshold") - cmd.Flags().StringArrayVar(&addrs, "addrs", []string{}, "Address") - cmd.Flags().StringArrayVar(&agents, "agents", []string{}, "Agents") - - return cmd -} diff --git a/x/group/client/module_client.go b/x/group/client/module_client.go deleted file mode 100644 index 00dcb10cd..000000000 --- a/x/group/client/module_client.go +++ /dev/null @@ -1,47 +0,0 @@ -package client - -import ( - "github.com/cosmos/cosmos-sdk/client" - "github.com/spf13/cobra" - "github.com/tendermint/go-amino" - agentcmd "gitlab.com/regen-network/regen-ledger/x/agent/client/cli" -) - -// ModuleClient exports all client functionality from this module -type ModuleClient struct { - storeKey string - cdc *amino.Codec -} - -func NewModuleClient(storeKey string, cdc *amino.Codec) ModuleClient { - return ModuleClient{storeKey, cdc} -} - -// GetQueryCmd returns the cli query commands for this module -func (mc ModuleClient) GetQueryCmd() *cobra.Command { - agentQueryCmd := &cobra.Command{ - Use: "agent", - Short: "Querying commands for the agent module", - } - - //dataQueryCmd.AddCommand(client.GetCommands( - // datacmd.GetCmdGetData(mc.storeKey, mc.cdc), - //)...) - - return agentQueryCmd -} - -// GetTxCmd returns the transaction commands for this module -func (mc ModuleClient) GetTxCmd() *cobra.Command { - agentTxCmd := &cobra.Command{ - Use: "agent", - Short: "Agent transactions subcommands", - } - - agentTxCmd.AddCommand(client.PostCommands( - agentcmd.GetCmdCreateAgent(mc.cdc), - )...) - - return agentTxCmd -} - diff --git a/x/group/codec.go b/x/group/codec.go deleted file mode 100644 index 94e14ec54..000000000 --- a/x/group/codec.go +++ /dev/null @@ -1,10 +0,0 @@ -package group - -import "github.com/cosmos/cosmos-sdk/codec" - - -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgCreateAgent{}, "agent/MsgCreateAgent", nil) - cdc.RegisterConcrete(MsgUpdateAgent{}, "agent/MsgUpdateAgent", nil) - cdc.RegisterConcrete(AgentInfo{}, "agent/AgentInfo", nil) -} diff --git a/x/group/handler.go b/x/group/handler.go deleted file mode 100644 index 277cf501d..000000000 --- a/x/group/handler.go +++ /dev/null @@ -1,37 +0,0 @@ -package group - -import ( -"fmt" - -sdk "github.com/cosmos/cosmos-sdk/types" -) - -// NewHandler returns a handler for "data" type messages. -func NewHandler(keeper Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - switch msg := msg.(type) { - case MsgCreateAgent: - return handleMsgCreateAgent(ctx, keeper, msg) - case MsgUpdateAgent: - return handleMsgUpdateAgent(ctx, keeper, msg) - default: - errMsg := fmt.Sprintf("Unrecognized data Msg type: %v", msg.Type()) - return sdk.ErrUnknownRequest(errMsg).Result() - } - } -} - - -func handleMsgCreateAgent(ctx sdk.Context, keeper Keeper, msg MsgCreateAgent) sdk.Result { - id := keeper.CreateAgent(ctx, msg.Data) - return sdk.Result{ - Tags: sdk.NewTags("agent.id", []byte(MustEncodeBech32AgentID(id))), - } -} - -func handleMsgUpdateAgent(ctx sdk.Context, keeper Keeper, msg MsgUpdateAgent) sdk.Result { - keeper.UpdateAgentInfo(ctx, msg.Id, msg.Signers, msg.Data) - return sdk.Result{ - Tags: sdk.NewTags("agent.id", []byte(MustEncodeBech32AgentID(msg.Id))), - } -} diff --git a/x/group/keeper.go b/x/group/keeper.go deleted file mode 100644 index 0d1b06375..000000000 --- a/x/group/keeper.go +++ /dev/null @@ -1,153 +0,0 @@ -package group - -import ( - "bytes" - "encoding/binary" - "fmt" - "github.com/cosmos/cosmos-sdk/codec" - "gitlab.com/regen-network/regen-ledger/utils" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type Keeper struct { - agentStoreKey sdk.StoreKey - - cdc *codec.Codec -} - -func NewKeeper(agentStoreKey sdk.StoreKey, cdc *codec.Codec) Keeper { - return Keeper{ - agentStoreKey: agentStoreKey, - cdc: cdc, - } -} - -var ( - keyNewAgentID = []byte("newAgentID") -) - -func keyAgentID(id AgentID) []byte { - return []byte(fmt.Sprintf("#%d", id)) -} - -func (keeper Keeper) GetAgentInfo(ctx sdk.Context, id AgentID) (info AgentInfo, err sdk.Error) { - store := ctx.KVStore(keeper.agentStoreKey) - bz := store.Get(keyAgentID(id)) - if bz == nil { - return info, sdk.ErrUnknownRequest("Not found") - } - info = AgentInfo{} - marshalErr := keeper.cdc.UnmarshalBinaryBare(bz, &info) - if marshalErr != nil { - return info, sdk.ErrUnknownRequest(marshalErr.Error()) - } - return info, nil -} - -const ( - Bech32Prefix = "xrnagt" -) - - -func MustEncodeBech32AgentID(id AgentID) string { - buf := make([]byte, binary.MaxVarintLen64) - n := binary.PutUvarint(buf, id) - return utils.MustEncodeBech32(Bech32Prefix, buf[:n]) -} - -func MustDecodeBech32AgentID(bech string) AgentID { - var id AgentID - hrp, bz := utils.MustDecodeBech32(bech) - if hrp != Bech32Prefix { - panic(fmt.Sprintf("Bech32 AgentID must start with %s", Bech32Prefix)) - } - id, n := binary.Uvarint(bz) - if n <= 0 { - panic("Error decoding AgentID") - } - return id -} - -func (keeper Keeper) getNewAgentId(ctx sdk.Context) (agentId AgentID) { - store := ctx.KVStore(keeper.agentStoreKey) - bz := store.Get(keyNewAgentID) - if bz == nil { - agentId = 0 - } else { - keeper.cdc.MustUnmarshalBinaryBare(bz, &agentId) - } - bz = keeper.cdc.MustMarshalBinaryBare(agentId + 1) - store.Set(keyNewAgentID, bz) - return agentId -} - -func (keeper Keeper) CreateAgent(ctx sdk.Context, info AgentInfo) AgentID { - id := keeper.getNewAgentId(ctx) - keeper.setAgentInfo(ctx, id, info) - return id -} - -func (keeper Keeper) setAgentInfo(ctx sdk.Context, id AgentID, info AgentInfo) { - store := ctx.KVStore(keeper.agentStoreKey) - bz, err := keeper.cdc.MarshalBinaryBare(info) - if err != nil { - panic(err) - } - store.Set(keyAgentID(id), bz) -} - -func (keeper Keeper) UpdateAgentInfo(ctx sdk.Context, id AgentID, signers []sdk.AccAddress, info AgentInfo) bool { - if !keeper.Authorize(ctx, id, signers) { - return false - } - keeper.setAgentInfo(ctx, id, info) - return true -} - -func (keeper Keeper) Authorize(ctx sdk.Context, id AgentID, signers []sdk.AccAddress) bool { - ctx.GasMeter().ConsumeGas(10, "agent auth") - info, err := keeper.GetAgentInfo(ctx, id) - if err != nil { - return false - } - return keeper.AuthorizeAgentInfo(ctx, &info, signers) -} - -func (keeper Keeper) AuthorizeAgentInfo(ctx sdk.Context, info *AgentInfo, signers []sdk.AccAddress) bool { - if info.AuthPolicy != MultiSig { - panic("Unknown auth policy") - } - - sigCount := 0 - sigThreshold := info.MultisigThreshold - - nAddrs := len(info.Addresses) - nSigners := len(signers) - for i := 0; i < nAddrs; i++ { - addr := info.Addresses[i] - // TODO Use a hash map to optimize this - for j := 0; j < nSigners; j++ { - ctx.GasMeter().ConsumeGas(10, "check addr") - if bytes.Compare(addr, signers[j]) == 0 { - sigCount++ - if sigCount >= sigThreshold { - return true - } - break - } - } - } - - nAgents := len(info.Agents) - for i := 0; i < nAgents; i++ { - agentId := info.Agents[i] - if keeper.Authorize(ctx, agentId, signers) { - sigCount++ - if sigCount >= sigThreshold { - return true - } - } - } - return false -} diff --git a/x/group/msgs.go b/x/group/msgs.go deleted file mode 100644 index 9f739323e..000000000 --- a/x/group/msgs.go +++ /dev/null @@ -1,79 +0,0 @@ -package group - -import ( - "encoding/json" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type MsgCreateAgent struct { - Data AgentInfo `json:"data"` - Signer sdk.AccAddress `json:"signer"` -} - -type MsgUpdateAgent struct { - Id AgentID `json:"id"` - Data AgentInfo `json:"data"` - Signers []sdk.AccAddress `json:"signers"` -} - -func NewMsgCreateAgent(info AgentInfo, signer sdk.AccAddress) MsgCreateAgent { - return MsgCreateAgent{ - Data: info, - Signer:signer, - } -} - -func (msg MsgCreateAgent) Route() string { return "agent" } - -func (msg MsgCreateAgent) Type() string { return "agent.create" } - -func (info AgentInfo) ValidateBasic() sdk.Error { - if len(info.Agents) <= 0 && len(info.Addresses) <= 0 { - return sdk.ErrUnknownRequest("Agent info must reference a non-empty set of members") - } - if info.AuthPolicy != MultiSig { - return sdk.ErrUnknownRequest("Only multi-sig auth policies are currently supported") - } - if info.MultisigThreshold <= 0 { - return sdk.ErrUnknownRequest("MultisigThreshold must be a positive integer") - } - return nil -} - -func (msg MsgCreateAgent) ValidateBasic() sdk.Error { - // TODO what are valid agent ID's - return msg.Data.ValidateBasic() -} - -func (msg MsgCreateAgent) GetSignBytes() []byte { - b, err := json.Marshal(msg) - if err != nil { - panic(err) - } - return sdk.MustSortJSON(b) -} - -func (msg MsgCreateAgent) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -func (msg MsgUpdateAgent) Route() string { return "agent" } - -func (msg MsgUpdateAgent) Type() string { return "agent.update" } - -func (msg MsgUpdateAgent) ValidateBasic() sdk.Error { - return msg.Data.ValidateBasic() -} - -func (msg MsgUpdateAgent) GetSignBytes() []byte { - b, err := json.Marshal(msg) - if err != nil { - panic(err) - } - return sdk.MustSortJSON(b) -} - -func (msg MsgUpdateAgent) GetSigners() []sdk.AccAddress { - return msg.Signers -} - diff --git a/x/group/querier.go b/x/group/querier.go deleted file mode 100644 index 913eb99aa..000000000 --- a/x/group/querier.go +++ /dev/null @@ -1,46 +0,0 @@ -package group - -import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/tendermint/abci/types" - "strconv" -) - -// query endpoints supported by the governance Querier -const ( - QueryAgent = "get" -) - -func NewQuerier(keeper Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { - switch path[0] { - case QueryAgent: - return queryAgent(ctx, path[1:], req, keeper) - default: - return nil, sdk.ErrUnknownRequest("unknown data query endpoint") - } - } -} - - -func queryAgent(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { - idStr := path[0] - - id, parseErr := strconv.ParseUint(idStr, 10, 64) - if parseErr != nil { - return []byte{}, sdk.ErrUnknownRequest("Can't parse id") - } - - info, err := keeper.GetAgentInfo(ctx, AgentID(id)) - - if err != nil { - return []byte{}, sdk.ErrUnknownRequest("could not resolve id") - } - - res, jsonErr := codec.MarshalJSONIndent(keeper.cdc, info) - if jsonErr != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", jsonErr.Error())) - } - return res, nil -} diff --git a/x/group/types.go b/x/group/types.go deleted file mode 100644 index a824169aa..000000000 --- a/x/group/types.go +++ /dev/null @@ -1,26 +0,0 @@ -package group - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// TODO change to auto-increment uint64 -type AgentID = uint64 - -type AuthPolicy int - -const ( - MultiSig AuthPolicy = 0 -) - -// An agent can be used to abstract over users and groups -// It could be used by a single user to manage multiple devices and setup a multisig policy -// It could be used to group individuals into a group or several groups/users into a larger group -type AgentInfo struct { - AuthPolicy AuthPolicy `json:"auth_policy"` - // An Agent can have either addresses or other agents as members - Addresses []sdk.AccAddress `json:"addresses,omitempty"` - Agents []AgentID `json:"agents,omitempty"` - MultisigThreshold int `json:"multisig_threshold"` - Memo string `json:"memo,omitempty"` -} -- GitLab