Skip to content

Commit dc4df9b

Browse files
committed
RVDS: support ledger eventlog record and ethereumAdapter
Signed-off-by: Jiale Zhang <[email protected]>
1 parent 01c3c1d commit dc4df9b

File tree

21 files changed

+1210
-14
lines changed

21 files changed

+1210
-14
lines changed

Cargo.lock

Lines changed: 401 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rvds/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,13 @@
1919
thiserror = { workspace = true }
2020
tokio = { workspace = true, features = ["full"] }
2121
url = "2"
22+
sha2 = { workspace = true }
23+
async-trait = { workspace = true }
24+
hex = { workspace = true }
25+
rand = "0.8"
26+
web3 = { version = "0.19", default-features = false, features = ["http", "signing"] }
27+
ethabi = "18"
28+
secp256k1 = { version = "0.27", features = ["rand"] }
29+
base64 = { workspace = true }
2230

2331

rvds/docs/architecture.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- **HTTP API(Actix-web)**:暴露 `/rvds/*` 接口,负责参数校验与响应封装。
1515
- **订阅注册表(Subscriber Registry)**:用 `HashSet` 存储已注册的 Trustee 基址,持久化于 `data/rvds/subscribers.json`
1616
- **事件转发器(Forwarder)**:接收发布事件后,构造 RVPS 期望的 `message` 包裹并并发调用各 Trustee 的 `/api/rvps/register`
17+
- **账本记录器(Ledger Recorder)**:对 `PublishEventRequest` 做规范化哈希,写入外部不可篡改账本(默认 noop,可配置 HTTP / 以太坊网关),返回记录凭据,并将审计凭据随 payload 一并下发。
1718
- **配置与启动器(Config / Bootstrap)**:从环境变量加载监听地址、数据目录、下游调用超时等参数。
1819

