Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/library/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./math/UInt64";
export * from "./math/UInt112";
export * from "./math/UInt224";
export * from "./protocol/VanillaProtocolModules";
export * from "./protocol/WithdrawalMessageProcessor";
export * from "./runtime/Balances";
export * from "./runtime/VanillaRuntimeModules";
export * from "./runtime/Withdrawals";
Expand Down
1 change: 0 additions & 1 deletion packages/protocol/src/prover/block/BlockProver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,6 @@ export class BlockProverProgrammable extends ZkProgrammable<
const finalizeBlockProof = deferTransactionProof.or(deferSTProof).not();
// .or()
// .or(state.bundleList.isEmpty().and(state.pendingSTBatches.isEmpty()));
// TODO This finalizes immediately if nothing happened - which we don't account for in tracer currently

return this.computeOutput(publicInput, state, finalizeBlockProof);
}
Expand Down
10 changes: 9 additions & 1 deletion packages/protocol/src/settlement/contracts/BridgeContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ export class BridgeContractContext {
}

export interface BridgeContractArgs {
SettlementContract: TypedClass<BridgingSettlementContractType> &
SettlementContract: TypedClass<
Pick<BridgingSettlementContractType, "assertStateRoot">
> &
typeof SmartContract;
messageProcessors: OutgoingMessageProcessor<unknown>[];
batchSize?: number;
Expand Down Expand Up @@ -186,7 +188,9 @@ export abstract class BridgeContractBase
messageType: args.messageType,
value,
});
Provable.log("h", Poseidon.hash(MessageType.toFields(message)));
return {
// TODO This doesn't make any sense tbh...
messageType: args.messageType,
result: processor.processMessage(value, {
bridgeContract: {
Expand Down Expand Up @@ -302,6 +306,10 @@ export abstract class BridgeContractBase
}
);

Provable.log(message.hash);
Provable.log(path);
Provable.log(stateRoot);

args.witness
.checkMembership(stateRoot, path, message.hash)
.or(isDummy)
Expand Down
176 changes: 176 additions & 0 deletions packages/sdk/test/bridgeContract/bridge-contract.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import "reflect-metadata";
import {
BridgeContract,
BridgeContractArgs,
BridgeContractContext,
BridgingSettlementContractType,
ContractArgsRegistry,
createMessageStruct,
OutgoingMessageArgument,
OutgoingMessageArgumentBatch,
OutgoingMessageKey,
Path,
PROTOKIT_FIELD_PREFIXES,
} from "@proto-kit/protocol";
import {
AccountUpdate,
Mina,
PrivateKey,
SmartContract,
state,
State,
Permissions,
TokenId,
Field,
UInt64,
Poseidon,
Provable,
method,
} from "o1js";
import { container } from "tsyringe";
import { Withdrawal, WithdrawalMessageProcessor } from "@proto-kit/library";
import {
InMemoryLinkedLeafStore,
InMemoryMerkleTreeStorage,
LinkedMerkleTree,
noop,
} from "@proto-kit/common";

class MockSettlementContract
extends SmartContract
implements Pick<BridgingSettlementContractType, "assertStateRoot">
{
@state(Field) root = State<Field>(Field(100));

public assertStateRoot(root: Field): AccountUpdate {
return this.self;
}

@method
public async test() {
noop();
}
}

const proofsEnabled = false;

describe("bridging contract", () => {
it("setup", async () => {
container
.resolve(ContractArgsRegistry)
.addArgs<BridgeContractArgs>("BridgeContract", {
SettlementContract: MockSettlementContract,
messageProcessors: [new WithdrawalMessageProcessor() as any],
});

const key1 = PrivateKey.random();
const key2 = PrivateKey.random();

const chain = await Mina.LocalBlockchain({ proofsEnabled });
Mina.setActiveInstance(chain);

const vkSettlement = await MockSettlementContract.compile();
const vk = await BridgeContract.compile();

const settlement = new MockSettlementContract(key1.toPublicKey());
const contract = new BridgeContract(key2.toPublicKey());

const tx = await Mina.transaction(chain.testAccounts[0], async () => {
AccountUpdate.fundNewAccount(chain.testAccounts[0], 2);

await settlement.deploy(vkSettlement);

const accountUpdate = await contract.deployProvable(
vk.verificationKey,
false,
Permissions.default(),
key1.toPublicKey()
);
accountUpdate.requireSignature();
AccountUpdate.attachToTransaction(accountUpdate);

AccountUpdate.createSigned(chain.testAccounts[0]).send({
to: key1.toPublicKey(),
amount: 1e9,
});
});

const proven = await tx
.sign([chain.testAccounts[0].key, key1, key2])
.prove();
const txId = await proven.send();
await txId.wait();

const tree = new LinkedMerkleTree(
new InMemoryMerkleTreeStorage(),
new InMemoryLinkedLeafStore()
);
const path = Path.fromKey(
PROTOKIT_FIELD_PREFIXES.OUTGOING_MESSAGE_BASE_PATH,
OutgoingMessageKey,
{
index: Field(0),
tokenId: contract.tokenId,
}
);
const message = new Withdrawal({
tokenId: TokenId.default,
amount: UInt64.from(1e9),
address: chain.testAccounts[1].key.toPublicKey(),
});
const MessageType = createMessageStruct(Withdrawal);
tree.setLeaf(
path.toBigInt(),
Poseidon.hash(
MessageType.toFields({ messageType: Field(0), value: message })
).toBigInt()
);
Provable.log(
"tree hash",
Poseidon.hash(
MessageType.toFields({ messageType: Field(0), value: message })
).toBigInt()
);

const tx2 = await Mina.transaction(chain.testAccounts[0], async () => {
await contract.updateStateRoot(tree.getRoot());
});
const proven2 = await tx2
.sign([chain.testAccounts[0].key, key1, key2])
.prove();
const txId2 = await proven2.send();
await txId2.wait();

container.resolve(BridgeContractContext).data = {
messageInputs: [[message]],
};

const treeWitness = tree.getReadWitness(path.toBigInt());

const tx3 = await Mina.transaction(chain.testAccounts[0], async () => {
const funded = await contract.rollupOutgoingMessages(
OutgoingMessageArgumentBatch.fromMessages([
new OutgoingMessageArgument({
messageType: Field(0),
witness: treeWitness,
}),
])
);

let numNewAccountsNumber = 0;
Provable.asProver(() => {
numNewAccountsNumber = parseInt(funded.toString(), 10);
});

// Pay account creation fees for internal token accounts
AccountUpdate.fundNewAccount(chain.testAccounts[0], numNewAccountsNumber);
});
const proven3 = await tx3
.sign([chain.testAccounts[0].key, key1, key2])
.prove();
const txId3 = await proven3.send();
await txId3.wait();

console.log(proven3.proofs.map((p) => p?.toJSON()));
}, 300000);
});