Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
multisend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
李伟@五瓣科技
multisend
Commits
5176ae54
Commit
5176ae54
authored
Feb 23, 2022
by
李伟@五瓣科技
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
heco mainnet
parent
e1aadc97
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
287 additions
and
148 deletions
+287
-148
buildTx.go
buildTx.go
+33
-0
client_eth.go
client_eth.go
+70
-141
originalTx.go
originalTx.go
+152
-0
originalTx_test.go
originalTx_test.go
+11
-0
transactor.go
transactor.go
+5
-1
transactor_test.go
transactor_test.go
+16
-6
No files found.
buildTx.go
0 → 100644
View file @
5176ae54
package
multisend
import
(
"crypto/ecdsa"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
func
buildSendTx
(
nonce
uint64
,
to
common
.
Address
,
amount
*
big
.
Int
,
gasLimit
uint64
,
gasPrice
*
big
.
Int
,
data
[]
byte
,
chainId
*
big
.
Int
,
privateKey
*
ecdsa
.
PrivateKey
)
(
*
types
.
Transaction
,
error
)
{
return
buildTx
(
nonce
,
to
,
amount
,
gasLimit
,
gasPrice
,
data
,
chainId
,
privateKey
)
}
func
buildOriginalTx
(
nonce
uint64
,
to
common
.
Address
,
chainId
*
big
.
Int
,
privateKey
*
ecdsa
.
PrivateKey
)
(
*
types
.
Transaction
,
error
)
{
return
buildTx
(
nonce
,
to
,
big
.
NewInt
(
int64
(
nonce
)),
0
,
big
.
NewInt
(
0
),
nil
,
chainId
,
privateKey
)
}
func
buildTx
(
nonce
uint64
,
to
common
.
Address
,
amount
*
big
.
Int
,
gasLimit
uint64
,
gasPrice
*
big
.
Int
,
data
[]
byte
,
chainId
*
big
.
Int
,
privateKey
*
ecdsa
.
PrivateKey
)
(
*
types
.
Transaction
,
error
)
{
tx
:=
types
.
NewTransaction
(
nonce
,
to
,
amount
,
gasLimit
,
gasPrice
,
data
)
if
privateKey
!=
nil
{
signedTx
,
err
:=
types
.
SignTx
(
tx
,
types
.
NewEIP155Signer
(
chainId
),
privateKey
)
if
err
!=
nil
{
return
nil
,
err
}
tx
=
signedTx
}
return
tx
,
nil
}
client_eth.go
View file @
5176ae54
...
...
@@ -3,48 +3,48 @@ package multisend
import
(
"context"
"crypto/ecdsa"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"github.com/go-redis/redis/v8"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"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"
)
var
p
rivatekey
string
=
"a1994419e9b06a7b27e8d094840ae26a6b7806633bb8be55a1a835f1620d8cec"
var
toAddress
common
.
Address
=
common
.
HexToAddress
(
"0x
4592d8f8d7b001e72cb26a73e4fa1806a51ac79d
"
)
var
sendTxP
rivatekey
string
=
"a1994419e9b06a7b27e8d094840ae26a6b7806633bb8be55a1a835f1620d8cec"
var
toAddress
common
.
Address
=
common
.
HexToAddress
(
"0x
0071B39fd266F8aeF392fb50F078A233b2218a0b
"
)
var
data
[]
byte
=
make
([]
byte
,
0
,
md5
.
Size
*
(
3
))
// func RegisterBuildTxParam(name string, factory Param) error {
// if _, exists := buildTxPrama[name]; exists {
// return fmt.Errorf("source param with the specified name already exists: %s", name)
// }
// buildTxPrama[name] = factory
// return nil
// }
func
init
()
{
privatekey
=
"a1994419e9b06a7b27e8d094840ae26a6b7806633bb8be55a1a835f1620d8cec"
for
i
:=
0
;
i
<
3
;
i
++
{
hash
:=
md5
.
Sum
([]
byte
(
fmt
.
Sprintf
(
"%d"
,
i
)))
data
=
append
(
data
,
hash
[
:
]
...
)
if
err
:=
RegisterClientFactory
(
"ethclient"
,
NewEthClientFactory
());
err
!=
nil
{
panic
(
err
)
}
}
type
EthClientFactory
struct
{}
type
EthClient
struct
{
NodeRpcURL
string
PrivateKey
*
ecdsa
.
PrivateKey
FromAddr
common
.
Address
NodeUrl
string
Nonce
uint64
GasPrice
*
big
.
Int
ChainId
*
big
.
Int
GasLimit
uint64
}
var
_
ClientFactory
=
(
*
EthClientFactory
)(
nil
)
var
_
Client
=
(
*
EthClient
)(
nil
)
func
init
()
{
if
err
:=
RegisterClientFactory
(
"ethclient"
,
NewEthClientFactory
());
err
!=
nil
{
panic
(
err
)
}
}
func
NewEthClientFactory
()
*
EthClientFactory
{
return
&
EthClientFactory
{}
}
...
...
@@ -54,155 +54,84 @@ func (f *EthClientFactory) ValidateConfig(cfg Config) error {
}
func
(
f
*
EthClientFactory
)
NewClient
(
cfg
Config
)
(
Client
,
error
)
{
return
&
EthClient
{
NodeRpcURL
:
"http://13.40.31.153:8545"
,
},
nil
}
func
(
c
*
EthClient
)
GenerateTx
()
(
*
types
.
Transaction
,
error
)
{
privateKeyAsECDSA
,
err
:=
crypto
.
HexToECDSA
(
p
rivatekey
)
sendTxPrivatekeyAsECDSA
,
err
:=
crypto
.
HexToECDSA
(
sendTxP
rivatekey
)
if
err
!=
nil
{
return
nil
,
err
panic
(
err
)
}
publicKey
:=
privateKeyAsECDSA
.
Public
()
publicKeyECDSA
,
ok
:=
publicKey
.
(
*
ecdsa
.
PublicKey
)
sendTxPublicKey
:=
sendTxPrivatekeyAsECDSA
.
Public
()
sendTxPublicKeyECDSA
,
ok
:=
sendTxPublicKey
.
(
*
ecdsa
.
PublicKey
)
if
!
ok
{
return
nil
,
fmt
.
Errorf
(
"publicKey.(*ecdsa.PublicKey) not ok"
)
panic
(
"publicKey.(*ecdsa.PublicKey) not ok"
)
}
fromAddress
:=
crypto
.
PubkeyToAddress
(
*
publicKeyECDSA
)
client
,
err
:=
ethclient
.
Dial
(
c
.
NodeRpcURL
)
if
err
!=
nil
{
return
nil
,
err
sendTxFromAddress
:=
crypto
.
PubkeyToAddress
(
*
sendTxPublicKeyECDSA
)
buildTxParam
:=
EthClient
{
PrivateKey
:
sendTxPrivatekeyAsECDSA
,
FromAddr
:
sendTxFromAddress
,
//NodeUrl: "http://13.40.31.153:8545",
//https://heco.getblock.io/mainnet/
//NodeUrl: "https://heco.getblock.io/mainnet/",
NodeUrl
:
"https://http-mainnet-node.huobichain.com"
,
}
nonce
,
err
:=
client
.
PendingNonceAt
(
context
.
Background
(),
fromAddress
)
cli
,
err
:=
ethclient
.
Dial
(
buildTxParam
.
NodeUrl
)
if
err
!=
nil
{
return
nil
,
err
panic
(
err
)
}
// gasPrice, err := client.SuggestGasPrice(context.Background())
// if err != nil {
// return nil, err
// }
// chainID, err := client.NetworkID(context.Background())
// if err != nil {
// return nil, err
// }
txs
,
md5data
,
err
:=
getBatchTx
(
3
,
c
.
NodeRpcURL
,
false
)
nonce
,
err
:=
cli
.
PendingNonceAt
(
context
.
Background
(),
buildTxParam
.
FromAddr
)
if
err
!=
nil
{
return
nil
,
err
panic
(
err
)
}
_
=
txs
// gasLimit, err := client.EstimateGas(context.Background(), ethereum.CallMsg{
// To: &toAddress,
// Data: md5data,
// })
//fmt.Printf("gasLimit: %d gasPrice: %d \n", gasLimit, gasPrice
)
tx
:=
types
.
NewTransaction
(
nonce
,
toAddress
,
big
.
NewInt
(
10000000000000
),
24894
,
big
.
NewInt
(
1000000000
),
md5data
)
//tx := types.NewTransaction(nonce, toAddress, big.NewInt(10000000000000), 24894, big.NewInt(1000000000), data)
gasPrice
,
err
:=
cli
.
SuggestGasPrice
(
context
.
Background
()
)
if
err
!=
nil
{
panic
(
err
)
}
signedTx
,
err
:=
types
.
SignTx
(
tx
,
types
.
NewEIP155Signer
(
big
.
NewInt
(
256
)),
privateKeyAsECDSA
)
ChainId
,
err
:=
cli
.
NetworkID
(
context
.
Background
()
)
if
err
!=
nil
{
return
nil
,
err
panic
(
err
)
}
return
signedTx
,
nil
}
type
Md5tx
struct
{
MD5
string
`json:md5`
Tx
*
types
.
Transaction
`json:tx`
buildTxParam
.
Nonce
=
nonce
buildTxParam
.
GasPrice
=
gasPrice
buildTxParam
.
ChainId
=
ChainId
return
&
buildTxParam
,
nil
}
var
ctx
=
context
.
Background
()
var
rdb
=
redis
.
NewClient
(
&
redis
.
Options
{
Addr
:
"54.250.115.98:6379"
,
Password
:
"redis20220217"
,
// no password set
DB
:
0
,
// use default DB
})
func
getBatchTx
(
txNum
int
,
nodeUrl
string
,
signed
bool
)
([]
Md5tx
,
[]
byte
,
error
)
{
res
:=
make
([]
Md5tx
,
0
,
txNum
)
md5Data
:=
make
([]
byte
,
0
,
md5
.
Size
*
(
txNum
))
//publicKey := privateKey.Public()
// publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
// if !ok {
// log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
// }
// fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
// cli, err := ethclient.Dial(nodeUrl)
// if err != nil {
// log.Fatal(err)
// }
// nonce, err := cli.PendingNonceAt(context.Background(), fromAddress)
// if err != nil {
// log.Fatal(err)
// }
// gasLimit, err := cli.EstimateGas(context.Background(), ethereum.CallMsg{
// To: &toAddress,
// Data: data,
// })
// gasPrice, err := cli.SuggestGasPrice(context.Background())
// if err != nil {
// log.Fatal(err)
// }
// chainID, _ := cli.NetworkID(context.Background())
// fmt.Printf("gasLimit: %v gasPrice: %v chainID: %v \n", 4178026, 1000000000, 256)
privateKeyAsECDSA
,
err
:=
crypto
.
HexToECDSA
(
privatekey
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
func
(
c
*
EthClient
)
GenerateTx
()
(
*
types
.
Transaction
,
error
)
{
for
i
:=
0
;
i
<
txNum
;
i
++
{
tx
:=
types
.
NewTransaction
(
0
+
uint64
(
i
),
toAddress
,
big
.
NewInt
(
10000000000000
),
4178026
,
big
.
NewInt
(
1000000000
),
nil
)
if
signed
{
signedTx
,
err
:=
types
.
SignTx
(
tx
,
types
.
NewEIP155Signer
(
big
.
NewInt
(
256
)),
privateKeyAsECDSA
)
select
{
case
md5Data
:=
<-
originalMd5Queue
:
if
c
.
GasLimit
==
0
{
cli
,
err
:=
ethclient
.
Dial
(
c
.
NodeUrl
)
if
err
!=
nil
{
return
nil
,
nil
,
err
panic
(
err
)
}
tx
=
signedTx
}
txAsBytes
,
err
:=
tx
.
MarshalBinary
()
if
err
!=
nil
{
return
nil
,
nil
,
err
}
md5Bytes
:=
md5
.
Sum
(
txAsBytes
)
md5Data
=
append
(
md5Data
,
md5Bytes
[
:
]
...
)
md5tx
:=
Md5tx
{
hex
.
EncodeToString
(
md5Bytes
[
:
]),
tx
}
gasLimit
,
err
:=
cli
.
EstimateGas
(
context
.
Background
(),
ethereum
.
CallMsg
{
To
:
&
toAddress
,
Data
:
*
md5Data
,
})
if
err
!=
nil
{
return
nil
,
err
}
res
=
append
(
res
,
md5tx
)
c
.
GasLimit
=
gasLimit
md5TxAsJson
,
err
:=
json
.
Marshal
(
md5tx
)
}
tx
,
err
:=
buildSendTx
(
c
.
Nonce
,
toAddress
,
big
.
NewInt
(
1
),
c
.
GasLimit
,
c
.
GasPrice
,
*
md5Data
,
c
.
ChainId
,
c
.
PrivateKey
)
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
err
}
if
i
==
txNum
{
err
=
rdb
.
LPush
(
ctx
,
"list-liwei"
,
md5TxAsJson
)
.
Err
()
}
else
{
rdb
.
LPush
(
ctx
,
"list-liwei"
,
md5TxAsJson
)
}
c
.
Nonce
+=
1
if
err
!=
nil
{
panic
(
err
)
}
return
tx
,
nil
}
return
res
,
md5Data
,
nil
}
originalTx.go
0 → 100644
View file @
5176ae54
package
multisend
import
(
"context"
"crypto/md5"
"encoding/json"
"fmt"
"math/big"
"sync"
"time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/go-redis/redis/v8"
)
var
originalTxParam
EthClient
var
originTxPrivateKey
string
=
"9e0944f587e1043d6e303644738b0c7c77ed15b176ca574ed0be40c0b9bbdc3a"
var
originalMd5Queue
chan
*
[]
byte
=
make
(
chan
*
[]
byte
,
1000
)
var
originalMd5TxQueue
chan
*
Md5tx
=
make
(
chan
*
Md5tx
,
500000
)
const
batchSize
=
8000
func
init
()
{
originTxPrivateKeyAsECDSA
,
err
:=
crypto
.
HexToECDSA
(
originTxPrivateKey
)
if
err
!=
nil
{
panic
(
err
)
}
originalTxParam
=
EthClient
{
PrivateKey
:
originTxPrivateKeyAsECDSA
,
Nonce
:
0
,
}
}
type
Md5tx
struct
{
MD5
string
`json:md5`
Tx
*
types
.
Transaction
`json:tx`
}
func
ProduceOriginalTx
()
{
for
{
//fmt.Printf("len(originalTxQueue): %d len(originalMd5TxQueue): %d \n", len(originalTxQueue), len(originalMd5TxQueue))
if
len
(
originalMd5Queue
)
<
100
{
var
md5Data
[]
byte
=
make
([]
byte
,
0
,
md5
.
Size
*
(
batchSize
))
for
i
:=
0
;
i
<
batchSize
;
i
++
{
tx
,
err
:=
buildOriginalTx
(
originalTxParam
.
Nonce
,
toAddress
,
big
.
NewInt
(
256
),
nil
)
if
err
!=
nil
{
fmt
.
Println
(
err
.
Error
())
continue
}
originalTxParam
.
Nonce
+=
1
txAsBytes
,
err
:=
tx
.
MarshalBinary
()
if
err
!=
nil
{
fmt
.
Println
(
err
.
Error
())
continue
}
md5Bytes
:=
md5
.
Sum
(
txAsBytes
)
md5Data
=
append
(
md5Data
,
md5Bytes
[
:
]
...
)
}
//startTime := time.Now()
// fp, err := os.Create("bin")
// if err != nil {
// fmt.Println(err)
// return
// }
// defer fp.Close()
// buf := new(bytes.Buffer)
// binary.Write(buf, binary.LittleEndian, md5Data)
// fp.Write(buf.Bytes())
fmt
.
Printf
(
"len(md5Data): %d
\n
"
,
len
(
md5Data
))
originalMd5Queue
<-
&
md5Data
//fmt.Printf("time.Since(startTime): %s \n", fmt.Sprintf("%.20f", time.Since(startTime).Seconds()))
//md5tx := Md5tx{hex.EncodeToString(md5Bytes[:]), tx}
//originalMd5TxQueue <- &md5tx
}
else
{
return
time
.
Sleep
(
time
.
Millisecond
*
1
)
}
}
}
var
ctx
=
context
.
Background
()
var
rdb
=
redis
.
NewClient
(
&
redis
.
Options
{
Addr
:
"54.250.115.98:6379"
,
Password
:
"redis20220217"
,
// no password set
DB
:
0
,
// use default DB
})
func
SendMd5Tx
()
{
//超时 超量
// count := 0
// sendTicker := time.NewTicker(time.Duration(5) * time.Second)
for
{
// if count > 50 {
// // fmt.Printf("current count: %d \n", count)
// // rdb.Context().Err()
// // sendTicker.Reset(time.Duration(5) * time.Second)
// // count = 0
// }
select
{
//case <-sendTicker.C:
// fmt.Printf("5s timeout\n")
// rdb.Context().Err()
// count = 0
case
md5Tx
:=
<-
originalMd5TxQueue
:
md5TxAsJson
,
err
:=
json
.
Marshal
(
md5Tx
)
if
err
!=
nil
{
fmt
.
Println
(
err
.
Error
())
continue
}
rdb
.
LPush
(
ctx
,
"list"
,
md5TxAsJson
)
}
}
}
func
StartProduceTx
()
{
wg
:=
sync
.
WaitGroup
{}
wg
.
Add
(
2
)
go
func
()
{
defer
wg
.
Done
()
ProduceOriginalTx
()
}()
go
func
()
{
defer
wg
.
Done
()
SendMd5Tx
()
}()
wg
.
Wait
()
}
originalTx_test.go
0 → 100644
View file @
5176ae54
package
multisend
import
(
"testing"
)
func
TestProduceTx
(
t
*
testing
.
T
)
{
//StartProduceTx()
ProduceOriginalTx
()
}
transactor.go
View file @
5176ae54
...
...
@@ -249,7 +249,10 @@ func (t *Transactor) sendTransactions() error {
}
var
sent
int
var
sentBytes
int64
defer
func
()
{
t
.
trackSentTxs
(
sent
,
sentBytes
)
}()
defer
func
()
{
fmt
.
Printf
(
"sent %d
\n
"
,
sent
)
t
.
trackSentTxs
(
sent
,
sentBytes
)
}()
t
.
logger
.
Info
(
"Sending batch of transactions"
,
"now"
,
time
.
Now
()
.
Format
(
"15:04:05"
),
"toSend"
,
toSend
)
batchStartTime
:=
time
.
Now
()
for
;
sent
<
toSend
;
sent
++
{
...
...
@@ -280,6 +283,7 @@ func (t *Transactor) sendTransactions() error {
//return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data))
// if we have to make way for the next batch
if
time
.
Since
(
batchStartTime
)
>=
time
.
Duration
(
t
.
config
.
SendPeriod
)
*
time
.
Second
{
fmt
.
Printf
(
"time.Since(batchStartTime): %s
\n
"
,
fmt
.
Sprintf
(
"%.20f"
,
time
.
Since
(
batchStartTime
)
.
Seconds
()))
break
}
}
...
...
transactor_test.go
View file @
5176ae54
...
...
@@ -7,16 +7,26 @@ import (
func
TestTransactor
(
t
*
testing
.
T
)
{
go
StartProduceTx
()
for
{
if
len
(
originalMd5Queue
)
>=
100
{
break
}
t
.
Logf
(
"waiting for produce original tx, len(originalMd5Queue):%d
\n
"
,
len
(
originalMd5Queue
))
time
.
Sleep
(
1
*
time
.
Second
)
}
cfg
:=
Config
{
Rate
:
2
,
Count
:
10
0
,
Rate
:
5
,
Count
:
2
0
,
Connections
:
1
,
Time
:
100
,
SendPeriod
:
1
,
SendPeriod
:
3
,
ClientFactory
:
"ethclient"
,
}
transactor
,
err
:=
NewTransactor
(
"ws
://13.40.31.153:8546
"
,
&
cfg
)
//wss://ws-mainnet-node.huobichain.com
transactor
,
err
:=
NewTransactor
(
"ws
s://ws-mainnet-node.huobichain.com
"
,
&
cfg
)
if
err
!=
nil
{
t
.
Error
(
err
)
...
...
@@ -25,6 +35,6 @@ func TestTransactor(t *testing.T) {
//transactor.sendLoop()
transactor
.
Start
()
time
.
Sleep
(
time
.
Second
*
6
0
)
time
.
Sleep
(
time
.
Second
*
12
0
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment