You can totally simulated the transaction througth eth_call.
Her are the code snippets of eth_call and apply transaction (source from go-ethereum):
eth_call (could not change state)
// Setup the gas pool (also for unmetered requests)
// and apply the message.
gp := new(core.GasPool).AddGas(math.MaxUint64)
res, gas, failed, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil {
return nil, 0, false, err
}
return res, gas, failed, err
apply transaction (could update state)
_, gas, failed, err := ApplyMessage(vmenv, msg, gp)
if err != nil {
return nil, 0, err
}
// Update the state with pending changes
var root []byte
if config.IsByzantium(header.Number) {
statedb.Finalise(true)
} else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
}
Remember to return the result of simulation when you use eth_call
.
The solidity function looks like:
function simulation() pure public returns(bool result) {
result = doSimulation();
}