Skip to content

Commit

Permalink
Add the virtual batch for v2 (0xPolygonHermez#765)
Browse files Browse the repository at this point in the history
* add the etherman part

* reflect suggestions

* remove unnecessary struct
  • Loading branch information
cool-develope authored Jun 17, 2022
1 parent ed1e5d6 commit b86e253
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 5 deletions.
80 changes: 77 additions & 3 deletions ethermanv2/etherman.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package ethermanv2

import (
"context"
"encoding/json"
"fmt"
"math/big"
"strings"
"time"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand All @@ -21,6 +24,7 @@ import (
)

var (
sequencedBatchesEventSignatureHash = crypto.Keccak256Hash([]byte("SequencedBatches(uint64)"))
ownershipTransferredSignatureHash = crypto.Keccak256Hash([]byte("OwnershipTransferred(address,address)"))
updateGlobalExitRootEventSignatureHash = crypto.Keccak256Hash([]byte("UpdateGlobalExitRoot(uint256,bytes32,bytes32)"))
forceBatchSignatureHash = crypto.Keccak256Hash([]byte("ForceBatch(uint64,bytes32,address,bytes)"))
Expand Down Expand Up @@ -106,6 +110,8 @@ func (etherMan *Client) readEvents(ctx context.Context, query ethereum.FilterQue

func (etherMan *Client) processEvent(ctx context.Context, vLog types.Log, blocks *[]state.Block) error {
switch vLog.Topics[0] {
case sequencedBatchesEventSignatureHash:
return etherMan.sequencedBatchesEvent(ctx, vLog, blocks)
case ownershipTransferredSignatureHash:
return etherMan.ownershipTransferredEvent(vLog)
case updateGlobalExitRootEventSignatureHash:
Expand Down Expand Up @@ -160,7 +166,7 @@ func (etherMan *Client) updateGlobalExitRootEvent(ctx context.Context, vLog type
(*blocks)[len(*blocks)-1].GlobalExitRoots = append((*blocks)[len(*blocks)-1].GlobalExitRoots, gExitRoot)
} else {
log.Error("Error processing UpdateGlobalExitRoot event. BlockHash:", vLog.BlockHash, ". BlockNumber: ", vLog.BlockNumber)
return fmt.Errorf("Error processing UpdateGlobalExitRoot event")
return fmt.Errorf("error processing UpdateGlobalExitRoot event")
}
return nil
}
Expand Down Expand Up @@ -207,12 +213,80 @@ func (etherMan *Client) forceBatchEvent(ctx context.Context, vLog types.Log, blo
} else if (*blocks)[len(*blocks)-1].BlockHash == vLog.BlockHash && (*blocks)[len(*blocks)-1].BlockNumber == vLog.BlockNumber {
(*blocks)[len(*blocks)-1].ForcedBatches = append((*blocks)[len(*blocks)-1].ForcedBatches, forcedBatch)
} else {
log.Error("Error processing UpdateGlobalExitRoot event. BlockHash:", vLog.BlockHash, ". BlockNumber: ", vLog.BlockNumber)
return fmt.Errorf("Error processing UpdateGlobalExitRoot event")
log.Error("Error processing ForceBatch event. BlockHash:", vLog.BlockHash, ". BlockNumber: ", vLog.BlockNumber)
return fmt.Errorf("error processing ForceBatch event")
}
return nil
}

func (etherMan *Client) sequencedBatchesEvent(ctx context.Context, vLog types.Log, blocks *[]state.Block) error {
log.Debug("SequencedBatches event detected")
_, err := etherMan.PoE.ParseSequencedBatches(vLog)
if err != nil {
return err
}
// Read the tx for this event.
tx, isPending, err := etherMan.EtherClient.TransactionByHash(ctx, vLog.TxHash)
if err != nil {
return err
} else if isPending {
return fmt.Errorf("error tx is still pending. TxHash: %s", tx.Hash().String())
}
sequences, err := decodeSequences(tx.Data())
if err != nil {
return fmt.Errorf("error decoding the sequences: %v", err)
}

if len(*blocks) == 0 || ((*blocks)[len(*blocks)-1].BlockHash != vLog.BlockHash || (*blocks)[len(*blocks)-1].BlockNumber != vLog.BlockNumber) {
fullBlock, err := etherMan.EtherClient.BlockByHash(ctx, vLog.BlockHash)
if err != nil {
return fmt.Errorf("error getting hashParent. BlockNumber: %d. Error: %w", vLog.BlockNumber, err)
}
t := time.Unix(int64(fullBlock.Time()), 0)
block := prepareBlock(vLog, t, fullBlock)
block.Sequences = append(block.Sequences, sequences...)
*blocks = append(*blocks, block)
} else if (*blocks)[len(*blocks)-1].BlockHash == vLog.BlockHash && (*blocks)[len(*blocks)-1].BlockNumber == vLog.BlockNumber {
(*blocks)[len(*blocks)-1].Sequences = append((*blocks)[len(*blocks)-1].Sequences, sequences...)
} else {
log.Error("Error processing SequencedBatches event. BlockHash:", vLog.BlockHash, ". BlockNumber: ", vLog.BlockNumber)
return fmt.Errorf("error processing SequencedBatches event")
}
return nil
}

func decodeSequences(txData []byte) ([]proofofefficiency.ProofOfEfficiencySequence, error) {
// Extract coded txs.
// Load contract ABI
abi, err := abi.JSON(strings.NewReader(proofofefficiency.ProofofefficiencyABI))
if err != nil {
return nil, err
}

// Recover Method from signature and ABI
method, err := abi.MethodById(txData[:4])
if err != nil {
return nil, err
}

// Unpack method inputs
data, err := method.Inputs.Unpack(txData[4:])
if err != nil {
return nil, err
}
var sequences []proofofefficiency.ProofOfEfficiencySequence
bytedata, err := json.Marshal(data[0])
if err != nil {
return nil, err
}
err = json.Unmarshal(bytedata, &sequences)
if err != nil {
return nil, err
}

return sequences, nil
}

func prepareBlock(vLog types.Log, t time.Time, fullBlock *types.Block) state.Block {
var block state.Block
block.BlockNumber = vLog.BlockNumber
Expand Down
56 changes: 56 additions & 0 deletions ethermanv2/etherman_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/hermeznetwork/hermez-core/ethermanv2/smartcontracts/bridge"
"github.com/hermeznetwork/hermez-core/ethermanv2/smartcontracts/proofofefficiency"
"github.com/hermeznetwork/hermez-core/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -106,3 +107,58 @@ func TestForcedBatchEvent(t *testing.T) {
assert.Equal(t, dataFromSmc, hex.EncodeToString(blocks[0].ForcedBatches[0].RawTxsData))
assert.Equal(t, etherman.auth.From, blocks[0].ForcedBatches[0].Sequencer)
}

func TestSequencedBatchesEvent(t *testing.T) {
// Set up testing environment
etherman, commit, _, br := newTestingEnv()

// Read currentBlock
ctx := context.Background()
initBlock, err := etherman.EtherClient.BlockByNumber(ctx, nil)
require.NoError(t, err)

// Make a bridge tx
a := etherman.auth
a.Value = big.NewInt(1000000000000000)
_, err = br.Bridge(a, common.Address{}, a.Value, 1, a.From)
require.NoError(t, err)
commit()
a.Value = big.NewInt(0)

// Get the last ger
ger, err := etherman.GlobalExitRootManager.GetLastGlobalExitRoot(nil)
require.NoError(t, err)

var sequences []proofofefficiency.ProofOfEfficiencySequence
rawTxs := "f84901843b9aca00827b0c945fbdb2315678afecb367f032d93f642f64180aa380a46057361d00000000000000000000000000000000000000000000000000000000000000048203e9808073efe1fa2d3e27f26f32208550ea9b0274d49050b816cadab05a771f4275d0242fd5d92b3fb89575c070e6c930587c520ee65a3aa8cfe382fcad20421bf51d621c"
sequences = append(sequences, proofofefficiency.ProofOfEfficiencySequence{
GlobalExitRoot: ger,
Timestamp: initBlock.Time(),
ForceBatchesNum: 0,
Transactions: common.Hex2Bytes(rawTxs),
})
sequences = append(sequences, proofofefficiency.ProofOfEfficiencySequence{
GlobalExitRoot: ger,
Timestamp: initBlock.Time() + 1,
ForceBatchesNum: 0,
Transactions: common.Hex2Bytes(rawTxs),
})
_, err = etherman.PoE.SequenceBatches(etherman.auth, sequences)
require.NoError(t, err)

// Mine the tx in a block
commit()

// Now read the event
finalBlock, err := etherman.EtherClient.BlockByNumber(ctx, nil)
require.NoError(t, err)
finalBlockNumber := finalBlock.NumberU64()
blocks, err := etherman.GetRollupInfoByBlockRange(ctx, initBlock.NumberU64(), &finalBlockNumber)
require.NoError(t, err)
assert.Equal(t, 2, len(blocks))
assert.Equal(t, 2, len(blocks[1].Sequences))
assert.Equal(t, common.Hex2Bytes(rawTxs), blocks[1].Sequences[1].Transactions)
assert.Equal(t, initBlock.Time(), blocks[1].Sequences[0].Timestamp)
assert.Equal(t, ger, blocks[1].Sequences[0].GlobalExitRoot)
assert.Equal(t, uint64(0), blocks[1].Sequences[1].ForceBatchesNum)
}
5 changes: 3 additions & 2 deletions statev2/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-core/ethermanv2/smartcontracts/proofofefficiency"
)

// Block struct
Expand All @@ -13,8 +14,8 @@ type Block struct {
ParentHash common.Hash
GlobalExitRoots []GlobalExitRoot
ForcedBatches []ForcedBatch

ReceivedAt time.Time
Sequences []proofofefficiency.ProofOfEfficiencySequence
ReceivedAt time.Time
}

// NewBlock creates a block with the given data.
Expand Down

0 comments on commit b86e253

Please sign in to comment.