forked from 0xPolygon/zkevm-ethtx-manager
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge tag 'v0.2.1' into upstream/v0.2.1-dev
* tag 'v0.2.1': fix if a tx is finalized very fast (0xPolygon#84) Rename config parameter `DBPath` to `StoragePath` (0xPolygon#77) feat: implement SQL lite storage (0xPolygon#72) Nonce too low issues fix (0xPolygon#75) fix nonce too low (0xPolygon#67) change namespace (0xPolygon#65) ensure tx order (0xPolygon#64) Quality Gate (0xPolygon#61) option to avoid gas estimationi
- Loading branch information
Showing
20 changed files
with
10,669 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package etherman | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
) | ||
|
||
// GetZkEVMAddressAndL1ChainID returns the ZkEVM address and the L1 chain ID | ||
func (etherMan *Client) GetZkEVMAddressAndL1ChainID() (common.Address, common.Address, uint64, error) { | ||
if etherMan == nil { | ||
return common.Address{}, common.Address{}, 0, fmt.Errorf("etherMan is nil") | ||
} | ||
return etherMan.cfg.ZkEVMAddr, etherMan.cfg.RollupManagerAddr, etherMan.cfg.L1ChainID, nil | ||
} |
5,058 changes: 5,058 additions & 0 deletions
5,058
etherman/smartcontracts/polygonrollupmanager_xlayer/polygonrollupmanager_xlayer.go
Large diffs are not rendered by default.
Oops, something went wrong.
3,689 changes: 3,689 additions & 0 deletions
3,689
etherman/smartcontracts/polygonvalidium_xlayer/polygonvalidium_xlayer.go
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,300 @@ | ||
package ethtxmanager | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"math/big" | ||
"strings" | ||
"time" | ||
|
||
"github.com/0xPolygon/zkevm-ethtx-manager/etherman/smartcontracts/polygonrollupmanager_xlayer" | ||
"github.com/0xPolygon/zkevm-ethtx-manager/etherman/smartcontracts/polygonvalidium_xlayer" | ||
"github.com/0xPolygon/zkevm-ethtx-manager/log" | ||
zkmanTypes "github.com/0xPolygon/zkevm-ethtx-manager/types" | ||
|
||
"github.com/ethereum/go-ethereum/accounts/abi" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/params" | ||
"github.com/google/uuid" | ||
) | ||
|
||
type contextKey string | ||
|
||
const ( | ||
sigLen = 4 | ||
hashLen = 32 | ||
proofLen = 24 | ||
traceID contextKey = "traceID" | ||
httpTimeout = 2 * time.Minute | ||
gasPricesThreshold = 10 // 10 wei | ||
) | ||
|
||
func getTraceID(ctx context.Context) (string, string) { | ||
if ctx == nil || ctx.Value(traceID) == nil { | ||
return "", "" | ||
} | ||
return string(traceID), ctx.Value(traceID).(string) | ||
} | ||
|
||
func (key contextKey) String() string { | ||
return string(key) | ||
} | ||
|
||
type sequenceBatchesArgs struct { | ||
Batches []polygonvalidium_xlayer.PolygonValidiumEtrogValidiumBatchData `json:"batches"` | ||
MaxSequenceTimestamp uint64 `json:"maxSequenceTimestamp"` | ||
InitSequencedBatch uint64 `json:"initSequencedBatch"` | ||
L2Coinbase common.Address `json:"l2Coinbase"` | ||
DataAvailabilityMessage []byte `json:"dataAvailabilityMessage"` | ||
} | ||
|
||
type verifyBatchesTrustedAggregatorArgs struct { | ||
RollupId uint64 `json:"rollupId"` | ||
PendingStateNum uint64 `json:"pendingStateNum"` | ||
InitNumBatch uint64 `json:"initNumBatch"` | ||
FinalNewBatch uint64 `json:"finalNewBatch"` | ||
NewLocalExitRoot [hashLen]byte `json:"newLocalExitRoot"` | ||
NewStateRoot [hashLen]byte `json:"newStateRoot"` | ||
Beneficiary common.Address `json:"beneficiary"` | ||
Proof [proofLen][hashLen]byte `json:"proof"` | ||
} | ||
|
||
var ( | ||
errCustodialAssetsNotEnabled = errors.New("custodial assets not enabled") | ||
errEmptyTx = errors.New("empty tx") | ||
errLoadAbi = errors.New("failed to load contract ABI") | ||
errGetMethodID = errors.New("failed to get method ID") | ||
errUnpack = errors.New("failed to unpack data") | ||
) | ||
|
||
func (c *Client) signTx(mTx zkmanTypes.MonitoredTx, tx *types.Transaction) (*types.Transaction, error) { | ||
if c == nil || !c.cfg.CustodialAssets.Enable { | ||
return nil, errCustodialAssetsNotEnabled | ||
} | ||
ctx := context.WithValue(context.Background(), traceID, uuid.New().String()) | ||
mLog := log.WithFields(getTraceID(ctx)) | ||
mLog.Infof("begin sign tx %x", tx.Hash()) | ||
|
||
var ret *types.Transaction | ||
contractAddress, rollupManagerAddr, _, err := c.etherman.GetZkEVMAddressAndL1ChainID() | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to get zkEVM address and L1 ChainID: %v", err) | ||
} | ||
sender := mTx.From | ||
switch sender { | ||
case c.cfg.CustodialAssets.SequencerAddr: | ||
args, err := c.unpackSequenceBatchesTx(tx) | ||
if err != nil { | ||
mLog.Errorf("failed to unpack tx %x data: %v", tx.Hash(), err) | ||
return nil, fmt.Errorf("failed to unpack tx %x data: %v", tx.Hash(), err) | ||
} | ||
infos, err := args.marshal(contractAddress, mTx) | ||
if err != nil { | ||
mLog.Errorf("failed to marshal tx %x data: %v", tx.Hash(), err) | ||
return nil, fmt.Errorf("failed to marshal tx %x data: %v", tx.Hash(), err) | ||
} | ||
ret, err = c.postSignRequestAndWaitResult(ctx, mTx, c.newSignRequest(c.cfg.CustodialAssets.OperateTypeSeq, sender, infos)) | ||
if err != nil { | ||
mLog.Errorf("failed to post custodial assets: %v", err) | ||
return nil, fmt.Errorf("failed to post custodial assets: %v", err) | ||
} | ||
case c.cfg.CustodialAssets.AggregatorAddr: | ||
args, err := c.unpackVerifyBatchesTrustedAggregatorTx(tx) | ||
if err != nil { | ||
mLog.Errorf("failed to unpack tx %x data: %v", tx.Hash(), err) | ||
return nil, fmt.Errorf("failed to unpack tx %x data: %v", tx.Hash(), err) | ||
} | ||
infos, err := args.marshal(rollupManagerAddr, mTx) | ||
if err != nil { | ||
mLog.Errorf("failed to marshal tx %x data: %v", tx.Hash(), err) | ||
return nil, fmt.Errorf("failed to marshal tx %x data: %v", tx.Hash(), err) | ||
} | ||
ret, err = c.postSignRequestAndWaitResult(ctx, mTx, c.newSignRequest(c.cfg.CustodialAssets.OperateTypeAgg, sender, infos)) | ||
if err != nil { | ||
mLog.Errorf("failed to post custodial assets: %v", err) | ||
return nil, fmt.Errorf("failed to post custodial assets: %v", err) | ||
} | ||
default: | ||
mLog.Errorf("unknown sender %s", sender.String()) | ||
return nil, fmt.Errorf("unknown sender %s", sender.String()) | ||
} | ||
|
||
return ret, nil | ||
} | ||
|
||
func (c *Client) unpackSequenceBatchesTx(tx *types.Transaction) (*sequenceBatchesArgs, error) { | ||
if tx == nil || len(tx.Data()) < sigLen { | ||
return nil, errEmptyTx | ||
} | ||
retArgs, err := unpack(tx.Data(), polygonvalidium_xlayer.PolygonvalidiumXlayerMetaData.ABI) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to unpack tx %x data: %v", tx.Hash(), err) | ||
} | ||
retBytes, err := json.Marshal(retArgs) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to marshal tx %x data: %v", tx.Hash(), err) | ||
} | ||
var args sequenceBatchesArgs | ||
err = json.Unmarshal(retBytes, &args) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to unmarshal tx %x data: %v", tx.Hash(), err) | ||
} | ||
|
||
return &args, nil | ||
} | ||
|
||
func (c *Client) unpackVerifyBatchesTrustedAggregatorTx(tx *types.Transaction) (*verifyBatchesTrustedAggregatorArgs, error) { | ||
if tx == nil || len(tx.Data()) < sigLen { | ||
return nil, errEmptyTx | ||
} | ||
retArgs, err := unpack(tx.Data(), polygonrollupmanager_xlayer.PolygonrollupmanagerMetaData.ABI) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to unpack tx %x data: %v", tx.Hash(), err) | ||
} | ||
retBytes, err := json.Marshal(retArgs) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to marshal tx %x data: %v", tx.Hash(), err) | ||
} | ||
var args verifyBatchesTrustedAggregatorArgs | ||
err = json.Unmarshal(retBytes, &args) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to unmarshal tx %x data: %v", tx.Hash(), err) | ||
} | ||
|
||
return &args, nil | ||
} | ||
|
||
func unpack(data []byte, abiString string) (map[string]interface{}, error) { | ||
// load contract ABI | ||
zkAbi, err := abi.JSON(strings.NewReader(abiString)) | ||
if err != nil { | ||
return nil, errLoadAbi | ||
} | ||
|
||
decodedSig := data[:sigLen] | ||
|
||
// recover Method from signature and ABI | ||
method, err := zkAbi.MethodById(decodedSig) | ||
if err != nil { | ||
return nil, errGetMethodID | ||
} | ||
|
||
decodedData := data[sigLen:] | ||
|
||
// unpack method inputs | ||
// result, err := method.Inputs.Unpack(decodedData) | ||
result := make(map[string]interface{}) | ||
err = method.Inputs.UnpackIntoMap(result, decodedData) | ||
if err != nil { | ||
return nil, errUnpack | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
type batchData struct { | ||
TransactionsHash string `json:"transactionsHash"` | ||
ForcedGlobalExitRoot string `json:"forcedGlobalExitRoot"` | ||
ForcedTimestamp uint64 `json:"forcedTimestamp"` | ||
ForcedBlockHashL1 string `json:"forcedBlockHashL1"` | ||
} | ||
|
||
func getGasPriceEther(gasPriceWei *big.Int) string { | ||
compactAmount := big.NewInt(0) | ||
reminder := big.NewInt(0) | ||
divisor := big.NewInt(params.Ether) | ||
compactAmount.QuoRem(gasPriceWei, divisor, reminder) | ||
|
||
return fmt.Sprintf("%v.%018s", compactAmount.String(), reminder.String()) | ||
} | ||
|
||
func (s *sequenceBatchesArgs) marshal(contractAddress common.Address, mTx zkmanTypes.MonitoredTx) (string, error) { | ||
if s == nil { | ||
return "", fmt.Errorf("sequenceBatchesArgs is nil") | ||
} | ||
gp := getGasPriceEther(mTx.GasPrice) | ||
httpArgs := struct { | ||
Batches []batchData `json:"batches"` | ||
MaxSequenceTimestamp uint64 `json:"maxSequenceTimestamp"` | ||
InitSequencedBatch uint64 `json:"initSequencedBatch"` | ||
L2Coinbase common.Address `json:"l2Coinbase"` | ||
DataAvailabilityMessage string `json:"dataAvailabilityMessage"` | ||
ContractAddress common.Address `json:"contractAddress"` | ||
GasLimit uint64 `json:"gasLimit"` | ||
GasPrice string `json:"gasPrice"` | ||
Nonce uint64 `json:"nonce"` | ||
}{ | ||
MaxSequenceTimestamp: s.MaxSequenceTimestamp, | ||
InitSequencedBatch: s.InitSequencedBatch, | ||
L2Coinbase: s.L2Coinbase, | ||
DataAvailabilityMessage: hex.EncodeToString(s.DataAvailabilityMessage), | ||
ContractAddress: contractAddress, | ||
GasLimit: mTx.Gas + mTx.GasOffset, | ||
GasPrice: gp, | ||
Nonce: mTx.Nonce, | ||
} | ||
|
||
httpArgs.Batches = make([]batchData, 0, len(s.Batches)) | ||
for _, batch := range s.Batches { | ||
httpArgs.Batches = append(httpArgs.Batches, batchData{ | ||
TransactionsHash: hex.EncodeToString(batch.TransactionsHash[:]), | ||
ForcedGlobalExitRoot: hex.EncodeToString(batch.ForcedGlobalExitRoot[:]), | ||
ForcedTimestamp: batch.ForcedTimestamp, | ||
ForcedBlockHashL1: hex.EncodeToString(batch.ForcedBlockHashL1[:]), | ||
}) | ||
} | ||
ret, err := json.Marshal(httpArgs) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to marshal sequenceBatchesArgs: %v", err) | ||
} | ||
|
||
return string(ret), nil | ||
} | ||
|
||
func (v *verifyBatchesTrustedAggregatorArgs) marshal(contractAddress common.Address, mTx zkmanTypes.MonitoredTx) (string, error) { | ||
if v == nil { | ||
return "", fmt.Errorf("verifyBatchesTrustedAggregatorArgs is nil") | ||
} | ||
|
||
gp := getGasPriceEther(mTx.GasPrice) | ||
httpArgs := struct { | ||
RollupId uint64 `json:"rollupID"` | ||
PendingStateNum uint64 `json:"pendingStateNum"` | ||
InitNumBatch uint64 `json:"initNumBatch"` | ||
FinalNewBatch uint64 `json:"finalNewBatch"` | ||
NewLocalExitRoot string `json:"newLocalExitRoot"` | ||
NewStateRoot string `json:"newStateRoot"` | ||
Beneficiary common.Address `json:"beneficiary"` | ||
Proof [proofLen]string `json:"proof"` | ||
ContractAddress common.Address `json:"contractAddress"` | ||
GasLimit uint64 `json:"gasLimit"` | ||
GasPrice string `json:"gasPrice"` | ||
Nonce uint64 `json:"nonce"` | ||
}{ | ||
RollupId: v.RollupId, | ||
PendingStateNum: v.PendingStateNum, | ||
InitNumBatch: v.InitNumBatch, | ||
FinalNewBatch: v.FinalNewBatch, | ||
NewLocalExitRoot: hex.EncodeToString(v.NewLocalExitRoot[:]), | ||
NewStateRoot: hex.EncodeToString(v.NewStateRoot[:]), | ||
Beneficiary: v.Beneficiary, | ||
ContractAddress: contractAddress, | ||
GasLimit: mTx.Gas + mTx.GasOffset, | ||
GasPrice: gp, | ||
Nonce: mTx.Nonce, | ||
} | ||
for i, p := range v.Proof { | ||
httpArgs.Proof[i] = hex.EncodeToString(p[:]) | ||
} | ||
|
||
ret, err := json.Marshal(httpArgs) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to marshal verifyBatchesTrustedAggregatorArgs: %v", err) | ||
} | ||
|
||
return string(ret), nil | ||
} |
Oops, something went wrong.