1920
## 数据模型
@@ -27,7 +28,14 @@
2728
{
2829
"artifact_type": "rpm",
2930
"slsa_provenance": ["..."], // 多个 provenance(原文或 base64),数组形式
30-
"artifacts_download_url": ["https://...rpm"]
31+
"artifacts_download_url": ["https://...rpm"],
32+
"audit_proof": { // 可选,账本回执
33+
"backend": "ethereum-gateway",
34+
"handle": "0x<tx_hash>",
35+
"event_hash": "<sha256(canonical payload)>",
36+
"payload_hash": "<sha256(payload)>",
37+
"payload_b64": "<base64 of payload>"
38+
}
3139
}
3240
```
3341
- **转发给 RVPS 的请求**
@@ -45,7 +53,7 @@
4553
- 返回:已新增的地址列表。
4654
- `POST /rvds/rv-publish-event`
4755
- 功能:校验事件并转发到全部 Trustee。
48-
- 返回:每个 Trustee 的投递结果(成功/失败与错误信息)。
56+
- 返回:每个 Trustee 的投递结果(成功/失败与错误信息),以及可选的 ledger 记录凭据
4957

5058
## 工作流程
5159

rvds/docs/audit-guide.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# 第三方审计操作手册(RVDS + RVPS + 以太坊账本)
2+
3+
本手册指导审计者仅凭 RVPS 返回的参考值(含审计字段)完成端到端验证,确认 RVDS 发布事件已被写入不可篡改账本(以太坊为例),并与 RVPS 内的参考值一致。账本侧仅写入摘要(hash),原文由 RVPS 的 `audit_proof.payload_b64` 提供。
4+
5+
## 前提信息
6+
- RVPS 查询到的 `ReferenceValue`,其中可选字段 `audit_proof`
7+
```json
8+
{
9+
"name": "...",
10+
"hash-value": [...],
11+
"audit_proof": {
12+
"backend": "ethereum-gateway",
13+
"handle": "0x<tx_hash>",
14+
"event_hash": "<sha256 of canonical PublishEventRequest>",
15+
"payload_hash": "<sha256 of payload>",
16+
"payload_b64": "<base64 of canonical payload>"
17+
}
18+
}
19+
```
20+
- RVDS 账本记录:在 ledger_receipt 中会返回与 `audit_proof` 对应的字段。
21+
- 合约地址与链信息:`ETH_CONTRACT_ADDRESS`,链 ID,RPC/浏览器入口。
22+
23+
## 步骤 1:本地重算并校验摘要
24+
1. 从 RVPS 返回的 `audit_proof.payload_b64` 解码得到 canonical `PublishEventRequest` JSON。
25+
2. 本地计算:
26+
- `sha256(payload)` → 对比 `payload_hash`
27+
- `sha256(canonical payload)` → 对比 `event_hash`
28+
若不一致,审计失败。
29+
30+
## 步骤 2:链上验证交易与事件
31+
1.`handle``tx_hash`),在浏览器或本地节点查询:
32+
- 浏览器:输入 tx_hash。
33+
- 节点:`eth_getTransactionReceipt <tx_hash>`.
34+
2. 确认交易成功,找到来自合约 `RvdsEventLog``EventRecorded` 事件。
35+
3. 解码事件参数(浏览器通常自动解码):
36+
- `eventHash` (bytes32) 应等于 `audit_proof.event_hash`
37+
- 第二个参数存储的是 `payloadHash`(摘要上链),应等于 `audit_proof.payload_hash`
38+
39+
## 步骤 3:对照 RVPS 参考值
40+
1.`payload` 中的 `slsa_provenance` 解析 `subject[].digest`(和 RVPS 逻辑一致)。
41+
2. 确认解析出的制品哈希与 RVPS 返回的 `hash-value` 完全匹配。
42+
3. 如有多份参考值(多个 subject),逐一对应。
43+
44+
## 命令行示例
45+
假设已拿到 `tx_hash``event_hash``payload_hash``payload_b64`
46+
47+
```bash
48+
# 1) 查询交易(需已配置 ETH_RPC_URL)
49+
curl -s -X POST "$ETH_RPC_URL" \
50+
-H "Content-Type: application/json" \
51+
-d '{
52+
"jsonrpc":"2.0",
53+
"method":"eth_getTransactionReceipt",
54+
"params":["<tx_hash>"],
55+
"id":1
56+
}' | jq .
57+
58+
# 2) 解析 logs,确认事件里 eventHash == audit_proof.event_hash,payloadHash == audit_proof.payload_hash
59+
# 3) 解码 RVPS 提供的 payload_b64 并重算 hash
60+
echo "<payload_b64_from_rvps>" | base64 -d > payload.json
61+
PAYLOAD_HASH_LOCAL=$(sha256sum payload.json | awk '{print $1}')
62+
echo "local payload hash: $PAYLOAD_HASH_LOCAL"
63+
# 对比 audit_proof.payload_hash / event_hash
64+
```
65+
66+
## 浏览器快速校验
67+
1. 打开区块浏览器,输入 `tx_hash`
68+
2. 在 Logs/Events 中找到 `EventRecorded`
69+
- `eventHash` 对比 `audit_proof.event_hash`
70+
- data/decoded payloadHash 对比 `audit_proof.payload_hash`
71+
- 原文由 RVPS 的 `payload_b64` 提供,在本地解码后重算哈希比对。
72+
73+
## 注意事项与影响
74+
- 账本只写 hash,原文不上链;RVPS 存储 payload_b64 供审计端重算哈希。
75+
- `audit_proof` 可选,未开启账本时保持兼容(字段缺失不影响现有接口)。
76+
- 若使用其它账本(如 Rekor),在 `audit_proof.backend/handle` 写入对应证明,验证时使用相应工具;结构不变。
77+

rvds/docs/deployment.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
- `RVDS_LISTEN_ADDR`:监听地址,默认 `0.0.0.0:8090`
1414
- `RVDS_DATA_DIR`:订阅持久化目录,默认 `data/rvds`
1515
- `RVDS_FORWARD_TIMEOUT_SECS`:转发超时秒数,默认 `10`
16+
- `RVDS_LEDGER_BACKEND``none`(默认)、`http``eth`
17+
- `RVDS_LEDGER_HTTP_ENDPOINT` / `RVDS_LEDGER_HTTP_API_KEY`:账本网关(http)配置
18+
- `RVDS_LEDGER_ETH_GATEWAY` / `RVDS_LEDGER_ETH_GATEWAY_API_KEY`:以太坊网关配置
1619
- `RUST_LOG`:日志等级,如 `info,rvds=debug`
1720

1821
## 源码构建运行
@@ -73,5 +76,6 @@ curl -k -X POST http://localhost:8090/rvds/rv-publish-event \
7376

7477
- 在 release workflow 中生成 `PublishEventRequest`,通过 `curl`/`gh api` 等 POST 到 RVDS。
7578
- RVDS 会自动并发转发到已注册的 Trustee;失败结果会返回在响应中,供重试或告警。
79+
- 若配置了 ledger,RVDS 会在响应和下游 payload 中附带 `audit_proof`(含 event_hash/payload_hash/payload_b64、tx 句柄等),便于 RVPS/审计使用。
7680

7781

rvds/docs/eth-gateway.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# RVDS 以太坊网关使用指南
2+
3+
> 作用:提供一个具备签名与上链能力的 HTTP 网关,接受 RVDS 的事件摘要请求,调用链上合约 `record(bytes32 eventHash, string payloadHash)`,并返回真实交易哈希。
4+
5+
## 功能
6+
7+
- 端点:`POST /record`
8+
- 请求:
9+
```json
10+
{
11+
"event_hash": "0x<sha256 hex>", // 32字节
12+
"payload": "canonical PublishEventRequest JSON"
13+
}
14+
```
15+
- 响应:
16+
```json
17+
{ "tx_hash": "0x<real-ethereum-tx-hash>" }
18+
```
19+
- 内部逻辑:
20+
- 对 payload 做 sha256,作为 `payloadHash`
21+
- ABI 编码调用合约 `record(eventHash, payloadHash)`
22+
- 使用私钥签名交易并通过 RPC 发送,返回 tx_hash。
23+
- 默认 gas 200000,gas_price 来自链上 `eth_gasPrice`
24+
25+
## 启动
26+
27+
```bash
28+
cd /root/design/trustee/rvds
29+
cargo run --bin eth_gateway
30+
```
31+
32+
必需环境变量:
33+
- `ETH_RPC_URL`:以太坊 RPC 地址(可用公用节点或自建节点)
34+
- `ETH_PRIVATE_KEY`:0x 前缀的私钥(用于签名)
35+
- `ETH_CONTRACT_ADDRESS`:已部署的合约地址(示例见下)
36+
37+
可选环境变量:
38+
- `ETH_GATEWAY_LISTEN`:监听地址,默认 `0.0.0.0:8095`
39+
- `ETH_CHAIN_ID`:链 ID,默认 `1`
40+
41+
## 合约示例(Solidity 0.8.x)
42+
43+
```solidity
44+
// SPDX-License-Identifier: Apache-2.0
45+
pragma solidity ^0.8.17;
46+
47+
contract RvdsEventLog {
48+
event EventRecorded(bytes32 indexed eventHash, string payloadHash, address indexed sender, uint256 blockNumber);
49+
50+
function record(bytes32 eventHash, string calldata payloadHash) external {
51+
emit EventRecorded(eventHash, payloadHash, msg.sender, block.number);
52+
}
53+
}
54+
```
55+
56+
部署后将合约地址写入 `ETH_CONTRACT_ADDRESS`
57+
58+
## 与 RVDS 对接
59+
60+
在 RVDS 配置:
61+
- `RVDS_LEDGER_BACKEND=eth`
62+
- `RVDS_LEDGER_ETH_GATEWAY=http://<gateway-host>:8095/record`
63+
- `RVDS_LEDGER_ETH_GATEWAY_API_KEY`(当前未校验,可留空)
64+
65+
RVDS 在 `/rvds/rv-publish-event` 时调用网关,`ledger_receipt.handle` 将包含真实链上 `tx_hash`
66+
67+
## 生产注意
68+
69+
- 私钥务必放在可信环境,可优先使用 KMS/HSM 管理;当前示例从环境变量读取,仅适用于 PoC。
70+
- 请确认 gas 费、nonce 管理符合预期;当前实现使用链上 `gasPrice`,固定 gas=200000,可按需调整或改为 `eth_estimateGas`
71+
- 如需鉴权,可在网关增加 API Key/Token 校验,并在 RVDS 设置 `RVDS_LEDGER_ETH_GATEWAY_API_KEY`
72+

rvds/docs/flow.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
}
2424
```
2525
- 并发调用每个 Trustee 的 `https://<trustee>/api/rvps/register`
26+
- 同步将事件摘要(canonical + sha256)写入外部账本(若启用),返回 ledger 凭据,并把审计字段(`audit_proof`,含 event_hash/payload_hash/payload_b64)附在 payload 中下发。
2627
4. **校验与入库**
2728
- Trustee Gateway 将请求转给 RVPS gRPC `RegisterReferenceValue`
2829
- RVPS 通过 `slsa` extractor:
2930
- 解析 `payload` 得到 `artifact_type/slsa_provenance[]/artifacts_download_url`
3031
- 针对每个 provenance(raw JSON 或 base64 JSON)解析 subject,支持多份 provenance。
3132
- 抽取 `subject[].digest`(优先 `sha256`),生成 `ReferenceValue`(默认 12 个月有效)。
33+
-`audit_proof` 落在 ReferenceValue(便于后续第三方审计)。
3234
- 调用存储接口写入参考值。
3335
5. **消费**
3436
- 上游(如 AS)调用 RVPS `query_reference_value` 获取可信哈希用于度量验证。

rvds/docs/ledger-design.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# RVDS 发布事件不可篡改账本记录设计
2+
3+
## 背景与目标
4+
5+
- 发布事件需要“公开可审计、不可篡改”地留痕(典型载体:区块链 / 透明日志)。
6+
- RVDS 在收到 `PublishEventRequest` 时,除转发给 Trustee 外,还需将事件摘要写入外部账本,并返回记录凭据。
7+
- 设计需可扩展:不同场景可接入不同账本(链、透明日志、第三方网关)。
8+
9+
## 设计概览
10+
11+
- 新增 **Ledger Recorder** 组件,核心是 `LedgerAdapter` 抽象:
12+
- `record_event(event, canonical_payload) -> LedgerReceipt`
13+
- 内置实现:`NoopLedger`(默认)、`HttpLedger`(对接外部账本网关)、`EthGatewayLedger`(通过以太坊网关写入链上日志)。
14+
- 事件哈希:
15+
- 使用 canonical JSON(对 `PublishEventRequest` 进行稳定序列化)后计算 `SHA256`,得到 `event_hash``payload_hash`
16+
- 账本端仅写入摘要(hash),不携带原文;原始 payload 以 base64 形式保存在 RVPS 的 `audit_proof` 中,供审计者校验。
17+
- RVDS API 回包增强:
18+
- `PublishResponse` 增加 `ledger_receipt`,便于 CI 在发布日志中附带证明。
19+
20+
## 账本适配层
21+
22+
### 接口
23+
```rust
24+
pub trait LedgerAdapter {
25+
async fn record_event(&self, event: &PublishEventRequest, canonical_payload: &str) -> Result<LedgerReceipt>;
26+
}
27+
```
28+
29+
### 内置实现
30+
- `NoopLedger`:不写外部账本,返回合成的 `event_hash`
31+
- `HttpLedger`:POST `{event_hash, payload}` 到外部网关;网关可自行决定只上链 hash 或其它策略;`ledger_receipt` 会携带本地的 `payload_b64` 供审计者使用。
32+
- `EthGatewayLedger`:面向以太坊链,通过网关 POST `{event_hash, payload}`,网关签名调用合约时仅写入摘要(hash),返回 `tx_hash``ledger_receipt` 同样附带 `payload_b64`
33+
34+
### 选择与配置
35+
- 环境变量:
36+
- `RVDS_LEDGER_BACKEND``none`(默认)、`http``eth`
37+
- `RVDS_LEDGER_HTTP_ENDPOINT`:后端网关地址(`http` 模式必填)
38+
- `RVDS_LEDGER_HTTP_API_KEY`:可选鉴权
39+
- `RVDS_LEDGER_ETH_GATEWAY`:以太坊网关地址(`eth` 模式必填)
40+
- `RVDS_LEDGER_ETH_GATEWAY_API_KEY`:以太坊网关鉴权(可选)
41+
- 未来扩展:
42+
- 可增加 `RekorAdapter`(Sigstore 透明日志)、`EthereumAdapter`(合约记录 `event_hash`),只需实现 `LedgerAdapter` 并在工厂中注册。
43+
44+
## 时序(含账本)
45+
46+
1. CI 调用 `POST /rvds/rv-publish-event`
47+
2. RVDS 规范化序列化 payload,计算 `event_hash`
48+
3. Ledger Recorder 通过适配器写入外部账本,获得 `ledger_receipt`(可能为空)。
49+
4. RVDS 按原逻辑并发转发给各 Trustee 的 `/api/rvps/register`
50+
5. RVDS 返回(示例):
51+
```json
52+
{
53+
"forwarded": [...],
54+
"ledger_receipt": {
55+
"backend": "http",
56+
"handle": "<opaque-proof>",
57+
"event_hash": "<sha256>",
58+
"payload_hash": "<sha256>",
59+
"payload_b64": "<base64 of canonical payload>"
60+
}
61+
}
62+
```
63+
6. 可选:Trustee/RVPS 存储或透传 `ledger_receipt`,便于后续审计。
64+
65+
- ## 容错与安全
66+
-
67+
- Ledger 失败策略:记录 warning 并继续转发(可根据需求改成强制失败)。
68+
- 哈希基于 canonical payload,避免字段顺序影响;业务如需更强规范,可固定字段排序/移除冗余。
69+
- 如需强制验证 ledger 成功,可在生产环境加开关:失败则拒绝发布。
70+
-
71+
- ## 实现范围(本次)
72+
-
73+
- 新增适配层与配置,默认 `none`,支持 `http` 网关写入,以及 `eth`(以太坊网关)模式。
74+
-`PublishResponse` 返回 `ledger_receipt`
75+
- 文档同步:architecture、flow 以及本设计说明。
76+
77+
## 以太坊链设计(网关模式)与合约示例
78+
79+
- 模式:RVDS 通过 `EthGatewayLedger``{event_hash, payload}` POST 到以太坊网关;网关负责签名并调用链上合约时仅写入摘要(hash),返回 `tx_hash`。原文不链上存储,`payload_b64` 仅在 RVPS 中保存。
80+
- 网关接口建议:
81+
- `POST /record` `{ "event_hash": "<hex>", "payload": "<canonical json>" }`
82+
- 返回 `{ "tx_hash": "0x..." }`
83+
- 合约示例(Solidity 0.8.x):
84+
```solidity
85+
// SPDX-License-Identifier: Apache-2.0
86+
pragma solidity ^0.8.17;
87+
88+
contract RvdsEventLog {
89+
event EventRecorded(bytes32 indexed eventHash, string payloadHash, address indexed sender, uint256 blockNumber);
90+
91+
function record(bytes32 eventHash, string calldata payloadHash) external {
92+
emit EventRecorded(eventHash, payloadHash, msg.sender, block.number);
93+
}
94+
}
95+
```
96+
- 部署与网关步骤(概要):
97+
1. 选择链(主网/测试网)并配置 RPC。
98+
2. 部署合约 `RvdsEventLog`,记录下合约地址。
99+
3. 网关持有链上账户私钥,暴露 REST 接口 `/record`
100+
-`event_hash``payloadHash`(可使用同样的 sha256/canonical)调用合约 `record`
101+
- 返回 `tx_hash` 供 RVDS 作为 `handle`
102+
4. 在 RVDS 配置:
103+
- `RVDS_LEDGER_BACKEND=eth`
104+
- `RVDS_LEDGER_ETH_GATEWAY=https://<your-eth-gateway>/record`
105+
- `RVDS_LEDGER_ETH_GATEWAY_API_KEY=<token>`(若需要)
106+
5. 审计时:根据 `event_hash` 计算后,在链上事件日志中查找 `EventRecorded`,确认对应 `tx_hash` 与区块高度。
107+

0 commit comments

Comments
 (0)