mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-18 16:44:12 +00:00
509 lines
14 KiB
Go
509 lines
14 KiB
Go
package contracts_steps
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math"
|
|
"math/big"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/chain/networkname"
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon/accounts/abi"
|
|
"github.com/ledgerwatch/erigon/accounts/abi/bind"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/accounts"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/blocks"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/contracts"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/devnet"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/requests"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/scenarios"
|
|
"github.com/ledgerwatch/erigon/cmd/devnet/services"
|
|
"github.com/ledgerwatch/erigon/rpc"
|
|
"github.com/ledgerwatch/erigon/turbo/adapter/ethapi"
|
|
)
|
|
|
|
func init() {
|
|
scenarios.MustRegisterStepHandlers(
|
|
scenarios.StepHandler(DeployChildChainReceiver),
|
|
scenarios.StepHandler(DeployRootChainSender),
|
|
scenarios.StepHandler(GenerateSyncEvents),
|
|
scenarios.StepHandler(ProcessRootTransfers),
|
|
scenarios.StepHandler(BatchProcessRootTransfers),
|
|
)
|
|
}
|
|
|
|
func GenerateSyncEvents(ctx context.Context, senderName string, numberOfTransfers int, minTransfer int, maxTransfer int) error {
|
|
sender := accounts.GetAccount(senderName)
|
|
ctx = devnet.WithCurrentNetwork(ctx, networkname.DevChainName)
|
|
|
|
auth, err := contracts.TransactOpts(ctx, sender.Address)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
heimdall := services.Heimdall(ctx)
|
|
|
|
stateSender := heimdall.StateSenderContract()
|
|
|
|
receiver, _ := scenarios.Param[*contracts.ChildReceiver](ctx, "childReceiver")
|
|
receiverAddress, _ := scenarios.Param[libcommon.Address](ctx, "childReceiverAddress")
|
|
|
|
receivedChan := make(chan *contracts.ChildReceiverReceived)
|
|
receiverSubscription, err := receiver.WatchReceived(&bind.WatchOpts{}, receivedChan)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Receiver subscription failed: %w", err)
|
|
}
|
|
|
|
defer receiverSubscription.Unsubscribe()
|
|
|
|
Uint256, _ := abi.NewType("uint256", "", nil)
|
|
Address, _ := abi.NewType("address", "", nil)
|
|
|
|
args := abi.Arguments{
|
|
{Name: "from", Type: Address},
|
|
{Name: "amount", Type: Uint256},
|
|
}
|
|
|
|
for i := 0; i < numberOfTransfers; i++ {
|
|
err := func() error {
|
|
sendData, err := args.Pack(sender.Address, big.NewInt(int64(minTransfer)))
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
waiter, cancel := blocks.BlockWaiter(ctx, contracts.DeploymentChecker)
|
|
defer cancel()
|
|
|
|
transaction, err := stateSender.SyncState(auth, receiverAddress, sendData)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
block, err := waiter.Await(transaction.Hash())
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to wait for sync block: %w", err)
|
|
}
|
|
|
|
blockNum := block.Number.Uint64()
|
|
|
|
logs, err := stateSender.FilterStateSynced(&bind.FilterOpts{
|
|
Start: blockNum,
|
|
End: &blockNum,
|
|
}, nil, nil)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to get post sync logs: %w", err)
|
|
}
|
|
|
|
sendConfirmed := false
|
|
|
|
for logs.Next() {
|
|
if logs.Event.ContractAddress != receiverAddress {
|
|
return fmt.Errorf("Receiver address mismatched: expected: %s, got: %s", receiverAddress, logs.Event.ContractAddress)
|
|
}
|
|
|
|
if !bytes.Equal(logs.Event.Data, sendData) {
|
|
return fmt.Errorf("Send data mismatched: expected: %s, got: %s", sendData, logs.Event.Data)
|
|
}
|
|
|
|
sendConfirmed = true
|
|
}
|
|
|
|
if !sendConfirmed {
|
|
return fmt.Errorf("No post sync log received")
|
|
}
|
|
|
|
auth.Nonce = (&big.Int{}).Add(auth.Nonce, big.NewInt(1))
|
|
|
|
return nil
|
|
}()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
receivedCount := 0
|
|
|
|
devnet.Logger(ctx).Info("Waiting for receive events")
|
|
|
|
for received := range receivedChan {
|
|
if received.Source != sender.Address {
|
|
return fmt.Errorf("Source address mismatched: expected: %s, got: %s", sender.Address, received.Source)
|
|
}
|
|
|
|
if received.Amount.Cmp(big.NewInt(int64(minTransfer))) != 0 {
|
|
return fmt.Errorf("Amount mismatched: expected: %s, got: %s", big.NewInt(int64(minTransfer)), received.Amount)
|
|
}
|
|
|
|
receivedCount++
|
|
if receivedCount == numberOfTransfers {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func DeployRootChainSender(ctx context.Context, deployerName string) (context.Context, error) {
|
|
deployer := accounts.GetAccount(deployerName)
|
|
ctx = devnet.WithCurrentNetwork(ctx, networkname.DevChainName)
|
|
|
|
auth, backend, err := contracts.DeploymentTransactor(ctx, deployer.Address)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
receiverAddress, _ := scenarios.Param[libcommon.Address](ctx, "childReceiverAddress")
|
|
|
|
heimdall := services.Heimdall(ctx)
|
|
|
|
waiter, cancel := blocks.BlockWaiter(ctx, contracts.DeploymentChecker)
|
|
defer cancel()
|
|
|
|
address, transaction, contract, err := contracts.DeployRootSender(auth, backend, heimdall.StateSenderAddress(), receiverAddress)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
block, err := waiter.Await(transaction.Hash())
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
devnet.Logger(ctx).Info("RootSender deployed", "chain", networkname.DevChainName, "block", block.Number, "addr", address)
|
|
|
|
return scenarios.WithParam(ctx, "rootSenderAddress", address).
|
|
WithParam("rootSender", contract), nil
|
|
}
|
|
|
|
func DeployChildChainReceiver(ctx context.Context, deployerName string) (context.Context, error) {
|
|
deployer := accounts.GetAccount(deployerName)
|
|
ctx = devnet.WithCurrentNetwork(ctx, networkname.BorDevnetChainName)
|
|
|
|
waiter, cancel := blocks.BlockWaiter(ctx, contracts.DeploymentChecker)
|
|
defer cancel()
|
|
|
|
address, transaction, contract, err := contracts.Deploy(ctx, deployer.Address, contracts.DeployChildReceiver)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
block, err := waiter.Await(transaction.Hash())
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
devnet.Logger(ctx).Info("ChildReceiver deployed", "chain", networkname.BorDevnetChainName, "block", block.Number, "addr", address)
|
|
|
|
return scenarios.WithParam(ctx, "childReceiverAddress", address).
|
|
WithParam("childReceiver", contract), nil
|
|
}
|
|
|
|
func ProcessRootTransfers(ctx context.Context, sourceName string, numberOfTransfers int, minTransfer int, maxTransfer int) error {
|
|
source := accounts.GetAccount(sourceName)
|
|
ctx = devnet.WithCurrentNetwork(ctx, networkname.DevChainName)
|
|
|
|
auth, err := contracts.TransactOpts(ctx, source.Address)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sender, _ := scenarios.Param[*contracts.RootSender](ctx, "rootSender")
|
|
stateSender := services.Heimdall(ctx).StateSenderContract()
|
|
|
|
receiver, _ := scenarios.Param[*contracts.ChildReceiver](ctx, "childReceiver")
|
|
receiverAddress, _ := scenarios.Param[libcommon.Address](ctx, "childReceiverAddress")
|
|
|
|
receivedChan := make(chan *contracts.ChildReceiverReceived)
|
|
receiverSubscription, err := receiver.WatchReceived(&bind.WatchOpts{}, receivedChan)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Receiver subscription failed: %w", err)
|
|
}
|
|
|
|
defer receiverSubscription.Unsubscribe()
|
|
|
|
Uint256, _ := abi.NewType("uint256", "", nil)
|
|
Address, _ := abi.NewType("address", "", nil)
|
|
|
|
args := abi.Arguments{
|
|
{Name: "from", Type: Address},
|
|
{Name: "amount", Type: Uint256},
|
|
}
|
|
|
|
for i := 0; i < numberOfTransfers; i++ {
|
|
amount := accounts.EtherAmount(float64(minTransfer))
|
|
|
|
err = func() error {
|
|
waiter, cancel := blocks.BlockWaiter(ctx, blocks.CompletionChecker)
|
|
defer cancel()
|
|
|
|
transaction, err := sender.SendToChild(auth, amount)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
block, terr := waiter.Await(transaction.Hash())
|
|
|
|
if terr != nil {
|
|
node := devnet.SelectBlockProducer(ctx)
|
|
|
|
traceResults, err := node.TraceTransaction(transaction.Hash())
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Send transaction failure: transaction trace failed: %w", err)
|
|
}
|
|
|
|
for _, traceResult := range traceResults {
|
|
callResults, err := node.TraceCall(rpc.AsBlockReference(block.Number), ethapi.CallArgs{
|
|
From: &traceResult.Action.From,
|
|
To: &traceResult.Action.To,
|
|
Data: &traceResult.Action.Input,
|
|
}, requests.TraceOpts.StateDiff, requests.TraceOpts.Trace, requests.TraceOpts.VmTrace)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Send transaction failure: trace call failed: %w", err)
|
|
}
|
|
|
|
results, _ := json.MarshalIndent(callResults, " ", " ")
|
|
fmt.Println(string(results))
|
|
}
|
|
|
|
return terr
|
|
}
|
|
|
|
blockNum := block.Number.Uint64()
|
|
|
|
logs, err := stateSender.FilterStateSynced(&bind.FilterOpts{
|
|
Start: blockNum,
|
|
End: &blockNum,
|
|
}, nil, nil)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to get post sync logs: %w", err)
|
|
}
|
|
|
|
for logs.Next() {
|
|
if logs.Event.ContractAddress != receiverAddress {
|
|
return fmt.Errorf("Receiver address mismatched: expected: %s, got: %s", receiverAddress, logs.Event.ContractAddress)
|
|
}
|
|
|
|
values, err := args.Unpack(logs.Event.Data)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed unpack log args: %w", err)
|
|
}
|
|
|
|
sender, ok := values[0].(libcommon.Address)
|
|
|
|
if !ok {
|
|
return fmt.Errorf("Unexpected arg type: expected: %T, got %T", libcommon.Address{}, values[0])
|
|
}
|
|
|
|
sentAmount, ok := values[1].(*big.Int)
|
|
|
|
if !ok {
|
|
return fmt.Errorf("Unexpected arg type: expected: %T, got %T", &big.Int{}, values[1])
|
|
}
|
|
|
|
if sender != source.Address {
|
|
return fmt.Errorf("Unexpected sender: expected: %s, got %s", source.Address, sender)
|
|
}
|
|
|
|
if amount.Cmp(sentAmount) != 0 {
|
|
return fmt.Errorf("Unexpected sent amount: expected: %s, got %s", amount, sentAmount)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
auth.Nonce = (&big.Int{}).Add(auth.Nonce, big.NewInt(1))
|
|
}
|
|
|
|
receivedCount := 0
|
|
|
|
devnet.Logger(ctx).Info("Waiting for receive events")
|
|
|
|
for received := range receivedChan {
|
|
if received.Source != source.Address {
|
|
return fmt.Errorf("Source address mismatched: expected: %s, got: %s", source.Address, received.Source)
|
|
}
|
|
|
|
if received.Amount.Cmp(accounts.EtherAmount(float64(minTransfer))) != 0 {
|
|
return fmt.Errorf("Amount mismatched: expected: %s, got: %s", accounts.EtherAmount(float64(minTransfer)), received.Amount)
|
|
}
|
|
|
|
receivedCount++
|
|
if receivedCount == numberOfTransfers {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func BatchProcessRootTransfers(ctx context.Context, sourceName string, batches int, transfersPerBatch, minTransfer int, maxTransfer int) error {
|
|
source := accounts.GetAccount(sourceName)
|
|
ctx = devnet.WithCurrentNetwork(ctx, networkname.DevChainName)
|
|
|
|
auth, err := contracts.TransactOpts(ctx, source.Address)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sender, _ := scenarios.Param[*contracts.RootSender](ctx, "rootSender")
|
|
stateSender := services.Heimdall(ctx).StateSenderContract()
|
|
|
|
receiver, _ := scenarios.Param[*contracts.ChildReceiver](ctx, "childReceiver")
|
|
receiverAddress, _ := scenarios.Param[libcommon.Address](ctx, "childReceiverAddress")
|
|
|
|
receivedChan := make(chan *contracts.ChildReceiverReceived)
|
|
receiverSubscription, err := receiver.WatchReceived(&bind.WatchOpts{}, receivedChan)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Receiver subscription failed: %w", err)
|
|
}
|
|
|
|
defer receiverSubscription.Unsubscribe()
|
|
|
|
Uint256, _ := abi.NewType("uint256", "", nil)
|
|
Address, _ := abi.NewType("address", "", nil)
|
|
|
|
args := abi.Arguments{
|
|
{Name: "from", Type: Address},
|
|
{Name: "amount", Type: Uint256},
|
|
}
|
|
|
|
for b := 0; b < batches; b++ {
|
|
|
|
hashes := make([]libcommon.Hash, transfersPerBatch)
|
|
|
|
waiter, cancel := blocks.BlockWaiter(ctx, blocks.CompletionChecker)
|
|
defer cancel()
|
|
|
|
amount := accounts.EtherAmount(float64(minTransfer))
|
|
|
|
for i := 0; i < transfersPerBatch; i++ {
|
|
|
|
transaction, err := sender.SendToChild(auth, amount)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hashes[i] = transaction.Hash()
|
|
auth.Nonce = (&big.Int{}).Add(auth.Nonce, big.NewInt(1))
|
|
}
|
|
|
|
blocks, err := waiter.AwaitMany(hashes...)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
startBlock := uint64(math.MaxUint64)
|
|
endBlock := uint64(0)
|
|
|
|
for _, block := range blocks {
|
|
blockNum := block.Number.Uint64()
|
|
|
|
if blockNum < startBlock {
|
|
startBlock = blockNum
|
|
}
|
|
if blockNum > endBlock {
|
|
endBlock = blockNum
|
|
}
|
|
}
|
|
|
|
logs, err := stateSender.FilterStateSynced(&bind.FilterOpts{
|
|
Start: startBlock,
|
|
End: &endBlock,
|
|
}, nil, nil)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to get post sync logs: %w", err)
|
|
}
|
|
|
|
receivedCount := 0
|
|
|
|
for logs.Next() {
|
|
if logs.Event.ContractAddress != receiverAddress {
|
|
return fmt.Errorf("Receiver address mismatched: expected: %s, got: %s", receiverAddress, logs.Event.ContractAddress)
|
|
}
|
|
|
|
values, err := args.Unpack(logs.Event.Data)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Failed unpack log args: %w", err)
|
|
}
|
|
|
|
sender, ok := values[0].(libcommon.Address)
|
|
|
|
if !ok {
|
|
return fmt.Errorf("Unexpected arg type: expected: %T, got %T", libcommon.Address{}, values[0])
|
|
}
|
|
|
|
sentAmount, ok := values[1].(*big.Int)
|
|
|
|
if !ok {
|
|
return fmt.Errorf("Unexpected arg type: expected: %T, got %T", &big.Int{}, values[1])
|
|
}
|
|
|
|
if sender != source.Address {
|
|
return fmt.Errorf("Unexpected sender: expected: %s, got %s", source.Address, sender)
|
|
}
|
|
|
|
if amount.Cmp(sentAmount) != 0 {
|
|
return fmt.Errorf("Unexpected sent amount: expected: %s, got %s", amount, sentAmount)
|
|
}
|
|
|
|
receivedCount++
|
|
}
|
|
|
|
if receivedCount != transfersPerBatch {
|
|
return fmt.Errorf("Expected %d, got: %d", transfersPerBatch, receivedCount)
|
|
}
|
|
}
|
|
|
|
receivedCount := 0
|
|
|
|
devnet.Logger(ctx).Info("Waiting for receive events")
|
|
|
|
for received := range receivedChan {
|
|
if received.Source != source.Address {
|
|
return fmt.Errorf("Source address mismatched: expected: %s, got: %s", source.Address, received.Source)
|
|
}
|
|
|
|
if received.Amount.Cmp(accounts.EtherAmount(float64(minTransfer))) != 0 {
|
|
return fmt.Errorf("Amount mismatched: expected: %s, got: %s", accounts.EtherAmount(float64(minTransfer)), received.Amount)
|
|
}
|
|
|
|
receivedCount++
|
|
if receivedCount == batches*transfersPerBatch {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|