github.com/ledgerwatch/erigon-lib@v1.0.0/types/txn_test.go (about)

     1  /*
     2     Copyright 2021 The Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package types
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/rand"
    22  	"strconv"
    23  	"testing"
    24  
    25  	gokzg4844 "github.com/crate-crypto/go-kzg-4844"
    26  	"github.com/holiman/uint256"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"github.com/ledgerwatch/erigon-lib/common/fixedgas"
    31  	"github.com/ledgerwatch/erigon-lib/common/hexutility"
    32  )
    33  
    34  func TestParseTransactionRLP(t *testing.T) {
    35  	for _, testSet := range allNetsTestCases {
    36  		testSet := testSet
    37  		t.Run(strconv.Itoa(int(testSet.chainID.Uint64())), func(t *testing.T) {
    38  			require := require.New(t)
    39  			ctx := NewTxParseContext(testSet.chainID)
    40  			tx, txSender := &TxSlot{}, [20]byte{}
    41  			for i, tt := range testSet.tests {
    42  				tt := tt
    43  				t.Run(strconv.Itoa(i), func(t *testing.T) {
    44  					payload := hexutility.MustDecodeHex(tt.PayloadStr)
    45  					parseEnd, err := ctx.ParseTransaction(payload, 0, tx, txSender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
    46  					require.NoError(err)
    47  					require.Equal(len(payload), parseEnd)
    48  					if tt.SignHashStr != "" {
    49  						signHash := hexutility.MustDecodeHex(tt.SignHashStr)
    50  						if !bytes.Equal(signHash, ctx.Sighash[:]) {
    51  							t.Errorf("signHash expected %x, got %x", signHash, ctx.Sighash)
    52  						}
    53  					}
    54  					if tt.IdHashStr != "" {
    55  						idHash := hexutility.MustDecodeHex(tt.IdHashStr)
    56  						if !bytes.Equal(idHash, tx.IDHash[:]) {
    57  							t.Errorf("IdHash expected %x, got %x", idHash, tx.IDHash)
    58  						}
    59  					}
    60  					if tt.SenderStr != "" {
    61  						expectSender := hexutility.MustDecodeHex(tt.SenderStr)
    62  						if !bytes.Equal(expectSender, txSender[:]) {
    63  							t.Errorf("expectSender expected %x, got %x", expectSender, txSender)
    64  						}
    65  					}
    66  					require.Equal(tt.Nonce, tx.Nonce)
    67  				})
    68  			}
    69  		})
    70  	}
    71  }
    72  
    73  func TestTransactionSignatureValidity1(t *testing.T) {
    74  	chainId := new(uint256.Int).SetUint64(1)
    75  	ctx := NewTxParseContext(*chainId)
    76  	ctx.WithAllowPreEip2s(true)
    77  
    78  	tx, txSender := &TxSlot{}, [20]byte{}
    79  	validTxn := hexutility.MustDecodeHex("f83f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870b801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a3664935301")
    80  	_, err := ctx.ParseTransaction(validTxn, 0, tx, txSender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
    81  	assert.NoError(t, err)
    82  
    83  	preEip2Txn := hexutility.MustDecodeHex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870b801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a07fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1")
    84  	_, err = ctx.ParseTransaction(preEip2Txn, 0, tx, txSender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
    85  	assert.NoError(t, err)
    86  
    87  	// Now enforce EIP-2
    88  	ctx.WithAllowPreEip2s(false)
    89  	_, err = ctx.ParseTransaction(validTxn, 0, tx, txSender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
    90  	assert.NoError(t, err)
    91  
    92  	_, err = ctx.ParseTransaction(preEip2Txn, 0, tx, txSender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
    93  	assert.Error(t, err)
    94  }
    95  
    96  // Problematic txn included in a bad block on Görli
    97  func TestTransactionSignatureValidity2(t *testing.T) {
    98  	chainId := new(uint256.Int).SetUint64(5)
    99  	ctx := NewTxParseContext(*chainId)
   100  	slot, sender := &TxSlot{}, [20]byte{}
   101  	rlp := hexutility.MustDecodeHex("02f8720513844190ab00848321560082520894cab441d2f45a3fee83d15c6b6b6c36a139f55b6288054607fc96a6000080c001a0dffe4cb5651e663d0eac8c4d002de734dd24db0f1109b062d17da290a133cc02a0913fb9f53f7a792bcd9e4d7cced1b8545d1ab82c77432b0bc2e9384ba6c250c5")
   102  	_, err := ctx.ParseTransaction(rlp, 0, slot, sender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
   103  	assert.Error(t, err)
   104  
   105  	// Only legacy transactions can happen before EIP-2
   106  	ctx.WithAllowPreEip2s(true)
   107  	_, err = ctx.ParseTransaction(rlp, 0, slot, sender[:], false /* hasEnvelope */, true /* wrappedWithBlobs */, nil)
   108  	assert.Error(t, err)
   109  }
   110  
   111  func TestTxSlotsGrowth(t *testing.T) {
   112  	assert := assert.New(t)
   113  	s := &TxSlots{}
   114  	s.Resize(11)
   115  	assert.Equal(11, len(s.Txs))
   116  	assert.Equal(11, s.Senders.Len())
   117  	s.Resize(23)
   118  	assert.Equal(23, len(s.Txs))
   119  	assert.Equal(23, s.Senders.Len())
   120  
   121  	s = &TxSlots{Txs: make([]*TxSlot, 20), Senders: make(Addresses, 20*20)}
   122  	s.Resize(20)
   123  	assert.Equal(20, len(s.Txs))
   124  	assert.Equal(20, s.Senders.Len())
   125  	s.Resize(23)
   126  	assert.Equal(23, len(s.Txs))
   127  	assert.Equal(23, s.Senders.Len())
   128  
   129  	s.Resize(2)
   130  	assert.Equal(2, len(s.Txs))
   131  	assert.Equal(2, s.Senders.Len())
   132  }
   133  
   134  func TestDedupHashes(t *testing.T) {
   135  	assert := assert.New(t)
   136  	h := toHashes(2, 6, 2, 5, 2, 4)
   137  	c := h.DedupCopy()
   138  	assert.Equal(6, h.Len())
   139  	assert.Equal(4, c.Len())
   140  	assert.Equal(toHashes(2, 2, 2, 4, 5, 6), h)
   141  	assert.Equal(toHashes(2, 4, 5, 6), c)
   142  
   143  	h = toHashes(2, 2)
   144  	c = h.DedupCopy()
   145  	assert.Equal(toHashes(2, 2), h)
   146  	assert.Equal(toHashes(2), c)
   147  
   148  	h = toHashes(1)
   149  	c = h.DedupCopy()
   150  	assert.Equal(1, h.Len())
   151  	assert.Equal(1, c.Len())
   152  	assert.Equal(toHashes(1), h)
   153  	assert.Equal(toHashes(1), c)
   154  
   155  	h = toHashes()
   156  	c = h.DedupCopy()
   157  	assert.Equal(0, h.Len())
   158  	assert.Equal(0, c.Len())
   159  	assert.Equal(0, len(h))
   160  	assert.Equal(0, len(c))
   161  
   162  	h = toHashes(1, 2, 3, 4)
   163  	c = h.DedupCopy()
   164  	assert.Equal(toHashes(1, 2, 3, 4), h)
   165  	assert.Equal(toHashes(1, 2, 3, 4), c)
   166  
   167  	h = toHashes(4, 2, 1, 3)
   168  	c = h.DedupCopy()
   169  	assert.Equal(toHashes(1, 2, 3, 4), h)
   170  	assert.Equal(toHashes(1, 2, 3, 4), c)
   171  
   172  }
   173  
   174  func toHashes(h ...byte) (out Hashes) {
   175  	for i := range h {
   176  		hash := [32]byte{h[i]}
   177  		out = append(out, hash[:]...)
   178  	}
   179  	return out
   180  }
   181  
   182  func TestBlobTxParsing(t *testing.T) {
   183  	// First parse a blob transaction body (no blobs/commitments/proofs)
   184  	wrappedWithBlobs := false
   185  	// Some arbitrary hardcoded example
   186  	bodyRlpHex := "f9012705078502540be4008506fc23ac008357b58494811a752c8cd697e3cb27" +
   187  		"279c330ed1ada745a8d7808204f7f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697b" +
   188  		"aef842a00000000000000000000000000000000000000000000000000000000000000003a000" +
   189  		"00000000000000000000000000000000000000000000000000000000000007d694bb9bc244d7" +
   190  		"98123fde783fcc1c72d3bb8c189413c07bf842a0c6bdd1de713471bd6cfa62dd8b5a5b42969e" +
   191  		"d09e26212d3377f3f8426d8ec210a08aaeccaf3873d07cef005aca28c39f8a9f8bdb1ec8d79f" +
   192  		"fc25afc0a4fa2ab73601a036b241b061a36a32ab7fe86c7aa9eb592dd59018cd0443adc09035" +
   193  		"90c16b02b0a05edcc541b4741c5cc6dd347c5ed9577ef293a62787b4510465fadbfe39ee4094"
   194  	bodyRlp := hexutility.MustDecodeHex(bodyRlpHex)
   195  
   196  	hasEnvelope := true
   197  	bodyEnvelope := hexutility.MustDecodeHex("b9012b03")
   198  	bodyEnvelope = append(bodyEnvelope, bodyRlp...)
   199  
   200  	ctx := NewTxParseContext(*uint256.NewInt(5))
   201  	ctx.withSender = false
   202  
   203  	var thinTx TxSlot // only tx body, no blobs
   204  	txType, err := PeekTransactionType(bodyEnvelope)
   205  	require.NoError(t, err)
   206  	assert.Equal(t, BlobTxType, txType)
   207  
   208  	p, err := ctx.ParseTransaction(bodyEnvelope, 0, &thinTx, nil, hasEnvelope, wrappedWithBlobs, nil)
   209  	require.NoError(t, err)
   210  	assert.Equal(t, len(bodyEnvelope), p)
   211  	assert.Equal(t, len(bodyEnvelope), int(thinTx.Size))
   212  	assert.Equal(t, bodyEnvelope[3:], thinTx.Rlp)
   213  	assert.Equal(t, BlobTxType, thinTx.Type)
   214  	assert.Equal(t, 2, len(thinTx.BlobHashes))
   215  	assert.Equal(t, 0, len(thinTx.Blobs))
   216  	assert.Equal(t, 0, len(thinTx.Commitments))
   217  	assert.Equal(t, 0, len(thinTx.Proofs))
   218  
   219  	// Now parse the same tx body, but wrapped with blobs/commitments/proofs
   220  	wrappedWithBlobs = true
   221  	hasEnvelope = false
   222  
   223  	blobsRlpPrefix := hexutility.MustDecodeHex("fa040008")
   224  	blobRlpPrefix := hexutility.MustDecodeHex("ba020000")
   225  	blob0 := make([]byte, fixedgas.BlobSize)
   226  	rand.Read(blob0)
   227  	blob1 := make([]byte, fixedgas.BlobSize)
   228  	rand.Read(blob1)
   229  
   230  	proofsRlpPrefix := hexutility.MustDecodeHex("f862")
   231  	var commitment0, commitment1 gokzg4844.KZGCommitment
   232  	rand.Read(commitment0[:])
   233  	rand.Read(commitment1[:])
   234  	var proof0, proof1 gokzg4844.KZGProof
   235  	rand.Read(proof0[:])
   236  	rand.Read(proof1[:])
   237  
   238  	wrapperRlp := hexutility.MustDecodeHex("03fa0401fe")
   239  	wrapperRlp = append(wrapperRlp, bodyRlp...)
   240  	wrapperRlp = append(wrapperRlp, blobsRlpPrefix...)
   241  	wrapperRlp = append(wrapperRlp, blobRlpPrefix...)
   242  	wrapperRlp = append(wrapperRlp, blob0...)
   243  	wrapperRlp = append(wrapperRlp, blobRlpPrefix...)
   244  	wrapperRlp = append(wrapperRlp, blob1...)
   245  	wrapperRlp = append(wrapperRlp, proofsRlpPrefix...)
   246  	wrapperRlp = append(wrapperRlp, 0xb0)
   247  	wrapperRlp = append(wrapperRlp, commitment0[:]...)
   248  	wrapperRlp = append(wrapperRlp, 0xb0)
   249  	wrapperRlp = append(wrapperRlp, commitment1[:]...)
   250  	wrapperRlp = append(wrapperRlp, proofsRlpPrefix...)
   251  	wrapperRlp = append(wrapperRlp, 0xb0)
   252  	wrapperRlp = append(wrapperRlp, proof0[:]...)
   253  	wrapperRlp = append(wrapperRlp, 0xb0)
   254  	wrapperRlp = append(wrapperRlp, proof1[:]...)
   255  
   256  	var fatTx TxSlot // with blobs/commitments/proofs
   257  	txType, err = PeekTransactionType(wrapperRlp)
   258  	require.NoError(t, err)
   259  	assert.Equal(t, BlobTxType, txType)
   260  
   261  	p, err = ctx.ParseTransaction(wrapperRlp, 0, &fatTx, nil, hasEnvelope, wrappedWithBlobs, nil)
   262  	require.NoError(t, err)
   263  	assert.Equal(t, len(wrapperRlp), p)
   264  	assert.Equal(t, len(wrapperRlp), int(fatTx.Size))
   265  	assert.Equal(t, wrapperRlp, fatTx.Rlp)
   266  	assert.Equal(t, BlobTxType, fatTx.Type)
   267  
   268  	assert.Equal(t, thinTx.Value, fatTx.Value)
   269  	assert.Equal(t, thinTx.Tip, fatTx.Tip)
   270  	assert.Equal(t, thinTx.FeeCap, fatTx.FeeCap)
   271  	assert.Equal(t, thinTx.Nonce, fatTx.Nonce)
   272  	assert.Equal(t, thinTx.DataLen, fatTx.DataLen)
   273  	assert.Equal(t, thinTx.DataNonZeroLen, fatTx.DataNonZeroLen)
   274  	assert.Equal(t, thinTx.AlAddrCount, fatTx.AlAddrCount)
   275  	assert.Equal(t, thinTx.AlStorCount, fatTx.AlStorCount)
   276  	assert.Equal(t, thinTx.Gas, fatTx.Gas)
   277  	assert.Equal(t, thinTx.IDHash, fatTx.IDHash)
   278  	assert.Equal(t, thinTx.Creation, fatTx.Creation)
   279  	assert.Equal(t, thinTx.BlobFeeCap, fatTx.BlobFeeCap)
   280  	assert.Equal(t, thinTx.BlobHashes, fatTx.BlobHashes)
   281  
   282  	require.Equal(t, 2, len(fatTx.Blobs))
   283  	require.Equal(t, 2, len(fatTx.Commitments))
   284  	require.Equal(t, 2, len(fatTx.Proofs))
   285  	assert.Equal(t, blob0, fatTx.Blobs[0])
   286  	assert.Equal(t, blob1, fatTx.Blobs[1])
   287  	assert.Equal(t, commitment0, fatTx.Commitments[0])
   288  	assert.Equal(t, commitment1, fatTx.Commitments[1])
   289  	assert.Equal(t, proof0, fatTx.Proofs[0])
   290  	assert.Equal(t, proof1, fatTx.Proofs[1])
   291  }