What is Solidity?
Solidity is a language that compiles down to Ethereum bytecode. You can write contracts (stateful objects) deployed to the Ethereum blockchain, and interact with them - manipulating state and calling other contracts - by sending data and ETH to the contract’s address. Solidity has been used to create games, as well, such as CryptoKitties
Truffle
So, like most new languages, I started off trying to write a simple game: in this case, Tic Tac Toe.
Truffle is a framework for developing these Ethereum applications (dApps, or distributed apps). Installed via npm, it’ll create a local test blockchain and manage your contract deployment to the blockchain.
Web3.js is a JavaScript library that provides an interface for reading from and sending data to the contract once its deployed. You include it in your Truffle application and it’ll get included with your HTML and other assets. It’s also available in test mode, so you can write unit tests in JavaScript that modify and assert the state of your contract.
Solidity pain points
(Most of this is copied from a previous post and should be revised)
I have a struct:
struct Game {
address xPlayer;
address oPlayer;
bool xTurn;
bool gameOver;
bool xWon;
int8[9] board;
}
and a function that sets up a particular Game
:
mapping(address => Game) public games;
function createGame(address gameAddress, address opponent) returns (bool) {
games[gameAddress] = Game({
xPlayer: opponent,
oPlayer: msg.sender,
xTurn: false,
gameOver: false,
xWon: false,
board: [0,0,0,0,0,0,0,0,0]
});
return true;
}
board
represents a Tic-Tac-Toe board. I’ve played around with making it int8[9]
, string
, bytes32
, and can’t get any to work:
int8[9]
Does not get returned by the public getter. In a test file,
address gameAddress;
var (xPlayer, oPlayer, xTurn, gameOver, xWon, board) = ticTacToe.games(gameAddress);
Results in:
TypeError: Not enough components (5) in value to assign all variables (6).
Uh, so my struct getter is only returning 5 components when called externally?
string
Fine, I’ll try a string. I set the board
to '000000000'
. That gets me past the destructuring problem! But now my assertion:
Assert.equal(board[0], '0', 'Board is intialized to 0s.');
Results in:
TypeError: Indexed expression has to be a type, mapping or array (is inaccessible dynamic type)
So basically, strings can’t be returned externally either? They’re returned as inacessible dynamic type
and you can’t coerce them to bytes32
or anything that implements the []
method.
bytes32
Well, this StackExchange post indicates I should use bytes32
to pass around externally.
Alright, my test is passing: I can access the 0th element and it’s the value I’m expecting. Hooray!
So I write a new function, one that lets me enter moves.
function move(address gameAddress, uint256 index) {
Game storage game = games[gameAddress];
if(game.xTurn) {
require(msg.sender == game.xPlayer);
game.board[0] = 'X';
} else {
game.board[0] = 'O';
}
game.xTurn = !game.xTurn;
}
However, this doesn’t compile:
TypeError: Expression has to be an lvalue.
game.board[0] = 'O';
The docs don’t talk much about bytes32
but mention you can convert a string
into bytes with the bytes()
function.
But that still doesn’t solve my problem of trying to access the value from outside of the contract because you can’t return strings!!
From everything I’ve looked at, I should be able to say game.board[0] =
. Even if I create a new bytes32
I still can’t use []
on it, which makes absolutely NO sense because I can use []
in the tests.
I’m incredibly frustrated an on the edge of pulling my hair out. Next steps: plead for help, pay for help, or try to import a string library
I just wish the compiler would give me more information, the Truffle test framework would let me put in breakpoints and inspect the return values I’m getting, and that there is more of a community who can answer these questions and explain what the right move is here.