Skip to content

Commit

Permalink
Merge pull request #38 from chainhackers/36-first-integrated-launch
Browse files Browse the repository at this point in the history
BattleShipDeploy.s.sol #36
  • Loading branch information
silvesterdrago authored Aug 13, 2023
2 parents 55fd9f0 + c17b419 commit 4257efe
Show file tree
Hide file tree
Showing 17 changed files with 651 additions and 52 deletions.
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ ETHERSCAN_API_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXX_FIXME
Source the .env file and deploy the contracts:
```shell
source .env
forge script script/Deploy.s.sol:DeployScript --rpc-url $GOERLI_RPC_URL --broadcast --verify
forge script script/GameRegistryDeploy.s.sol:GameRegistryDeploy --rpc-url $GOERLI_RPC_URL --broadcast --verify

```
```shell
# ...
Expand All @@ -122,3 +123,24 @@ forge script script/Deploy.s.sol:DeployScript --rpc-url $GOERLI_RPC_URL --broadc
#
#Sensitive values saved to: ...
```
Deploy BattleShip:
```shell
forge script script/BattleShipDeploy.s.sol:BattleShipDeploy --rpc-url $GOERLI_RPC_URL --broadcast --verify -v
```
```shell
# Details: `Pass - Verified`
# Contract successfully verified
# All (1) contracts were verified!
```

## Upgrade!
### Upgrade `GameRegistry` in Goerli
```shell
source .env
forge script script/GameRegistryUpgrade.s.sol:GameRegistryUpgrade --rpc-url $GOERLI_RPC_URL --broadcast --verify -v
```
```shell
#Details: `Pass - Verified`
#Contract successfully verified
#All (1) contracts were verified!
```
24 changes: 14 additions & 10 deletions backend/battleship.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
from zokrates import zokrates_prove
from game import Game
from log_setup import setup_logger
from dotenv import load_dotenv

load_dotenv()
logger = setup_logger()

HORIZONTAL = 1
Expand All @@ -38,7 +36,7 @@ def __init__(
self._zokrates_init_handler_dir = zokrates_init_handler_dir
self._zokrates_move_handler_dir = zokrates_move_handler_dir
self.board_size()
self._game_id = game_id
self._game_id = int(game_id)
self.calculate_filled_cells()

@property
Expand Down Expand Up @@ -106,7 +104,8 @@ def _zokrates_init_validator(self):
return zokrates_prove(
self._zokrates_executable_location,
self._zokrates_init_handler_dir,
*self.ships_positions
*self.ships_positions,
logger=logger,
)

def call_game_init(self, proof):
Expand All @@ -124,7 +123,7 @@ def call_game_init(self, proof):
})
signed_tx = self.w3.eth.account.sign_transaction(tx, private_key=PRIVATE_KEY)
tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)
logger.info(f"TX SENT {tx_hash} FROM GAME_INIT")
logger.info(f"TX SENT {tx_hash.hex()} FROM GAME_INIT")

def _zokrates_move_validator(self, coordinate, digest):
"""
Expand All @@ -140,6 +139,7 @@ def _zokrates_move_validator(self, coordinate, digest):
*self.ships_positions,
digest,
coordinate,
logger=logger,
)

def calculate_result(self, guess):
Expand Down Expand Up @@ -173,19 +173,20 @@ def call_move_result(self, move_id, game_id, result, proof):
:param result: int
:return:
"""
logger.info(f'Sending transaction with result {result[1]} to contract')
tx = self.contract.functions.moveResult(
self.w3.to_wei(move_id, "wei"), # Convert to type uint256
self.w3.to_wei(game_id, "wei"), # Convert to type uint256
move_id,
result[0], # Status code
game_id,
*parse_proof(proof)
).build_transaction({
"from": self.account.address,
"nonce": self.w3.eth.get_transaction_count(self.account.address),
})
signed_tx = self.w3.eth.account.sign_transaction(tx, private_key=PRIVATE_KEY)
tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)
logger.info(f'SEND TRANSACTION WITH RESULT {result[1]} TO CONTRACT')
logger.info(f'TRANSACTION DETAILS'
logger.info(f"tx sent {tx_hash.hex()} from move_result")
logger.info(f'transaction details'
f'{self.w3.eth.wait_for_transaction_receipt(tx_hash)}')

def player_move(self, value):
Expand All @@ -211,10 +212,13 @@ def handle_move_event(self, event):
"player": event['args']['player'],
"digest": event['args']['digest']
}
logger.info(f'Event received: {msg}')
if self._game_id == msg['gameId']:
print(msg)
logger.info("Call player_move function")
self.player_move(msg)
logger.info(msg)
else:
logger.info(f'Wrong game id {msg["gameId"]} != {self._game_id}')

