Serialization of `timestamp` field for `CommitSig::BlockIdFlagAbsent` does not match Go counterpart
romac opened this issue · 0 comments
What went wrong?
I noticed the following error when testing the light client attack evidence submission to CometBFT 0.34 and 0.37 via the /broacast_evidence
RPC endpoint from Hermes:
evidence.ValidateBasic failed: invalid conflicting light block: invalid signed header: invalid commit: wrong CommitSig #1: time is present
My investigation led me to the following problem:
CommitSig::BlockIdFlagAbsent
currently serializes to JSON as
{
"block_id_flag": 1,
"validator_address": "",
"timestamp": "1970-01-01T00:00:00Z",
"signature": ""
}
which fails the CometBFT check CommitSig.ValidateBasic()
with time is present
This check is performed as
switch cs.BlockIDFlag {
case BlockIDFlagAbsent:
if len(cs.ValidatorAddress) != 0 {
return errors.New("validator address is present")
}
if !cs.Timestamp.IsZero() {
return errors.New("time is present")
}
IsZero()
is defined as
// IsZero reports whether t represents the zero time instant, // January 1, year 1, 00:00:00 UTC.
func (t Time) IsZero() bool {
return t.sec() == 0 && t.nsec() == 0
}
From the documentation of the Time
struct, we see that it expects a
zero time to be 0001-01-01T00:00:00Z
and not 1970-01-01T00:00:00Z
:
// The zero value for a Time is defined to be
// January 1, year 1, 00:00:00.000000000 UTC
// which (1) looks like a zero, or as close as you can get in a date // (1-1-1 00:00:00 UTC), (2) is unlikely enough to arise in practice to // be a suitable "not set" sentinel, unlike Jan 1 1970, and (3) has a // non-negative year even in time zones west of UTC, unlike 1-1-0 // 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York.
There may be other instances where the timestamp is formatted
incorrectly, but I don't have time to look into it at the moment.
Steps to reproduce
-
Download this evidence serialized as JSON: https://gist.github.com/romac/58548ff5b4f2ad880bcb53364b1b7ffa
-
Create a new Rust project, add
tendermint-rpc
v0.31.1 as a dependency:
$ cargo new --bin evidence
$ cd evidence/
$ cargo add tendermint-rpc@0.33.1
$ mv ~/Downloads/evidence.json ./
- Paste the following in
src/main.rs
:
use std::fs::File;
use tendermint_rpc::dialect::v0_34::Evidence;
fn main() {
let file = File::open("evidence.json").unwrap();
let evidence: Evidence = serde_json::from_reader(file).unwrap();
println!("{}", serde_json::to_string_pretty(&evidence).unwrap());
}
- Run the executable
$ cargo run -q | jq '.value.ConflictingBlock.signed_header.commit.signatures[1].timestamp'
Expected
"0001-01-01T00:00:00Z"
Result
"1970-01-01T00:00:00Z"
Definition of "done"
The result should match the expected behaviour and tendermint-rs should be able to submit a valid evidence to CometBFT 0.34 and 0.37.
Related issues
Looks like this was already popped up in past issues, but either the fix was lost or overwritten or it was never correct in the first place: