-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathTaikoInbox.sol
More file actions
156 lines (126 loc) · 5.76 KB
/
Copy pathTaikoInbox.sol
File metadata and controls
156 lines (126 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IBlobRefRegistry} from "../../blobs/IBlobRefRegistry.sol";
import {IDelayedInclusionStore} from "../IDelayedInclusionStore.sol";
import {DelayedInclusionStore} from "./DelayedInclusionStore.sol";
import {IInbox} from "../IInbox.sol";
import {ILookahead} from "../ILookahead.sol";
import {IProposerFees} from "../IProposerFees.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
contract TaikoInbox is IInbox, DelayedInclusionStore, Ownable {
/// @dev Caller is not the current preconfer
error NotCurrentPreconfer();
/// @dev Anchor block ID is too old
error AnchorBlockTooOld();
/// @dev Blockhash is not available for the anchor block
error BlockhashUnavailable();
struct Metadata {
uint256 anchorBlockId;
bytes32 anchorBlockHash;
bool isDelayedInclusion;
}
ILookahead public immutable lookahead;
IProposerFees public proposerFees;
uint256 public immutable maxAnchorBlockIdOffset;
/// @dev Modifier to check if proposerFees has been initialised
modifier checkProposerFeesInitialized() {
require(address(proposerFees) != address(0), "ProposerFees not initialised");
_;
}
// attributes associated with the publication
uint256 private constant METADATA = 0;
uint256 private constant BLOB_REFERENCE = 1;
uint256 private constant NUM_ATTRIBUTES = 2;
bytes32[] private _publicationHashes;
constructor(
address _lookahead,
address _blobRefRegistry,
uint256 _maxAnchorBlockIdOffset,
uint256 _inclusionDelay,
address _owner
) DelayedInclusionStore(_inclusionDelay, _blobRefRegistry) Ownable(_owner) {
lookahead = ILookahead(_lookahead);
maxAnchorBlockIdOffset = _maxAnchorBlockIdOffset;
// guarantee there is always a previous hash
_publicationHashes.push(0);
}
/// @inheritdoc IInbox
function initializeProposerFees(address _proposerFees) external onlyOwner {
require(address(proposerFees) != address(0), "ProposerFees already initialised");
require(_proposerFees != address(0), "ProposerFees cannot be zero");
proposerFees = IProposerFees(_proposerFees);
emit ProposerFeesInitialised(_proposerFees);
}
/// @inheritdoc IInbox
function publish(uint256 nBlobs, uint64 anchorBlockId) external checkProposerFeesInitialized {
if (address(lookahead) != address(0)) {
require(lookahead.isCurrentPreconfer(msg.sender), NotCurrentPreconfer());
}
// Build the attribute for the anchor transaction inputs
require(anchorBlockId >= block.number - maxAnchorBlockIdOffset, AnchorBlockTooOld());
Metadata memory metadata = Metadata({
anchorBlockId: anchorBlockId,
anchorBlockHash: blockhash(anchorBlockId),
isDelayedInclusion: false
});
require(metadata.anchorBlockHash != 0, BlockhashUnavailable());
bytes[] memory attributes = new bytes[](NUM_ATTRIBUTES);
attributes[METADATA] = abi.encode(metadata);
attributes[BLOB_REFERENCE] = abi.encode(blobRefRegistry.getRef(_buildBlobIndices(nBlobs)));
_publish(attributes, false);
// Publish each delayed inclusion as a separate publication
IDelayedInclusionStore.Inclusion[] memory inclusions = processDueInclusions();
uint256 nInclusions = inclusions.length;
// Metadata is the same as the regular publication, so we just set `isDelayedInclusion` to true
metadata.isDelayedInclusion = true;
for (uint256 i; i < nInclusions; ++i) {
attributes[METADATA] = abi.encode(metadata);
attributes[BLOB_REFERENCE] = abi.encode(inclusions[i]);
_publish(attributes, true);
}
}
/// @dev Internal implementation of publication logic
/// @param attributes The data to publish
/// @param isDelayed Whether this is a delayed inclusion publication
function _publish(bytes[] memory attributes, bool isDelayed) internal {
proposerFees.payPublicationFee(msg.sender, isDelayed);
uint256 nAttributes = attributes.length;
bytes32[] memory attributeHashes = new bytes32[](nAttributes);
for (uint256 i; i < nAttributes; ++i) {
attributeHashes[i] = keccak256(attributes[i]);
}
uint256 id = _publicationHashes.length;
PublicationHeader memory header = PublicationHeader({
id: id,
prevHash: _publicationHashes[id - 1],
publisher: msg.sender,
timestamp: block.timestamp,
blockNumber: block.number,
attributesHash: keccak256(abi.encode(attributeHashes))
});
bytes32 pubHash = keccak256(abi.encode(header));
_publicationHashes.push(pubHash);
emit Published(pubHash, header, attributes);
}
/// @inheritdoc IInbox
function getPublicationHash(uint256 idx) external view returns (bytes32) {
return _publicationHashes[idx];
}
/// @inheritdoc IInbox
function getNextPublicationId() external view returns (uint256) {
return _publicationHashes.length;
}
/// @inheritdoc IInbox
function validateHeader(PublicationHeader calldata header) external view returns (bool) {
return keccak256(abi.encode(header)) == _publicationHashes[header.id];
}
/// @dev Builds blob indices array for the given number of blobs
/// @param nBlobs Number of blobs to create indices for
/// @return blobIndices Array of blob indices
function _buildBlobIndices(uint256 nBlobs) private pure returns (uint256[] memory blobIndices) {
blobIndices = new uint256[](nBlobs);
for (uint256 i; i < nBlobs; ++i) {
blobIndices[i] = i;
}
}
}