-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
L2Wallet SendTransaction is not thread safe #42
Comments
Method |
If my requirement now is to support concurrency safety when calling a contract to send transactions, which interface or function should I use to implement it? Or should I directly use the rpc method of the node to implement it? |
You can call directly
client, err := clients.Dial("https://sepolia.era.zksync.dev")
if err != nil {
log.Panic(err)
}
defer client.Close()
chainID, err := client.ChainID(context.Background())
if err != nil {
log.Panic(err)
}
baseSigner, err := NewBaseSignerFromRawPrivateKey(rawPrivateKey, chainID.Int64())
if err != nil {
log.Panic(err)
}
signer := Signer(baseSigner)
var preparedTx zkTypes.Transaction712 // prepared tx in thread-safe manner
signature, err := signer.SignTypedData(signer.Domain(), preparedTx)
if err != nil {
log.Panic(err)
}
tx, err := preparedTx.RLPValues(signature)
if err != nil {
log.Panic(err)
}
hahs, err := client.SendRawTransaction(ctx context.Context, tx)
if err != nil {
log.Panic(err)
} |
i have tried the above mentioned method to send raw transaction concurrently, but i have found that i need to mange |
I found that when multiple goroutines concurrently call SendTransaction to send transactions, it's possible to get the same txhash for different transactions. This can lead to some transactions not being confirmed, and calling WaitMined after sending the transaction can't retrieve the transaction information, resulting in a deadlock. The code to reproduce this issue is as follows:
`func main() {
PrivateKey := ""
ZkSyncEraProvider := ""
}`
However, after adding a lock to SendTransaction, a new problem arose.
Since the Nonce calculation in PopulateTransaction is based on an RPC call rather than local caching, concurrent calls to SendTransaction can lead to the Nonce not being updated in time.
This can result in transactions with the same Nonce field being generated. When the previous transaction is submitted and successfully processed, the subsequent transaction will be rejected due to an invalid Nonce field.
go func() { defer wg.Done() amount := ToWei("1", 18) mintData, err := contractABI.Pack("mint", l2address, amount) if err != nil { return } lock.Lock() hash, err := wallet.SendTransaction(context.Background(), &accounts.Transaction{ To: &SatsAddress, Data: mintData, }) if err != nil { fmt.Println(err) return } lock.Unlock() _, err = client.WaitMined(context.Background(), hash) if err != nil { log.Panic(err) } }()
In the end, I had to include WaitMined in the locked scope as well, forcing the originally concurrent transactions to be executed and confirmed in a completely serial manner.
go func() { defer wg.Done() amount := ToWei("1", 18) mintData, err := contractABI.Pack("mint", l2address, amount) if err != nil { return } lock.Lock() hash, err := wallet.SendTransaction(context.Background(), &accounts.Transaction{ To: &SatsAddress, Data: mintData, }) if err != nil { fmt.Println(err) return } _, err = client.WaitMined(context.Background(), hash) if err != nil { log.Panic(err) } lock.Unlock() }()
My question is, when using zksync-gosdk, is it only possible to execute transactions serially, and not to send transactions concurrently?
If concurrent transactions are possible, how can it be done? If not, please add a note in the comments of SendTransaction indicating that it is not thread-safe for concurrent use.
The text was updated successfully, but these errors were encountered: