Putting it together¶
Now we combine all the components that we previously setup in a setup function. It will be called once for Alice and once for Bob from main like this:
func main() {
// Setup Alice and Bob.
alice, bob := setup(RoleAlice), setup(RoleBob)
// Run our example protocol: Bob Opens, Updates and Closes.
if err := bob.openChannel(); err != nil {
panic(fmt.Errorf("opening channel: %w", err))
}
time.Sleep(100 * time.Millisecond) // Wait for Alice to be ready.
if err := bob.updateChannel(); err != nil {
panic(fmt.Errorf("updating channel: %w", err))
}
if err := bob.closeChannel(); err != nil {
panic(fmt.Errorf("closing channel: %w", err))
}
// Wait for both nodes to stop.
fmt.Println("Waiting for Alice")
<-alice.done
fmt.Println("Waiting for Bob")
<-bob.done
}
func setup(role Role) *node {
fmt.Println("Starting ", role)
account, wallet, err := setupWallet(role)
if err != nil {
panic(fmt.Sprintf("setting up wallet: %v", err))
}
transactor := createTransactor(wallet)
_, contractBackend, err := connectToChain(transactor)
if err != nil {
panic(fmt.Sprintf("connecting to chain: %v", err))
}
adjudicator, assetholder, err := setupContracts(role, contractBackend, account.Account)
if err != nil {
panic(fmt.Errorf("setting up contracts: %w", err))
}
listener, bus, err := setupNetwork(role, account)
if err != nil {
panic(fmt.Errorf("setting up network: %w", err))
}
funder := setupFunder(contractBackend, account.Account, assetholder)
cl, err := client.New(cfg.addrs[role], bus, funder, adjudicator, wallet)
if err != nil {
panic(fmt.Errorf("creating client: %w", err))
}
// Create the node that defines all event handlers for go-perun.
node := &node{role: role, account: account, transactor: transactor,
contractBackend: contractBackend, assetholder: assetholder, listener: listener,
bus: bus, client: cl, ch: nil, done: make(chan struct{})}
// Set the NewChannel handler.
cl.OnNewChannel(node.HandleNewChannel)
// Start Proposal- and UpdateHandlers.
go cl.Handle(node, node)
// Listen on incoming connections.
go bus.Listen(listener)
return node
}
Running the App¶
Now we can finally test if everything works together.
First start your local Ethereum blockchain specifying the block time, the number of accounts, and the mnemonic:
ganache-cli -b 5 -a 2 -m "pistol kiwi shrug future ozone ostrich match remove crucial oblige cream critic"
The chain is running when you see an output like this:
Ganache CLI v6.12.1 (ganache-core: 2.13.1)
Available Accounts
==================
(0) 0x2EE1ac154435f542ECEc55C5b0367650d8A5343B (100 ETH)
(1) 0x70765701b79a4e973dAbb4b30A72f5a845f22F9E (100 ETH)
Private Keys
==================
(0) 0xb691bc22c5a30f64876c6136553023d522dcdf0744306dccf4f034a465532e27
(1) 0xb5dc82fc5f4d82b59a38ac963a15eaaedf414f496a037bb4a52310915ac84097
HD Wallet
==================
Mnemonic: pistol kiwi shrug future ozone ostrich match remove crucial oblige cream critic
Base HD Path: m/44'/60'/0'/0/{account_index}
Gas Price
==================
20000000000
Gas Limit
==================
6721975
Call Gas Limit
==================
9007199254740991
Listening on 127.0.0.1:8545
You can see Alice’ and Bobs addresses starting with 0x2EE… and 0x707… having both 100 ETH.
Now run the tutorial application via the following command:
go run .
If everything works, you should see the following output:
Starting Alice
Deployed contracts
Adjudicator at 0x079557d7549d7D44F4b00b51d2C532674129ed51
AssetHolder at 0x923439be515b6A928cB9650d70000a9044e49E85
Setting up listener for 0.0.0.0:8401
Starting Bob
Validated contracts
Adjudicator at 0x079557d7549d7D44F4b00b51d2C532674129ed51
AssetHolder at 0x923439be515b6A928cB9650d70000a9044e49E85
Setting up listener for 0.0.0.0:8402
Opening channel from Bob to Alice
Received channel proposal from 0x307837303736353730316237396134653937336441626234623330413732663561383435663232463945
Alice HandleNewChannel with id 0x644eba7aca469e34229de7b7f0ce12f31ef4bc30f17a35a7d95412e2d64296d0
Accepted channel with id 0x644eba7aca469e34229de7b7f0ce12f31ef4bc30f17a35a7d95412e2d64296d0
Bob HandleNewChannel with id 0x644eba7aca469e34229de7b7f0ce12f31ef4bc30f17a35a7d95412e2d64296d0
🎉 Opened channel with id 0x644eba7aca469e34229de7b7f0ce12f31ef4bc30f17a35a7d95412e2d64296d0
Alice HandleUpdate Bals=[15000000000000000000, 5000000000000000000]
HandleAdjudicatorEvent called id=0x644eba7aca469e34229de7b7f0ce12f31ef4bc30f17a35a7d95412e2d64296d0
HandleAdjudicatorEvent called id=0x644eba7aca469e34229de7b7f0ce12f31ef4bc30f17a35a7d95412e2d64296d0
Waiting for Alice
Waiting for Bob
Warning
The ganache-cli window will output the two deploy transactions. The first for ~2M gas is the Adjudicator
Transaction: 0xe3b4e79293d042e264224fe64f1028e4a1c7da02ba8d63f9a125081479e83d2f
Contract created: 0x079557d7549d7d44f4b00b51d2c532674129ed51
Gas usage: 2090042
Block Number: 1
Block Time: Wed Jan 13 2021 16:40:28 GMT+0100 (Central European Standard Time)
and then the AssetHolder for ~870K gas
Transaction: 0x1fb382d4640a1fa986a1d2c6451dfbcb5d86bd00ac05bc0a091294c002fb0c09
Contract created: 0x923439be515b6a928cb9650d70000a9044e49e85
Gas usage: 870103
Block Number: 2
Block Time: Wed Jan 13 2021 16:40:29 GMT+0100 (Central European Standard Time)
Note
The transactions are really quick on the local chain. On a testnet or main-chain each transaction would take about 15 seconds.