forked from CyberMiles/travis
-
Notifications
You must be signed in to change notification settings - Fork 3
/
txs.go
145 lines (125 loc) · 4.2 KB
/
txs.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
package api
import (
"bytes"
"math/big"
"time"
"github.com/pkg/errors"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
rpcClient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/CyberMiles/travis/utils"
)
const defaultGas = 90000
// SendTxArgs represents the arguments to sumbit a new transaction
type SendTxArgs struct {
From common.Address `json:"from"`
To *common.Address `json:"to"`
Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
// newer name and should be preferred by clients.
Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"`
}
// prepareSendTxArgs is a helper function that fills in default values for unspecified tx fields.
func (args *SendTxArgs) setDefaults(b *Backend) error {
if args.Gas == nil {
args.Gas = new(hexutil.Uint64)
*(*uint64)(args.Gas) = defaultGas
}
if args.GasPrice == nil {
price := utils.GetParams().GasPrice
args.GasPrice = (*hexutil.Big)(new(big.Int).SetUint64(price))
}
if args.Value == nil {
args.Value = new(hexutil.Big)
}
if args.Nonce == nil {
nonce := b.ManagedState().GetNonce(args.From)
args.Nonce = (*hexutil.Uint64)(&nonce)
}
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
return errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`)
}
if args.To == nil {
// Contract creation
var input []byte
if args.Data != nil {
input = *args.Data
} else if args.Input != nil {
input = *args.Input
}
if len(input) == 0 {
return errors.New(`contract creation without any data provided`)
}
}
return nil
}
func (args *SendTxArgs) toTransaction() *ethTypes.Transaction {
var input []byte
if args.Data != nil {
input = *args.Data
} else if args.Input != nil {
input = *args.Input
}
if args.To == nil {
return ethTypes.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
}
return ethTypes.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
}
// BroadcastTx broadcasts a transaction to tendermint core
// #unstable
func (b *Backend) BroadcastTxSync(tx *ethTypes.Transaction) (*ctypes.ResultBroadcastTx, error) {
buf := new(bytes.Buffer)
if err := tx.EncodeRLP(buf); err != nil {
return nil, err
}
return b.GetLocalClient().BroadcastTxSync(buf.Bytes())
}
func (b *Backend) BroadcastTxCommit(tx *ethTypes.Transaction) (*ctypes.ResultBroadcastTxCommit, error) {
buf := new(bytes.Buffer)
if err := tx.EncodeRLP(buf); err != nil {
return nil, err
}
return b.GetLocalClient().BroadcastTxCommit(buf.Bytes())
}
// signTransaction sets defaults and signs the given transaction
// NOTE: the caller needs to ensure that the nonceLock is held, and release it after use.
func (b *Backend) signTransaction(args *SendTxArgs) (*ethTypes.Transaction, error) {
// Look up the wallet containing the requested signer
account := accounts.Account{Address: args.From}
// Set some sanity defaults and terminate on failure
if err := args.setDefaults(b); err != nil {
return nil, err
}
// Assemble the transaction and sign with the wallet
tx := args.toTransaction()
wallet, err := b.ethereum.AccountManager().Find(account)
if err != nil {
return nil, err
}
ethChainId := int64(b.ethConfig.NetworkId)
signed, err := wallet.SignTx(account, tx, big.NewInt(ethChainId))
if err != nil {
return nil, err
}
return signed, nil
}
//----------------------------------------------------------------------
// wait for Tendermint to open the socket and run http endpoint
func waitForServer(c *rpcClient.Local) {
for {
_, err := c.Status()
if err == nil {
break
}
log.Info("Waiting for tendermint endpoint to start", "err", err)
time.Sleep(time.Second * 3)
}
}