Skip to content

Commit

Permalink
Add duplicate TX rejection on-chain in Pente
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Broadhurst <[email protected]>
  • Loading branch information
peterbroadhurst committed Dec 13, 2024
1 parent 83b85a6 commit f55a688
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
9 changes: 9 additions & 0 deletions solidity/contracts/domains/pente/PentePrivacyGroup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ contract PentePrivacyGroup is IPente, UUPSUpgradeable, EIP712Upgradeable {

mapping(bytes32 => bool) private _unspent;
mapping(bytes32 => address) private _approvals;
mapping(bytes32 => bool) private _txids;
address _nextImplementation;

// Config follows the convention of a 4 byte type selector, followed by ABI encoded bytes
bytes4 public constant PenteConfig_V0 = 0x00010000;

error PenteDuplicateTransaction(bytes32 txId);
error PenteUnsupportedConfigType(bytes4 configSelector);
error PenteDuplicateEndorser(address signer);
error PenteInvalidEndorser(address signer);
Expand Down Expand Up @@ -155,6 +157,13 @@ contract PentePrivacyGroup is IPente, UUPSUpgradeable, EIP712Upgradeable {
States calldata states,
ExternalCall[] calldata externalCalls
) internal {

// On-chain enforcement of TXID uniqueness
if (_txids[txId] != false) {
revert PenteDuplicateTransaction(txId);
}
_txids[txId] = true;

// Perform the state transitions
for (uint i = 0; i < states.inputs.length; i++) {
if (!_unspent[states.inputs[i]]) {
Expand Down
23 changes: 17 additions & 6 deletions solidity/test/domains/pente/PentePrivacyGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,22 +129,33 @@ describe("PentePrivacyGroup", function () {
);
const tx1ID = randBytes32();

const tx1 = {
inputs: [],
reads: [],
outputs: stateSet1,
info: info1,
};
await expect(
privacyGroup.transition(
tx1ID,
{
inputs: [],
reads: [],
outputs: stateSet1,
info: info1,
},
tx1,
[],
endorsements1
)
)
.to.emit(privacyGroup, "PenteTransition")
.withArgs(tx1ID, [], [], stateSet1, info1);

// Rejects duplicate
await expect(
privacyGroup.transition(
tx1ID,
tx1,
[],
endorsements1
)
).to.be.rejectedWith("PenteDuplicateTransaction");

const stateSet2 = [randBytes32(), randBytes32(), randBytes32()];
const inputs2 = [stateSet1[1]];
const reads2 = [stateSet1[0], stateSet1[2]];
Expand Down

0 comments on commit f55a688

Please sign in to comment.