`encode_int192` zero-pads negative values, corrupting them on `abi_encode`

Đang mở Phù hợp với người mới
#82 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
76/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
rust
Lĩnh vực
api, backend

Hướng nghiên cứu

Đọc các phần triển khai của ReportBase::encode_int192 và ReportBase::encode_int64, sau đó kiểm tra bài kiểm thử test_decode_report_data_v12 hiện có. Bổ sung kiểm thử khứ hồi cho các giá trị âm và kiểm tra các từ ABI được mã hóa có sử dụng mở rộng dấu hay không; hoàn thành khi các trường âm được giải mã trở lại đúng giá trị ban đầu và cả hai bộ mã hóa đều xuất ra các từ chuẩn tắc.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.

Ngôn ngữ chính
TypeScript
Star
11
Fork
16
Merge trung bình
1 ngày 20 giờ
Pull request đã merge (30 ngày)
4

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của smartcontractkit/data-streams-sdk

Tất cả issue của smartcontractkit/data-streams-sdk

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.