-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Protobuf3 compatibility and repeated nulls #260
Comments
Thanks for reporting this! I always thought there must be some edge cases where amino still behaves slightly differently than protobuf. Do you mind sharing the .proto files with us? (Sounds like you’ve created some for Block and Commit?) Thanks again :) |
Thanks for the response! syntax = "proto3";
import "google/protobuf/timestamp.proto";
package proto3;
message Block {
Header header = 1;
Data data = 2;
EvidenceData evidence = 3;
Commit last_commit = 4;
}
message Header {
// basic block info
Version version = 1;
string chain_id = 2;
int64 height = 3;
google.protobuf.Timestamp time = 4;
int64 num_txs = 5;
int64 total_txs = 6;
// prev block info
BlockID last_block_id = 7;
// hashes of block data
bytes last_commit_hash = 8; // commit from validators from the last block
bytes data_hash = 9; // transactions
// hashes from the app output from the prev block
bytes validators_hash = 10; // validators for the current block
bytes next_validators_hash = 11; // validators for the next block
bytes consensus_hash = 12; // consensus params for current block
bytes app_hash = 13; // state after txs from the previous block
bytes last_results_hash = 14; // root hash of all results from the txs from the previous block
// consensus info
bytes evidence_hash = 15; // evidence included in the block
bytes proposer_address = 16; // original proposer of the block
}
message Data {
repeated bytes txs = 1;
}
message EvidenceData {
repeated Evidence evidence = 1;
bytes hash = 2;
}
message Commit {
BlockID block_id = 1;
repeated Vote precommits = 2;
} Upd: oh, I missed some structures: message Version {
uint64 block = 1;
uint64 app = 2;
}
message BlockID {
bytes hash = 1;
PartSetHeader parts = 2;
}
// From Tendermint's types.proto
message Evidence {
string type = 1;
Validator validator = 2;
int64 height = 3;
google.protobuf.Timestamp time = 4;
int64 total_voting_power = 5;
}
message Vote {
int32 type = 1; // In Go, it's a `byte`, not int32, be careful
int64 height = 2;
int32 round = 3;
BlockID block_id = 4 [json_name = "block_id"];
google.protobuf.Timestamp timestamp = 5;
bytes validator_address = 6 [json_name = "validator_address"];
int32 validator_index = 7 [json_name = "validator_index"];
bytes signature = 8;
} |
Amino allows you set a flag per field (
And thanks a lot for the protobuf files! I'm looking into encoding most/everything in tendermint using gogo/protobuf while keeping the go-structs via custom types (see: tendermint/tendermint@develop...ismail/custom_types_revival_or_not) ref: #206 |
It would be great having encoding in vanilla protobuf! It would be much easier to achieve Tendermint-compatible behaviour in other programming languages :) As a side question: Wouldn't it be better to use protobuf-generated structs where possible, or embed them in hand-written structs where additional functionality needed (i.e., mutex in And another side question: E.g. add new emptyVote := Vote {
Type: EmptyPrecommitType,
Height: 17,
Round: 0,
BlockID: ..., // real blockID
Timestamp: ...,
ValidatorAddress: validator.Address,
ValidatorIndex: validator.Index,
signature: nil,
} This way, in RPC JSON it would look like: "precommits": [
{
"type": 2,
"height": 16,
...,
"validator_address": "04C60B72246943675E2F3AADA00E30EC41AA7D4E",
"validator_index": 0,
"signature": "Z09xcrfz9T6+3q1Yk+gxUo2todPI7mebKed6zO+i1pnIMPdFbSFT9JJjxo5J9HLrn4x2Fqf3QYefQ8lQGNMzBg=="
},
{
"type": 12,
"height": 16,
...,
"validator_address": "9F16F63227F11942E6E4A3282B2A293E4BF8206C",
"validator_index": 1,
"signature": null
},
...
] Instead of current: "precommits": [
{
"type": 2,
"height": 16,
...,
"validator_address": "04C60B72246943675E2F3AADA00E30EC41AA7D4E",
"validator_index": 0,
"signature": "Z09xcrfz9T6+3q1Yk+gxUo2todPI7mebKed6zO+i1pnIMPdFbSFT9JJjxo5J9HLrn4x2Fqf3QYefQ8lQGNMzBg=="
},
null,
...
] |
That is the idea, yes.
I agree. There is some pushback by the team on this idea though. Basically due to the following reasons:
It's better to discuss this directly in the tendermint repo. I'll copy over your suggestion (which seems like a good idea on first sight). |
Just to double-check: In your example, the type in the rpc would be different, right (it currently says |
Yep, type would be |
Yep, using generated DTOs as a first-class structures sounds pretty bad... The better way would be to use protobuf-generated structs "at the end", i.e., convert first-class Go structures to protobuf-generated ones, serialize them, and then sign. This way, the signature verification would be easy to implement in any language, since you could just use existing protobuf library, and binary encoding would be the same out-of-the box. Note: That's just an idea, I may be missing some important details, and be outright wrong :) P.S.
But I'm not sure if one should worry about that in practice, maybe this never happens, or easy to work around. |
That is basically the approach I've experimented with (in the branch I've posted). But using gogo/protobuf's custom types too. I'm not sure it is the best idea.
Yeah, that is a valid concern. In practice I would not worry too much about this though. I think if you use floats or maps you will end up with different byte outputs. amino just doesn't allow those by default. I think the risk is more than manageable and even google's friends at deep mind are trying to use protobuf for hashing: https://github.com/deepmind/objecthash-proto |
ref: #212 |
Hi!
I'm trying to reproduce Amino encoding of the
Block
andCommit
structures in Scala/Java, and I found an obstacle...When
Precommits
field containsnils
s, it seems that Amino encodes anil
value as00
(along with type prefix ofc).But AFAIK in protobuf3, it's impossible to have a null as a value in repeated field.
Here's the code to show
00
:Output
The only way for me to reproduce that behaviour in Scala/Java is to patch protobuf libraries to behave against the Protobuf3 spec.
Example response from Tendermint's RPC
Block
, containing null inPrecommits
:The text was updated successfully, but these errors were encountered: