141 lines
4.8 KiB
Go
141 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"math/big"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/ethereum/go-ethereum/abi"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
)
|
|
|
|
// SimpleStorage 是从 Solidity 合约生成的绑定。
|
|
type SimpleStorage struct {
|
|
*bind.BoundContract
|
|
}
|
|
|
|
// NewSimpleStorage 创建一个与 SimpleStorage 合约绑定的新实例。
|
|
func NewSimpleStorage(address common.Address, backend bind.ContractBackend) (*SimpleStorage, error) {
|
|
parsed, err := abi.JSON(strings.NewReader(simpleStorageABI))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
contract := bind.NewBoundContract(address, parsed, backend, backend, backend)
|
|
return &SimpleStorage{contract}, nil
|
|
}
|
|
|
|
// Set 调用合约的 set 方法。
|
|
func (s *SimpleStorage) Set(opts *bind.TransactOpts, key string, value *big.Int) (*types.Transaction, error) {
|
|
return s.Transact(opts, "set", key, value)
|
|
}
|
|
|
|
// Get 调用合约的 get 方法。
|
|
func (s *SimpleStorage) Get(opts *bind.CallOpts, key string) (*big.Int, error) {
|
|
var res []interface{}
|
|
err := s.Call(opts, &res, "get", key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
decoded, ok := res[0].(*big.Int)
|
|
if !ok {
|
|
return nil, fmt.Errorf("failed to decode result")
|
|
}
|
|
return decoded, nil
|
|
}
|
|
|
|
var simpleStorageABI = `[{"constant":false,"inputs":[{"name":"key","type":"string"},{"name":"value","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"key","type":"string"}],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]`
|
|
var simpleStorageBytecode = "0x608060405234801561001057600080fd5b5060c08061001f6000396000f3fe60806040526004361061004e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d14610053575b600080fd5b34801561005f57600080fd5b5061006c600480360381019080803590602001909291905050506100a2565b6040518082815260200191505060405180910390f35b60008160008190555056fea26469706673582212209c6b1e4d375b6083c4d98b45a74086c425c7f89f2f0f8e0f40d1b28b1dfb3d4664736f6c634300080a0033"
|
|
|
|
var contractAddress = common.HexToAddress("0x5FbDB2315678afecb367f032d93F642f64180aa3") // 替换为实际的合约地址
|
|
|
|
func main() {
|
|
// 使用 WebSocket 连接到本地运行的 Geth 实例
|
|
rpcClient, err := rpc.Dial("ws://localhost:8546")
|
|
if err != nil {
|
|
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
|
|
}
|
|
defer rpcClient.Close()
|
|
|
|
client := ethclient.NewClient(rpcClient)
|
|
|
|
// 生成一个新的随机账户
|
|
privateKey, err := crypto.GenerateKey()
|
|
if err != nil {
|
|
log.Fatalf("Failed to generate private key: %v", err)
|
|
}
|
|
publicKey := privateKey.Public()
|
|
|
|
// publicKeyECDSA 已删除,因为未使用
|
|
|
|
fromAddress := crypto.PubkeyToAddress(publicKey.(ecdsa.PublicKey))
|
|
|
|
// 创建交易选项
|
|
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337))
|
|
if err != nil {
|
|
log.Fatalf("Failed to create transactor: %v", err)
|
|
}
|
|
auth.Nonce = big.NewInt(0) // 设置初始 nonce
|
|
auth.Value = big.NewInt(0) // 没有转账价值
|
|
auth.GasLimit = uint64(300000) // 设置 gas limit
|
|
auth.GasPrice = big.NewInt(1) // 设置 gas 价格
|
|
|
|
// 创建合约实例
|
|
instance, err := NewSimpleStorage(contractAddress, client)
|
|
if err != nil {
|
|
log.Fatalf("Failed to instantiate contract: %v", err)
|
|
}
|
|
|
|
http.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
|
|
valueStr := r.URL.Query().Get("value")
|
|
key := r.URL.Query().Get("key")
|
|
if valueStr == "" || key == "" {
|
|
http.Error(w, "Missing 'value' or 'key' parameter", http.StatusBadRequest)
|
|
return
|
|
}
|
|
value, ok := new(big.Int).SetString(valueStr, 10)
|
|
if !ok {
|
|
http.Error(w, "Invalid 'value' parameter", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
tx, err := instance.Set(auth, key, value)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to set value: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
fmt.Fprintf(w, "Transaction sent: %s\n", tx.Hash().Hex())
|
|
})
|
|
|
|
http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
|
|
key := r.URL.Query().Get("key")
|
|
if key == "" {
|
|
http.Error(w, "Missing 'key' parameter", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
value, err := instance.Get(&bind.CallOpts{}, key)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to get value: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"key": key,
|
|
"value": value,
|
|
})
|
|
})
|
|
|
|
log.Println("Starting server on :8081...")
|
|
if err := http.ListenAndServe(":8081", nil); err != nil {
|
|
log.Fatalf("Failed to start server: %v", err)
|
|
}
|
|
}
|