def subscribe_to_contract_events(self):
"""
Expand Down
4 changes: 3 additions & 1 deletion backend/zokrates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json


def zokrates_prove(zokrates_path, work_dir, *args):
def zokrates_prove(zokrates_path, work_dir, *args, logger=None):
result = subprocess.run(
" ".join([
f"{zokrates_path}",
Expand All @@ -18,5 +18,7 @@ def zokrates_prove(zokrates_path, work_dir, *args):
cwd=work_dir
)
if result.returncode == 0:
if logger is not None:
logger.info(result.stdout.decode("utf-8"))
with open(work_dir + "/proof.json", "r") as f:
return json.load(f)
2 changes: 2 additions & 0 deletions contracts/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ out/
/broadcast/*/31337/
/broadcast/**/dry-run/

broadcast

# Docs
docs/
32 changes: 32 additions & 0 deletions contracts/script/BattleShipDeploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Script, console2} from "forge-std/Script.sol";
import "../src/BattleShip.sol";
import "../src/verifiers/battleship_init.sol";
import "../src/verifiers/battleship_move.sol";

contract BattleShipDeploy is Script {
//Goerli
address constant REGISTRY = 0x15009Cbe24D1bFA83ABeCD177a5cd00B0D069AC0;
address constant BACKEND = 0xb95A131ABF8c82aC9A3e9715Fb2eb1f7E2AAfcE8;

function run() public {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployerAddr = vm.addr(deployerPrivateKey);

vm.startBroadcast(deployerPrivateKey);

BattleShipInitVerifier initVerifier = new BattleShipInitVerifier();
BattleShipMoveVerifier moveVerifier = new BattleShipMoveVerifier();

BattleShip battleShip = new BattleShip(
IGameRegistry(REGISTRY),
BACKEND,
initVerifier,
moveVerifier
);

vm.stopBroadcast();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "../src/GameRegistry.sol";

import {ERC1967Proxy} from "../lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol";

contract DeployScript is Script {
contract GameRegistryDeploy is Script {
function run() public {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployerAddr = vm.addr(deployerPrivateKey);
Expand Down
32 changes: 32 additions & 0 deletions contracts/script/GameRegistryUpgrade.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Script, console2} from "forge-std/Script.sol";
import "../src/interfaces/IGameRegistry.sol";
import "../src/GameRegistry.sol";
import "./IUpgradeable.sol";

import {ERC1967Proxy} from "../lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol";

contract GameRegistryUpgrade is Script {
//Goerli
address constant REGISTRY = 0x15009Cbe24D1bFA83ABeCD177a5cd00B0D069AC0;

function run() public {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployerAddr = vm.addr(deployerPrivateKey);

vm.startBroadcast(deployerPrivateKey);

address newGrid = address(new GameRegistry());
bytes memory data = abi.encodeCall(
GameRegistry.initialize,
"https://arweave.net/rip5RY1wf8gKBl5CxEAKQHG9tc09SqyMFwJDOYT8xX0/{id}");
IUpgradeable(REGISTRY).upgradeTo(newGrid);

GameRegistry registry = GameRegistry(REGISTRY);
assert(registry.owner() == deployerAddr);

vm.stopBroadcast();
}
}
7 changes: 7 additions & 0 deletions contracts/script/IUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IUpgradeable {
//https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol#L68
function upgradeTo(address newImplementation) external;
}
83 changes: 74 additions & 9 deletions contracts/src/BattleShip.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,93 @@
pragma solidity 0.8.20;

import "./interfaces/IGame.sol";
import "./interfaces/IGameRegistry.sol";
import "../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
import "./verifiers/battleship_init.sol";
import "./verifiers/battleship_move.sol";

contract BattleShip is IGame {
uint256 public number;
uint256 public digest;
contract BattleShip is IGame, Ownable {
uint256 public nextMoveId;
mapping(uint256 => uint256) public digest;
IGameRegistry public registry;
BattleShipInitVerifier public initVerifier;
BattleShipMoveVerifier public moveVerifier;
mapping(uint256 => mapping(uint8 => uint8)) public discovered;

// @dev mapping of move IDs to moves
mapping(uint256 => MoveSent) public moves;

constructor(
IGameRegistry _registry,
address backend,
BattleShipInitVerifier _initVerifier,
BattleShipMoveVerifier _moveVerifier
){
registry = _registry;
initVerifier = _initVerifier;
moveVerifier = _moveVerifier;
transferOwnership(backend);
}

function initGame(uint256 gameId, ZoKratesStructs.Proof calldata proof, uint256[] calldata inputs) external {
digest = inputs[0];
emit GameInit(gameId, digest);
uint256[1] memory _inputs;
_inputs[0] = inputs[0];
BattleShipInitVerifier.Proof memory _proof;
_proof.a.X = proof.a.X;
_proof.a.Y = proof.a.Y;
_proof.b.X[0] = proof.b.X[0];
_proof.b.X[1] = proof.b.X[1];
_proof.b.Y[0] = proof.b.Y[0];
_proof.b.Y[1] = proof.b.Y[1];
_proof.c.X = proof.c.X;
_proof.c.Y = proof.c.Y;
require(initVerifier.verifyTx(_proof, _inputs), "Invalid proof");
digest[gameId] = inputs[0];
for (uint8 i = 0; i < 100; i++) {
discovered[gameId][i] = 0;
}
emit GameInit(gameId, digest[gameId]);
}

function isValidMove(uint8 coordinate, uint256 gameId) external view returns (bool){
return coordinate % 5 > 0;
if (coordinate > 99) {
return false;
}
return discovered[gameId][coordinate] == 0;
}

function move(uint8 coordinate, uint256 gameId) external {
emit Move(number, coordinate, gameId, msg.sender);
number++;
emit Move(nextMoveId, coordinate, gameId, tx.origin, digest[gameId]); //TODO tx.origin :P
moves[nextMoveId].gameId = gameId;
moves[nextMoveId].coordinate = coordinate;
moves[nextMoveId].player = tx.origin; //TODO tx.origin :P update interface pass player addr explicitly
nextMoveId++;
}


function moveResult(uint256 moveId, uint8 result, uint256 gameId, ZoKratesStructs.Proof calldata proof, uint256[] calldata inputs) external {
require(digest == inputs[0], "Invalid digest");
uint256[3] memory _inputs;
_inputs[0] = inputs[0];
_inputs[1] = inputs[1];
_inputs[2] = inputs[2];
BattleShipMoveVerifier.Proof memory _proof;
_proof.a.X = proof.a.X;
_proof.a.Y = proof.a.Y;
_proof.b.X[0] = proof.b.X[0];
_proof.b.X[1] = proof.b.X[1];
_proof.b.Y[0] = proof.b.Y[0];
_proof.b.Y[1] = proof.b.Y[1];
_proof.c.X = proof.c.X;
_proof.c.Y = proof.c.Y;
require(moveVerifier.verifyTx(_proof, _inputs), "Invalid proof");
require(digest[gameId] == inputs[0], "Invalid digest");

emit MoveResult(moveId, result, gameId);
uint8 coordinate = moves[moveId].coordinate;
discovered[gameId][coordinate] = result;

delete moves[moveId];
registry.answerPlayerMove(gameId, moveId, IGameRegistry.MoveRes(result), 0, false);
}

function name(uint256 gameId) external view returns (string memory){
Expand Down
Loading

0 comments on commit 4257efe

Please sign in to comment.