Merge tag 'v1.10.8' into develop

This commit is contained in:
Austin Roberts
2021-10-18 11:17:14 -05:00
50 changed files with 1013 additions and 590 deletions
-14
View File
@@ -248,8 +248,6 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
return params.RinkebyChainConfig
case ghash == params.GoerliGenesisHash:
return params.GoerliChainConfig
case ghash == params.CalaverasGenesisHash:
return params.CalaverasChainConfig
default:
return params.AllEthashProtocolChanges
}
@@ -399,18 +397,6 @@ func DefaultGoerliGenesisBlock() *Genesis {
}
}
func DefaultCalaverasGenesisBlock() *Genesis {
// Full genesis: https://gist.github.com/holiman/c6ed9269dce28304ad176314caa75e97
return &Genesis{
Config: params.CalaverasChainConfig,
Timestamp: 0x60b3877f,
ExtraData: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000005211cea3870c7ba7c6c44b185e62eecdb864cd8c560228ce57d31efbf64c200b2c200aacec78cf17a7148e784fe95a7a750335f8b9572ee28d72e7650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
GasLimit: 0x47b760,
Difficulty: big.NewInt(1),
Alloc: decodePrealloc(calaverasAllocData),
}
}
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
// Override the default period to the user requested one
-4
View File
@@ -185,10 +185,6 @@ func TestGenesisHashes(t *testing.T) {
genesis: DefaultRinkebyGenesisBlock(),
hash: params.RinkebyGenesisHash,
},
{
genesis: DefaultCalaverasGenesisBlock(),
hash: params.CalaverasGenesisHash,
},
}
for i, c := range cases {
b := c.genesis.MustCommit(rawdb.NewMemoryDatabase())
+5
View File
@@ -89,6 +89,11 @@ func (db *nofreezedb) Ancient(kind string, number uint64) ([]byte, error) {
return nil, errNotSupported
}
// ReadAncients returns an error as we don't have a backing chain freezer.
func (db *nofreezedb) ReadAncients(kind string, start, max, maxByteSize uint64) ([][]byte, error) {
return nil, errNotSupported
}
// Ancients returns an error as we don't have a backing chain freezer.
func (db *nofreezedb) Ancients() (uint64, error) {
return 0, errNotSupported
+13 -1
View File
@@ -180,6 +180,18 @@ func (f *freezer) Ancient(kind string, number uint64) ([]byte, error) {
return nil, errUnknownTable
}
// ReadAncients retrieves multiple items in sequence, starting from the index 'start'.
// It will return
// - at most 'max' items,
// - at least 1 item (even if exceeding the maxByteSize), but will otherwise
// return as many items as fit into maxByteSize.
func (f *freezer) ReadAncients(kind string, start, count, maxBytes uint64) ([][]byte, error) {
if table := f.tables[kind]; table != nil {
return table.RetrieveItems(start, count, maxBytes)
}
return nil, errUnknownTable
}
// Ancients returns the length of the frozen items.
func (f *freezer) Ancients() (uint64, error) {
return atomic.LoadUint64(&f.frozen), nil
@@ -403,7 +415,7 @@ func (f *freezer) freeze(db ethdb.KeyValueStore) {
}
batch.Reset()
// Wipe out side chains also and track dangling side chians
// Wipe out side chains also and track dangling side chains
var dangling []common.Hash
for number := first; number < f.frozen; number++ {
// Always keep the genesis block in active database
+163 -51
View File
@@ -70,6 +70,19 @@ func (i *indexEntry) marshallBinary() []byte {
return b
}
// bounds returns the start- and end- offsets, and the file number of where to
// read there data item marked by the two index entries. The two entries are
// assumed to be sequential.
func (start *indexEntry) bounds(end *indexEntry) (startOffset, endOffset, fileId uint32) {
if start.filenum != end.filenum {
// If a piece of data 'crosses' a data-file,
// it's actually in one piece on the second data-file.
// We return a zero-indexEntry for the second file as start
return 0, end.offset, end.filenum
}
return start.offset, end.offset, end.filenum
}
// freezerTable represents a single chained data table within the freezer (e.g. blocks).
// It consists of a data file (snappy encoded arbitrary data blobs) and an indexEntry
// file (uncompressed 64 bit indices into the data file).
@@ -546,84 +559,183 @@ func (t *freezerTable) append(item uint64, encodedBlob []byte, wlock bool) (bool
return false, nil
}
// getBounds returns the indexes for the item
// returns start, end, filenumber and error
func (t *freezerTable) getBounds(item uint64) (uint32, uint32, uint32, error) {
buffer := make([]byte, indexEntrySize)
var startIdx, endIdx indexEntry
// Read second index
if _, err := t.index.ReadAt(buffer, int64((item+1)*indexEntrySize)); err != nil {
return 0, 0, 0, err
// getIndices returns the index entries for the given from-item, covering 'count' items.
// N.B: The actual number of returned indices for N items will always be N+1 (unless an
// error is returned).
// OBS: This method assumes that the caller has already verified (and/or trimmed) the range
// so that the items are within bounds. If this method is used to read out of bounds,
// it will return error.
func (t *freezerTable) getIndices(from, count uint64) ([]*indexEntry, error) {
// Apply the table-offset
from = from - uint64(t.itemOffset)
// For reading N items, we need N+1 indices.
buffer := make([]byte, (count+1)*indexEntrySize)
if _, err := t.index.ReadAt(buffer, int64(from*indexEntrySize)); err != nil {
return nil, err
}
endIdx.unmarshalBinary(buffer)
// Read first index (unless it's the very first item)
if item != 0 {
if _, err := t.index.ReadAt(buffer, int64(item*indexEntrySize)); err != nil {
return 0, 0, 0, err
}
startIdx.unmarshalBinary(buffer)
} else {
var (
indices []*indexEntry
offset int
)
for i := from; i <= from+count; i++ {
index := new(indexEntry)
index.unmarshalBinary(buffer[offset:])
offset += indexEntrySize
indices = append(indices, index)
}
if from == 0 {
// Special case if we're reading the first item in the freezer. We assume that
// the first item always start from zero(regarding the deletion, we
// only support deletion by files, so that the assumption is held).
// This means we can use the first item metadata to carry information about
// the 'global' offset, for the deletion-case
return 0, endIdx.offset, endIdx.filenum, nil
indices[0].offset = 0
indices[0].filenum = indices[1].filenum
}
if startIdx.filenum != endIdx.filenum {
// If a piece of data 'crosses' a data-file,
// it's actually in one piece on the second data-file.
// We return a zero-indexEntry for the second file as start
return 0, endIdx.offset, endIdx.filenum, nil
}
return startIdx.offset, endIdx.offset, endIdx.filenum, nil
return indices, nil
}
// Retrieve looks up the data offset of an item with the given number and retrieves
// the raw binary blob from the data file.
func (t *freezerTable) Retrieve(item uint64) ([]byte, error) {
blob, err := t.retrieve(item)
items, err := t.RetrieveItems(item, 1, 0)
if err != nil {
return nil, err
}
if t.noCompression {
return blob, nil
}
return snappy.Decode(nil, blob)
return items[0], nil
}
// retrieve looks up the data offset of an item with the given number and retrieves
// the raw binary blob from the data file. OBS! This method does not decode
// compressed data.
func (t *freezerTable) retrieve(item uint64) ([]byte, error) {
// RetrieveItems returns multiple items in sequence, starting from the index 'start'.
// It will return at most 'max' items, but will abort earlier to respect the
// 'maxBytes' argument. However, if the 'maxBytes' is smaller than the size of one
// item, it _will_ return one element and possibly overflow the maxBytes.
func (t *freezerTable) RetrieveItems(start, count, maxBytes uint64) ([][]byte, error) {
// First we read the 'raw' data, which might be compressed.
diskData, sizes, err := t.retrieveItems(start, count, maxBytes)
if err != nil {
return nil, err
}
var (
output = make([][]byte, 0, count)
offset int // offset for reading
outputSize int // size of uncompressed data
)
// Now slice up the data and decompress.
for i, diskSize := range sizes {
item := diskData[offset : offset+diskSize]
offset += diskSize
decompressedSize := diskSize
if !t.noCompression {
decompressedSize, _ = snappy.DecodedLen(item)
}
if i > 0 && uint64(outputSize+decompressedSize) > maxBytes {
break
}
if !t.noCompression {
data, err := snappy.Decode(nil, item)
if err != nil {
return nil, err
}
output = append(output, data)
} else {
output = append(output, item)
}
outputSize += decompressedSize
}
return output, nil
}
// retrieveItems reads up to 'count' items from the table. It reads at least
// one item, but otherwise avoids reading more than maxBytes bytes.
// It returns the (potentially compressed) data, and the sizes.
func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []int, error) {
t.lock.RLock()
defer t.lock.RUnlock()
// Ensure the table and the item is accessible
if t.index == nil || t.head == nil {
return nil, errClosed
return nil, nil, errClosed
}
if atomic.LoadUint64(&t.items) <= item {
return nil, errOutOfBounds
itemCount := atomic.LoadUint64(&t.items) // max number
// Ensure the start is written, not deleted from the tail, and that the
// caller actually wants something
if itemCount <= start || uint64(t.itemOffset) > start || count == 0 {
return nil, nil, errOutOfBounds
}
// Ensure the item was not deleted from the tail either
if uint64(t.itemOffset) > item {
return nil, errOutOfBounds
if start+count > itemCount {
count = itemCount - start
}
startOffset, endOffset, filenum, err := t.getBounds(item - uint64(t.itemOffset))
var (
output = make([]byte, maxBytes) // Buffer to read data into
outputSize int // Used size of that buffer
)
// readData is a helper method to read a single data item from disk.
readData := func(fileId, start uint32, length int) error {
// In case a small limit is used, and the elements are large, may need to
// realloc the read-buffer when reading the first (and only) item.
if len(output) < length {
output = make([]byte, length)
}
dataFile, exist := t.files[fileId]
if !exist {
return fmt.Errorf("missing data file %d", fileId)
}
if _, err := dataFile.ReadAt(output[outputSize:outputSize+length], int64(start)); err != nil {
return err
}
outputSize += length
return nil
}
// Read all the indexes in one go
indices, err := t.getIndices(start, count)
if err != nil {
return nil, err
return nil, nil, err
}
dataFile, exist := t.files[filenum]
if !exist {
return nil, fmt.Errorf("missing data file %d", filenum)
var (
sizes []int // The sizes for each element
totalSize = 0 // The total size of all data read so far
readStart = indices[0].offset // Where, in the file, to start reading
unreadSize = 0 // The size of the as-yet-unread data
)
for i, firstIndex := range indices[:len(indices)-1] {
secondIndex := indices[i+1]
// Determine the size of the item.
offset1, offset2, _ := firstIndex.bounds(secondIndex)
size := int(offset2 - offset1)
// Crossing a file boundary?
if secondIndex.filenum != firstIndex.filenum {
// If we have unread data in the first file, we need to do that read now.
if unreadSize > 0 {
if err := readData(firstIndex.filenum, readStart, unreadSize); err != nil {
return nil, nil, err
}
unreadSize = 0
}
readStart = 0
}
if i > 0 && uint64(totalSize+size) > maxBytes {
// About to break out due to byte limit being exceeded. We don't
// read this last item, but we need to do the deferred reads now.
if unreadSize > 0 {
if err := readData(secondIndex.filenum, readStart, unreadSize); err != nil {
return nil, nil, err
}
}
break
}
// Defer the read for later
unreadSize += size
totalSize += size
sizes = append(sizes, size)
if i == len(indices)-2 || uint64(totalSize) > maxBytes {
// Last item, need to do the read now
if err := readData(secondIndex.filenum, readStart, unreadSize); err != nil {
return nil, nil, err
}
break
}
}
// Retrieve the data itself, decompress and return
blob := make([]byte, endOffset-startOffset)
if _, err := dataFile.ReadAt(blob, int64(startOffset)); err != nil {
return nil, err
}
t.readMeter.Mark(int64(len(blob) + 2*indexEntrySize))
return blob, nil
return output[:outputSize], sizes, nil
}
// has returns an indicator whether the specified number data
+116 -1
View File
@@ -74,7 +74,7 @@ func TestFreezerBasics(t *testing.T) {
exp := getChunk(15, y)
got, err := f.Retrieve(uint64(y))
if err != nil {
t.Fatal(err)
t.Fatalf("reading item %d: %v", y, err)
}
if !bytes.Equal(got, exp) {
t.Fatalf("test %d, got \n%x != \n%x", y, got, exp)
@@ -692,3 +692,118 @@ func TestAppendTruncateParallel(t *testing.T) {
}
}
}
// TestSequentialRead does some basic tests on the RetrieveItems.
func TestSequentialRead(t *testing.T) {
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
fname := fmt.Sprintf("batchread-%d", rand.Uint64())
{ // Fill table
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
if err != nil {
t.Fatal(err)
}
// Write 15 bytes 30 times
for x := 0; x < 30; x++ {
data := getChunk(15, x)
f.Append(uint64(x), data)
}
f.DumpIndex(0, 30)
f.Close()
}
{ // Open it, iterate, verify iteration
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 50, true)
if err != nil {
t.Fatal(err)
}
items, err := f.RetrieveItems(0, 10000, 100000)
if err != nil {
t.Fatal(err)
}
if have, want := len(items), 30; have != want {
t.Fatalf("want %d items, have %d ", want, have)
}
for i, have := range items {
want := getChunk(15, i)
if !bytes.Equal(want, have) {
t.Fatalf("data corruption: have\n%x\n, want \n%x\n", have, want)
}
}
f.Close()
}
{ // Open it, iterate, verify byte limit. The byte limit is less than item
// size, so each lookup should only return one item
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 40, true)
if err != nil {
t.Fatal(err)
}
items, err := f.RetrieveItems(0, 10000, 10)
if err != nil {
t.Fatal(err)
}
if have, want := len(items), 1; have != want {
t.Fatalf("want %d items, have %d ", want, have)
}
for i, have := range items {
want := getChunk(15, i)
if !bytes.Equal(want, have) {
t.Fatalf("data corruption: have\n%x\n, want \n%x\n", have, want)
}
}
f.Close()
}
}
// TestSequentialReadByteLimit does some more advanced tests on batch reads.
// These tests check that when the byte limit hits, we correctly abort in time,
// but also properly do all the deferred reads for the previous data, regardless
// of whether the data crosses a file boundary or not.
func TestSequentialReadByteLimit(t *testing.T) {
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
fname := fmt.Sprintf("batchread-2-%d", rand.Uint64())
{ // Fill table
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 100, true)
if err != nil {
t.Fatal(err)
}
// Write 10 bytes 30 times,
// Splitting it at every 100 bytes (10 items)
for x := 0; x < 30; x++ {
data := getChunk(10, x)
f.Append(uint64(x), data)
}
f.Close()
}
for i, tc := range []struct {
items uint64
limit uint64
want int
}{
{9, 89, 8},
{10, 99, 9},
{11, 109, 10},
{100, 89, 8},
{100, 99, 9},
{100, 109, 10},
} {
{
f, err := newCustomTable(os.TempDir(), fname, rm, wm, sg, 100, true)
if err != nil {
t.Fatal(err)
}
items, err := f.RetrieveItems(0, tc.items, tc.limit)
if err != nil {
t.Fatal(err)
}
if have, want := len(items), tc.want; have != want {
t.Fatalf("test %d: want %d items, have %d ", i, want, have)
}
for ii, have := range items {
want := getChunk(10, ii)
if !bytes.Equal(want, have) {
t.Fatalf("test %d: data corruption item %d: have\n%x\n, want \n%x\n", i, ii, have, want)
}
}
f.Close()
}
}
}
+6
View File
@@ -62,6 +62,12 @@ func (t *table) Ancient(kind string, number uint64) ([]byte, error) {
return t.db.Ancient(kind, number)
}
// ReadAncients is a noop passthrough that just forwards the request to the underlying
// database.
func (t *table) ReadAncients(kind string, start, count, maxBytes uint64) ([][]byte, error) {
return t.db.ReadAncients(kind, start, count, maxBytes)
}
// Ancients is a noop passthrough that just forwards the request to the underlying
// database.
func (t *table) Ancients() (uint64, error) {
+9 -8
View File
@@ -74,7 +74,7 @@ type Message interface {
Value() *big.Int
Nonce() uint64
CheckNonce() bool
IsFake() bool
Data() []byte
AccessList() types.AccessList
}
@@ -212,8 +212,9 @@ func (st *StateTransition) buyGas() error {
}
func (st *StateTransition) preCheck() error {
// Make sure this transaction's nonce is correct.
if st.msg.CheckNonce() {
// Only check transactions that are not fake
if !st.msg.IsFake() {
// Make sure this transaction's nonce is correct.
stNonce := st.state.GetNonce(st.msg.From())
if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
@@ -222,11 +223,11 @@ func (st *StateTransition) preCheck() error {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
st.msg.From().Hex(), msgNonce, stNonce)
}
}
// Make sure the sender is an EOA
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
st.msg.From().Hex(), codeHash)
// Make sure the sender is an EOA
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
st.msg.From().Hex(), codeHash)
}
}
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
+5 -5
View File
@@ -579,10 +579,10 @@ type Message struct {
gasTipCap *big.Int
data []byte
accessList AccessList
checkNonce bool
isFake bool
}
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, accessList AccessList, checkNonce bool) Message {
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, accessList AccessList, isFake bool) Message {
return Message{
from: from,
to: to,
@@ -594,7 +594,7 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
gasTipCap: gasTipCap,
data: data,
accessList: accessList,
checkNonce: checkNonce,
isFake: isFake,
}
}
@@ -610,7 +610,7 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
amount: tx.Value(),
data: tx.Data(),
accessList: tx.AccessList(),
checkNonce: true,
isFake: false,
}
// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
@@ -631,4 +631,4 @@ func (m Message) Gas() uint64 { return m.gasLimit }
func (m Message) Nonce() uint64 { return m.nonce }
func (m Message) Data() []byte { return m.data }
func (m Message) AccessList() AccessList { return m.accessList }
func (m Message) CheckNonce() bool { return m.checkNonce }
func (m Message) IsFake() bool { return m.isFake }
+78 -16
View File
@@ -16,17 +16,49 @@
package vm
const (
set2BitsMask = uint16(0b1100_0000_0000_0000)
set3BitsMask = uint16(0b1110_0000_0000_0000)
set4BitsMask = uint16(0b1111_0000_0000_0000)
set5BitsMask = uint16(0b1111_1000_0000_0000)
set6BitsMask = uint16(0b1111_1100_0000_0000)
set7BitsMask = uint16(0b1111_1110_0000_0000)
)
// bitvec is a bit vector which maps bytes in a program.
// An unset bit means the byte is an opcode, a set bit means
// it's data (i.e. argument of PUSHxx).
type bitvec []byte
func (bits *bitvec) set(pos uint64) {
(*bits)[pos/8] |= 0x80 >> (pos % 8)
var lookup = [8]byte{
0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1,
}
func (bits *bitvec) set8(pos uint64) {
(*bits)[pos/8] |= 0xFF >> (pos % 8)
(*bits)[pos/8+1] |= ^(0xFF >> (pos % 8))
func (bits bitvec) set1(pos uint64) {
bits[pos/8] |= lookup[pos%8]
}
func (bits bitvec) setN(flag uint16, pos uint64) {
a := flag >> (pos % 8)
bits[pos/8] |= byte(a >> 8)
if b := byte(a); b != 0 {
// If the bit-setting affects the neighbouring byte, we can assign - no need to OR it,
// since it's the first write to that byte
bits[pos/8+1] = b
}
}
func (bits bitvec) set8(pos uint64) {
a := byte(0xFF >> (pos % 8))
bits[pos/8] |= a
bits[pos/8+1] = ^a
}
func (bits bitvec) set16(pos uint64) {
a := byte(0xFF >> (pos % 8))
bits[pos/8] |= a
bits[pos/8+1] = 0xFF
bits[pos/8+2] = ^a
}
// codeSegment checks if the position is in a code segment.
@@ -40,22 +72,52 @@ func codeBitmap(code []byte) bitvec {
// ends with a PUSH32, the algorithm will push zeroes onto the
// bitvector outside the bounds of the actual code.
bits := make(bitvec, len(code)/8+1+4)
return codeBitmapInternal(code, bits)
}
// codeBitmapInternal is the internal implementation of codeBitmap.
// It exists for the purpose of being able to run benchmark tests
// without dynamic allocations affecting the results.
func codeBitmapInternal(code, bits bitvec) bitvec {
for pc := uint64(0); pc < uint64(len(code)); {
op := OpCode(code[pc])
if op >= PUSH1 && op <= PUSH32 {
numbits := op - PUSH1 + 1
pc++
pc++
if op < PUSH1 || op > PUSH32 {
continue
}
numbits := op - PUSH1 + 1
if numbits >= 8 {
for ; numbits >= 16; numbits -= 16 {
bits.set16(pc)
pc += 16
}
for ; numbits >= 8; numbits -= 8 {
bits.set8(pc) // 8
bits.set8(pc)
pc += 8
}
for ; numbits > 0; numbits-- {
bits.set(pc)
pc++
}
} else {
pc++
}
switch numbits {
case 1:
bits.set1(pc)
pc += 1
case 2:
bits.setN(set2BitsMask, pc)
pc += 2
case 3:
bits.setN(set3BitsMask, pc)
pc += 3
case 4:
bits.setN(set4BitsMask, pc)
pc += 4
case 5:
bits.setN(set5BitsMask, pc)
pc += 5
case 6:
bits.setN(set6BitsMask, pc)
pc += 6
case 7:
bits.setN(set7BitsMask, pc)
pc += 7
}
}
return bits
+22 -2
View File
@@ -47,10 +47,10 @@ func TestJumpDestAnalysis(t *testing.T) {
{[]byte{byte(PUSH32)}, 0xFF, 1},
{[]byte{byte(PUSH32)}, 0xFF, 2},
}
for _, test := range tests {
for i, test := range tests {
ret := codeBitmap(test.code)
if ret[test.which] != test.exp {
t.Fatalf("expected %x, got %02x", test.exp, ret[test.which])
t.Fatalf("test %d: expected %x, got %02x", i, test.exp, ret[test.which])
}
}
}
@@ -73,3 +73,23 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
}
bench.StopTimer()
}
func BenchmarkJumpdestOpAnalysis(bench *testing.B) {
var op OpCode
bencher := func(b *testing.B) {
code := make([]byte, 32*b.N)
for i := range code {
code[i] = byte(op)
}
bits := make(bitvec, len(code)/8+1+4)
b.ResetTimer()
codeBitmapInternal(code, bits)
}
for op = PUSH1; op <= PUSH32; op++ {
bench.Run(op.String(), bencher)
}
op = JUMPDEST
bench.Run(op.String(), bencher)
op = STOP
bench.Run(op.String(), bencher)
}
+4
View File
@@ -669,6 +669,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.Gas += returnGas
@@ -703,6 +704,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.Gas += returnGas
@@ -730,6 +732,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.Gas += returnGas
@@ -757,6 +760,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
stack.push(&temp)
if err == nil || err == ErrExecutionReverted {
ret = common.CopyBytes(ret)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
scope.Contract.Gas += returnGas
+1 -1
View File
@@ -262,7 +262,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// if the operation clears the return data (e.g. it has returning data)
// set the last return to the result of the operation.
if operation.returns {
in.returnData = common.CopyBytes(res)
in.returnData = res
}
switch {