`encode_int192` zero-pads negative values, corrupting them on `abi_encode`
还没有人认领这个 Issue。
评估
调研方向
阅读 ReportBase::encode_int192 和 ReportBase::encode_int64 的实现,然后检查现有的 test_decode_report_data_v12 测试。为负值添加往返测试,并检查编码后的 ABI 字是否使用符号扩展;当负数字段解码回原始值且两个编码器都输出规范字时,即为完成。
由索引模型根据 Issue 内容生成。
描述
encode_int192 zero-pads negative values, so abi_encode corrupts them and emits non-canonical ABI words.
ReportBase::encode_int192 right-aligns BigInt::to_signed_bytes_be() — the minimal two's-complement form — into a zero-filled 32-byte buffer. For a negative value that minimal form is shorter than 24 bytes, and the leading bytes are left 0x00 instead of 0xFF, so the sign is lost.
ReportBase::encode_int64 has the same zero-fill, but because i64::to_be_bytes() is always 8 bytes and read_int64 reads exactly those 8 bytes back, the value survives a round-trip through this crate. The word it emits is still not what an ABI encoder would produce.
Affects 1.2.0, 1.2.2 and 1.3.0 (current). decode is correct — it reads the low 24 bytes as signed — so bodies returned by a real verifier are unaffected. What breaks is anything that builds a report with abi_encode.
Reproduction
use chainlink_data_streams_report::{feed_id::ID, report::v12::ReportDataV12};
use num_bigint::BigInt;
let report = ReportDataV12 {
feed_id: ID([0u8; 32]),
valid_from_timestamp: 1,
observations_timestamp: 1,
native_fee: BigInt::ZERO,
link_fee: BigInt::ZERO,
expires_at: 2,
nav_per_share: BigInt::from(-1),
next_nav_per_share: BigInt::from(-1_000_000),
nav_date: -1,
ripcord: 0,
};
let decoded = ReportDataV12::decode(&report.abi_encode().unwrap()).unwrap();
assert_eq!(decoded.nav_per_share, BigInt::from(-1)); // fails: 255
Output:
nav_per_share in: -1 out: 255
next_nav_per_share in: -1000000 out: 15777216
nav_date in: -1 out: -1
The navPerShare word:
actual: 00000000000000000000000000000000000000000000000000000000000000ff
expected: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Impact
Any code that builds a report body with abi_encode gets a different value back than it put in, whenever a field is negative. This is easy to miss in a test: a case that encodes a negative value to prove the consumer rejects it still passes, because what reaches the consumer is a large positive number rejected for an unrelated reason.
The emitted word is also not valid ABI, so a body built with abi_encode and read by Solidity's abi.decode disagrees with this crate.
Suggested fix
Fill the buffer according to the sign before copying, in both encode_int192 and encode_int64:
pub(crate) fn encode_int192(value: &BigInt) -> Result<[u8; 32], ReportError> {
let bytes_value = value.to_signed_bytes_be();
let len = bytes_value.len();
if len > 24 {
return Err(ReportError::InvalidLength("int192"));
}
let fill = if value.sign() == Sign::Minus { 0xFF } else { 0x00 };
let mut buffer = [fill; 32];
buffer[32 - len..32].copy_from_slice(&bytes_value);
Ok(buffer)
}
A round-trip test over negative values would catch both. The existing test_decode_report_data_v12 uses only positive mocks, which is why this is not caught today.
- 主要语言
- TypeScript
- 星标
- 11
- 派生
- 16
- 平均合并
- 3 天 16 小时
- 30 天内合并 PR
- 2
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
smartcontractkit/data-streams-sdk 的其他 Issue
-
Add 'once' support可能已有人在做 @ChrisWozniak 于 49 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 55/100
smartcontractkit/data-streams-sdk#61 · 1 个 reaction ·
查看 smartcontractkit/data-streams-sdk 的全部 Issue
相似的 Issue
-
area:cli bug P4
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
bug from-studio
难度 2/5 1-3 小时 新手友好度 65/100
esengine/DeepSeek-Reasonix#14868 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
linxiv-dev/linXiv#384 · 1 条评论 ·
维护者通常 1 天内回复
-
scope:core type:security
难度 2/5 1-3 小时 新手友好度 75/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 66/100
mailgun/mailgun.js#544 ·