/
utils.go
152 lines (132 loc) · 4.35 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package ethtxs
import (
"context"
"crypto/ecdsa"
"errors"
"math/big"
"sync"
"time"
"github.com/33cn/plugin/plugin/dapp/x2ethereum/ebrelayer/ethinterface"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
)
//EthTxStatus ...
type EthTxStatus int32
type nonceMutex struct {
nonce int64
rw *sync.RWMutex
}
var addr2Nonce = make(map[common.Address]nonceMutex)
//String ...
func (ethTxStatus EthTxStatus) String() string {
return [...]string{"Fail", "Success", "Pending"}[ethTxStatus]
}
//const
const (
PendingDuration4TxExeuction = 300
EthTxPending = EthTxStatus(2)
)
//SignClaim4Eth ...
func SignClaim4Eth(hash common.Hash, privateKey *ecdsa.PrivateKey) ([]byte, error) {
rawSignature, _ := prefixMessage(hash, privateKey)
signature := hexutil.Bytes(rawSignature)
return signature, nil
}
func prefixMessage(message common.Hash, key *ecdsa.PrivateKey) ([]byte, []byte) {
//只是为保留代码在此处
//prefixed := utils.SoliditySHA3WithPrefix(message[:])
var prefixed []byte
sig, err := secp256k1.Sign(prefixed, math.PaddedBigBytes(key.D, 32))
if err != nil {
panic(err)
}
return sig, prefixed
}
func getNonce(sender common.Address, client ethinterface.EthClientSpec) (*big.Int, error) {
if nonceMutex, exist := addr2Nonce[sender]; exist {
nonceMutex.rw.Lock()
defer nonceMutex.rw.Unlock()
nonceMutex.nonce++
addr2Nonce[sender] = nonceMutex
txslog.Debug("getNonce from cache", "address", sender.String(), "nonce", nonceMutex.nonce)
return big.NewInt(nonceMutex.nonce), nil
}
nonce, err := client.PendingNonceAt(context.Background(), sender)
if nil != err {
return nil, err
}
txslog.Debug("getNonce", "address", sender.String(), "nonce", nonce)
n := new(nonceMutex)
n.nonce = int64(nonce)
n.rw = new(sync.RWMutex)
addr2Nonce[sender] = *n
return big.NewInt(int64(nonce)), nil
}
func revokeNonce(sender common.Address) (*big.Int, error) {
if nonceMutex, exist := addr2Nonce[sender]; exist {
nonceMutex.rw.Lock()
defer nonceMutex.rw.Unlock()
nonceMutex.nonce--
addr2Nonce[sender] = nonceMutex
txslog.Debug("revokeNonce", "address", sender.String(), "nonce", nonceMutex.nonce)
return big.NewInt(nonceMutex.nonce), nil
}
return nil, errors.New("address doesn't exist tx")
}
//PrepareAuth ...
func PrepareAuth(client ethinterface.EthClientSpec, privateKey *ecdsa.PrivateKey, transactor common.Address) (*bind.TransactOpts, error) {
if nil == privateKey || nil == client {
txslog.Error("PrepareAuth", "nil input parameter", "client", client, "privateKey", privateKey)
return nil, errors.New("nil input parameter")
}
ctx := context.Background()
gasPrice, err := client.SuggestGasPrice(ctx)
if err != nil {
txslog.Error("PrepareAuth", "Failed to SuggestGasPrice due to:", err.Error())
return nil, errors.New("failed to get suggest gas price")
}
auth := bind.NewKeyedTransactor(privateKey)
auth.Value = big.NewInt(0) // in wei
auth.GasLimit = GasLimit4Deploy
auth.GasPrice = gasPrice
if auth.Nonce, err = getNonce(transactor, client); err != nil {
return nil, err
}
return auth, nil
}
func waitEthTxFinished(client ethinterface.EthClientSpec, txhash common.Hash, txName string) error {
txslog.Info(txName, "Wait for tx to be finished executing with hash", txhash.String())
timeout := time.NewTimer(PendingDuration4TxExeuction * time.Second)
oneSecondtimeout := time.NewTicker(5 * time.Second)
for {
select {
case <-timeout.C:
return errors.New("eth tx timeout")
case <-oneSecondtimeout.C:
_, err := client.TransactionReceipt(context.Background(), txhash)
if err == ethereum.NotFound {
continue
} else if err != nil {
return err
}
txslog.Info(txName, "Finished executing for tx", txhash.String())
return nil
}
}
}
//GetEthTxStatus ...
func GetEthTxStatus(client ethinterface.EthClientSpec, txhash common.Hash) string {
receipt, err := client.TransactionReceipt(context.Background(), txhash)
if nil != err {
return EthTxPending.String()
}
status := EthTxStatus(receipt.Status).String()
if status != EthTxPending.String() {
txslog.Info("GetEthTxStatus", "Eth tx hash", txhash.String(), "status", status, "BlockNum", receipt.BlockNumber.Int64())
}
return status
}