Invoking Smart Contracts
Invoking a Smart Contract's entry point in Solo looks like the following:
req := solo.NewCallParams("example1", "storeString", "paramString", "Hello, world!").WithIotas(1)
_, err = chain.PostRequestSync(req, nil)
In the example
TestTutorial3 we invoke the
storeString entry point of the
example1 smart contract by posting it as a request. The parameter
paramString is passed with the string value "Hello, world!". The Solo
test code itself is separate from the chain where the smart contract is invoked and is not executed "on-chain".
NewCallParams creates a call object named
req which wraps all call
parameters into a single object. This is syntactic sugar just for convenience.
In this case, the call object only wraps the target smart contract name, target
entry point name, and one named parameter
paramString. In other cases it could
contain many parameters.
WithIotas attaches a single iota with the request. All
are implemented as value transactions with additional data, and therefore we
need to transfer at least a single token for the request to be valid.
PostRequestSync sends the request to the chain. Let’s describe in detail what
is going on here.
The diagram above depicts the generic process of posting an
on-ledger request to the smart
contract. The same picture is valid for the Solo environment and for any other
requester which sends an
on-ledger request to the smart contract, for example, the IOTA Smart Contracts
wallet or another chain.
Posting the request always consists of the steps below. Note that in Solo all 7
steps are carried out by the single call to
- Creating the smart contract transaction which wraps the request with metadata
and moves tokens. Each request transaction is a value transaction, it always
moves at least one token. Therefore, each request transaction must be signed
by the private key of the owner of the tokens: the requester. That securely
identifies each requester in IOTA Smart Contracts. In Solo, the transaction is signed by the
private key provided in the second parameter of the
PostRequestSynccall (see below).
- Posting the request transaction to the Tangle and confirming it. In Solo it
is just adding the transaction to the
UTXODB ledger, the emulated UTXO Ledger, so it is confirmed immediately and synchronously. The confirmed transaction on the ledger becomes part of the backlog of requests to the chain. In the real UTXO Ledger the sender would have to wait until the ledger confirms the transaction.
- The chain picks the request from the backlog and runs the request on the VM.
- The VM calls the target entry point of the smart contract program. The program updates the state.
- The VM produces a state update transaction (the
- The chain signs the transaction with its private key. In the Solo
environment is the
ChainSigSchemeproperty of the chain. In the real Wasp environment it is the threshold signature of the committee of validator nodes.
- The chain posts the resulting transaction to the Tangle and, after confirmation, solidifies the corresponding state. In the Solo environment it adds the transaction to the UTXODB ledger.
The following lines in the log correspond to step 7:
54:43.809 INFO TestTutorial3.ex3 vmcontext/runreq.go:311 eventlog -> '[req] CHvU6BUDgt9MZJTxsYMZ1p1veg591mvwKGQBJd2KYdaB: Ok'
54:43.809 INFO TestTutorial3 solo/clock.go:35 AdvanceClockBy: logical clock advanced by 2ns
54:43.809 INFO TestTutorial3.ex3.m mempool/mempool.go:119 OUT MEMPOOL CHvU6BUDgt9MZJTxsYMZ1p1veg591mvwKGQBJd2KYdaB
54:43.809 INFO TestTutorial3.ex3 solo/run.go:86 state transition #2 --> #3. Requests in the block: 1. Outputs: 1
The chain adds a record about any successfully processed request
CHvU6BUDgt9MZJTxsYMZ1p1veg591mvwKGQBJd2KYdaB to the immutable on-chain log.
_, err = chain.PostRequestSync(req, nil) in the Solo test uses
for the default signature scheme of the requester. The
the one which deployed the chain, is used as the default requester. In the
Solo environment you can create other identities for requesters (“wallets”)
Alternatively, in the example above, we could send an off-ledger request by using
chain.PostRequestOffLedger instead of
However, to be able to submit off-ledger request, the account sending the request must deposit funds to the chain beforehand.
wallet, address := env.NewKeyPairWithFunds()
AgentID := iscp.NewAgentID(ownerAddr, 0)
// deposit into the account
req := solo.NewCallParams(accounts.Contract.Name, accounts.FuncDeposit.Name).WithIotas(100)
_, err := chain.PostRequestSync(req, owner)
//no .WithIotas() needed, fees will be deducted from the sender on-chain account
req := solo.NewCallParams("example1", "storeString", "paramString", "Hello, world!")
_, err = chain.PostRequestOffLedger(req, wallet)