|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "encoding/hex" |
| 6 | + "encoding/json" |
| 7 | + "fmt" |
| 8 | + "log" |
| 9 | + "math/big" |
| 10 | + "math/rand" |
| 11 | + "strconv" |
| 12 | + "time" |
| 13 | + |
| 14 | + "C" |
| 15 | + |
| 16 | + "github.com/ethereum/go-ethereum" |
| 17 | + "github.com/ethereum/go-ethereum/common" |
| 18 | + "github.com/ethereum/go-ethereum/core/types" |
| 19 | + "github.com/sambacha/dgeth/simulator" |
| 20 | +) |
| 21 | + |
| 22 | +type TransactionRequest struct { |
| 23 | + To *string `json:"to"` |
| 24 | + From *string `json:"from"` |
| 25 | + Nonce *string `json:"nonce"` |
| 26 | + |
| 27 | + GasLimit *string `json:"gasLimit"` |
| 28 | + GasPrice *string `json:"gasPrice"` |
| 29 | + |
| 30 | + Data *string `json:"data"` |
| 31 | + Value *string `json:"value"` |
| 32 | + ChainId *uint64 `json:"chainId"` |
| 33 | +} |
| 34 | + |
| 35 | +func main() {} |
| 36 | + |
| 37 | +var ( |
| 38 | + simulators = make(map[int]*simulator.Simulator) |
| 39 | + nextSimulatorID = 0 |
| 40 | +) |
| 41 | + |
| 42 | +//export newSimulator |
| 43 | +func newSimulator() C.int { |
| 44 | + sim, err := simulator.NewSimulator() |
| 45 | + if err != nil { |
| 46 | + log.Fatal(err) |
| 47 | + } |
| 48 | + id := nextSimulatorID |
| 49 | + simulators[id] = sim |
| 50 | + nextSimulatorID++ |
| 51 | + return C.int(id) |
| 52 | +} |
| 53 | + |
| 54 | +//export getBlockNumber |
| 55 | +func getBlockNumber(simID C.int) *C.char { |
| 56 | + sim := getSimulator(simID) |
| 57 | + bn := sim.GetLatestBlockNumber() |
| 58 | + return C.CString(bn.String()) |
| 59 | +} |
| 60 | + |
| 61 | +//export getCode |
| 62 | +func getCode(simID C.int, account *C.char) *C.char { |
| 63 | + sim := getSimulator(simID) |
| 64 | + code, err := sim.Backend.CodeAt(context.Background(), common.HexToAddress(C.GoString(account)), nil) |
| 65 | + if err != nil { |
| 66 | + log.Fatal(err) |
| 67 | + } |
| 68 | + |
| 69 | + return C.CString(common.Bytes2Hex(code)) |
| 70 | +} |
| 71 | + |
| 72 | +//export getChainID |
| 73 | +func getChainID(simID C.int) *C.char { |
| 74 | + sim := getSimulator(simID) |
| 75 | + bn := sim.GetChainID() |
| 76 | + return C.CString(bn.String()) |
| 77 | +} |
| 78 | + |
| 79 | +//export getBalance |
| 80 | +func getBalance(simID C.int, account *C.char) *C.char { |
| 81 | + sim := getSimulator(simID) |
| 82 | + bal, err := sim.Backend.BalanceAt(context.Background(), common.HexToAddress(C.GoString(account)), nil) |
| 83 | + if err != nil { |
| 84 | + log.Fatal(err) |
| 85 | + } |
| 86 | + |
| 87 | + return C.CString(bal.String()) |
| 88 | +} |
| 89 | + |
| 90 | +//export getTransactionCount |
| 91 | +func getTransactionCount(simID C.int, account *C.char) C.int { |
| 92 | + sim := getSimulator(simID) |
| 93 | + count, err := sim.Backend.NonceAt(context.Background(), common.HexToAddress(C.GoString(account)), nil) |
| 94 | + if err != nil { |
| 95 | + log.Fatal(err) |
| 96 | + } |
| 97 | + |
| 98 | + return C.int(count) |
| 99 | +} |
| 100 | + |
| 101 | +//export getLogs |
| 102 | +func getLogs(simID C.int, queryJson *C.char) *C.char { |
| 103 | + sim := getSimulator(simID) |
| 104 | + |
| 105 | + var query ethereum.FilterQuery |
| 106 | + |
| 107 | + err := json.Unmarshal([]byte(C.GoString(queryJson)), &query) |
| 108 | + if err != nil { |
| 109 | + log.Fatal(err) |
| 110 | + } |
| 111 | + |
| 112 | + logs, err := sim.Backend.FilterLogs(context.Background(), query) |
| 113 | + |
| 114 | + if err != nil { |
| 115 | + log.Fatal(err) |
| 116 | + } |
| 117 | + |
| 118 | + logsJson, err := json.Marshal(logs) |
| 119 | + return C.CString(string(logsJson)) |
| 120 | +} |
| 121 | + |
| 122 | +//export call |
| 123 | +func call(simID C.int, msgJson *C.char) *C.char { |
| 124 | + sim := getSimulator(simID) |
| 125 | + var msg TransactionRequest |
| 126 | + |
| 127 | + err := json.Unmarshal([]byte(C.GoString(msgJson)), &msg) |
| 128 | + if err != nil { |
| 129 | + log.Fatal(err) |
| 130 | + } |
| 131 | + |
| 132 | + var callMsg ethereum.CallMsg |
| 133 | + |
| 134 | + if msg.From != nil { |
| 135 | + callMsg.From = common.HexToAddress(*msg.From) |
| 136 | + } |
| 137 | + if msg.To != nil { |
| 138 | + temp := common.HexToAddress(*msg.To) |
| 139 | + callMsg.To = &temp |
| 140 | + } |
| 141 | + if msg.GasLimit != nil { |
| 142 | + value, err := strconv.ParseUint(*msg.GasLimit, 16, 64) |
| 143 | + if err != nil { |
| 144 | + log.Fatal(err) |
| 145 | + } |
| 146 | + |
| 147 | + callMsg.Gas = value |
| 148 | + } |
| 149 | + if msg.GasPrice != nil { |
| 150 | + callMsg.GasPrice = big.NewInt(0) |
| 151 | + callMsg.GasPrice.SetString(*msg.GasPrice, 16) |
| 152 | + } |
| 153 | + if msg.Data != nil { |
| 154 | + data, err := hex.DecodeString((*msg.Data)[2:]) |
| 155 | + if err != nil { |
| 156 | + log.Fatal(err) |
| 157 | + } |
| 158 | + |
| 159 | + callMsg.Data = data |
| 160 | + } |
| 161 | + |
| 162 | + res, err := sim.Backend.CallContract(context.Background(), callMsg, nil) |
| 163 | + if err != nil { |
| 164 | + log.Fatal(err) |
| 165 | + } |
| 166 | + |
| 167 | + return C.CString(hex.EncodeToString(res)) |
| 168 | +} |
| 169 | + |
| 170 | +type txReceipt struct { |
| 171 | + Tx *types.Transaction |
| 172 | + IsPending bool |
| 173 | +} |
| 174 | + |
| 175 | +//export getTransaction |
| 176 | +func getTransaction(simID C.int, txHash *C.char) *C.char { |
| 177 | + sim := getSimulator(simID) |
| 178 | + |
| 179 | + hash := common.HexToHash(C.GoString(txHash)) |
| 180 | + tx, isPending, err := sim.Backend.SimulatedBackend.TransactionByHash(context.Background(), hash) |
| 181 | + if err != nil { |
| 182 | + log.Fatal(err) |
| 183 | + } |
| 184 | + |
| 185 | + stringified, err := json.Marshal(txReceipt{Tx: tx, IsPending: isPending}) |
| 186 | + if err != nil { |
| 187 | + log.Fatal(err) |
| 188 | + } |
| 189 | + |
| 190 | + return C.CString(string(stringified[:])) |
| 191 | +} |
| 192 | + |
| 193 | +//export sendTransaction |
| 194 | +func sendTransaction(simID C.int, txData *C.char) *C.char { |
| 195 | + sim := getSimulator(simID) |
| 196 | + |
| 197 | + bytes, err := hex.DecodeString(C.GoString(txData)[2:]) |
| 198 | + if err != nil { |
| 199 | + log.Fatal(err) |
| 200 | + } |
| 201 | + |
| 202 | + tx := &types.Transaction{} |
| 203 | + err = tx.UnmarshalBinary(bytes) |
| 204 | + if err != nil { |
| 205 | + log.Fatal(err) |
| 206 | + } |
| 207 | + |
| 208 | + err = sim.Backend.SimulatedBackend.SendTransaction(context.Background(), tx) |
| 209 | + if err != nil { |
| 210 | + log.Fatal(err) |
| 211 | + } |
| 212 | + |
| 213 | + sim.Backend.Commit() |
| 214 | + |
| 215 | + receipt, err := sim.Backend.SimulatedBackend.TransactionReceipt(context.Background(), tx.Hash()) |
| 216 | + if err != nil { |
| 217 | + log.Fatal(err) |
| 218 | + } |
| 219 | + |
| 220 | + receiptJson, err := json.Marshal(receipt) |
| 221 | + if err != nil { |
| 222 | + log.Fatal(err) |
| 223 | + } |
| 224 | + |
| 225 | + return C.CString(string(receiptJson)) |
| 226 | +} |
| 227 | + |
| 228 | +func getSimulator(simID C.int) *simulator.Simulator { |
| 229 | + id := int(simID) |
| 230 | + sim, ok := simulators[id] |
| 231 | + if !ok { |
| 232 | + log.Fatal(fmt.Errorf("simulator with %d does not exist", id)) |
| 233 | + } |
| 234 | + return sim |
| 235 | +} |
| 236 | + |
| 237 | +//export cgoCurrentMillis |
| 238 | +func cgoCurrentMillis() C.long { |
| 239 | + return C.long(time.Now().Unix()) |
| 240 | +} |
| 241 | + |
| 242 | +//export cgoSeed |
| 243 | +func cgoSeed(m C.long) { |
| 244 | + rand.Seed(int64(m)) |
| 245 | +} |
| 246 | + |
| 247 | +//export cgoRandom |
| 248 | +func cgoRandom(m C.int) C.int { |
| 249 | + return C.int(rand.Intn(int(m))) |
| 250 | +} |
0 commit comments