core/vm: clean up code and containerOffset handling
This commit is contained in:
parent
5bfacf4ba2
commit
644823db48
103
core/vm/eof.go
103
core/vm/eof.go
|
@ -67,12 +67,9 @@ func isEOFVersion1(code []byte) bool {
|
|||
// Container is an EOF container object.
|
||||
type Container struct {
|
||||
types []*functionMetadata
|
||||
codeSectionOffsets []int
|
||||
codeSectionEnd int
|
||||
codeSectionOffsets []int // contains all the offsets of the codeSections. The last item marks the end
|
||||
subContainers []*Container
|
||||
subContainerOffsets []int
|
||||
subContainerEnd int
|
||||
dataOffest int
|
||||
subContainerOffsets []int // contains all the offsets of the subContainers. The last item marks the end
|
||||
dataSize int // might be more than len(data)
|
||||
rawContainer []byte
|
||||
}
|
||||
|
@ -108,48 +105,44 @@ func (meta *functionMetadata) checkStackMax(stackMax int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Container) codeSectionSize(s int) int {
|
||||
if s >= len(c.codeSectionOffsets) || s < 0 {
|
||||
return 0
|
||||
} else if s == len(c.codeSectionOffsets)-1 {
|
||||
return c.codeSectionEnd - c.codeSectionOffsets[s]
|
||||
}
|
||||
return c.codeSectionOffsets[s+1] - c.codeSectionOffsets[s]
|
||||
}
|
||||
|
||||
func (c *Container) codeSectionBytes(s int) []byte {
|
||||
if s >= len(c.codeSectionOffsets) || s < 0 {
|
||||
// codeSectionAt returns the code section at index.
|
||||
// returns an empty slice if the index is out of bounds.
|
||||
func (c *Container) codeSectionAt(index int) []byte {
|
||||
if index >= len(c.codeSectionOffsets)-1 || index < 0 {
|
||||
return c.rawContainer[0:0]
|
||||
} else if s == len(c.codeSectionOffsets)-1 {
|
||||
return c.rawContainer[c.codeSectionOffsets[s]:c.codeSectionEnd]
|
||||
}
|
||||
return c.rawContainer[c.codeSectionOffsets[s]:c.codeSectionOffsets[s+1]]
|
||||
return c.rawContainer[c.codeSectionOffsets[index]:c.codeSectionOffsets[index+1]]
|
||||
}
|
||||
|
||||
func (c *Container) subContainerSize(s int) int {
|
||||
if s >= len(c.subContainerOffsets) || s < 0 {
|
||||
return 0
|
||||
} else if s == len(c.subContainerOffsets)-1 {
|
||||
return c.subContainerEnd - c.subContainerOffsets[s]
|
||||
}
|
||||
return c.subContainerOffsets[s+1] - c.subContainerOffsets[s]
|
||||
}
|
||||
|
||||
func (c *Container) subContainerBytes(s int) []byte {
|
||||
if s >= len(c.subContainerOffsets) || s < 0 {
|
||||
// subContainerAt returns the sub container at index.
|
||||
// returns an empty slice if the index is out of bounds.
|
||||
func (c *Container) subContainerAt(index int) []byte {
|
||||
if index >= len(c.subContainerOffsets)-1 || index < 0 {
|
||||
return c.rawContainer[0:0]
|
||||
} else if s == len(c.subContainerOffsets)-1 {
|
||||
return c.rawContainer[c.subContainerOffsets[s]:c.subContainerEnd]
|
||||
}
|
||||
return c.rawContainer[c.subContainerOffsets[s]:c.subContainerOffsets[s+1]]
|
||||
return c.rawContainer[c.subContainerOffsets[index]:c.subContainerOffsets[index+1]]
|
||||
}
|
||||
|
||||
func (c *Container) dataOffset() int {
|
||||
if len(c.subContainerOffsets) > 0 {
|
||||
return c.subContainerOffsets[len(c.subContainerOffsets)-1]
|
||||
}
|
||||
return c.codeSectionOffsets[len(c.codeSectionOffsets)-1]
|
||||
}
|
||||
|
||||
func (c *Container) dataLen() int {
|
||||
return len(c.rawContainer) - c.dataOffest
|
||||
return len(c.rawContainer) - c.dataOffset()
|
||||
}
|
||||
|
||||
func (c *Container) getDataAt(offset, length uint64) []byte {
|
||||
return getData(c.rawContainer, uint64(c.dataOffset())+offset, length)
|
||||
}
|
||||
|
||||
// MarshalBinary encodes an EOF container into binary format.
|
||||
func (c *Container) MarshalBinary() []byte {
|
||||
// Drop the end markers
|
||||
codeSectionOffsets := c.codeSectionOffsets[:len(c.codeSectionOffsets)-1]
|
||||
|
||||
// Build EOF prefix.
|
||||
b := make([]byte, 2)
|
||||
copy(b, eofMagic)
|
||||
|
@ -159,9 +152,9 @@ func (c *Container) MarshalBinary() []byte {
|
|||
b = append(b, kindTypes)
|
||||
b = binary.BigEndian.AppendUint16(b, uint16(len(c.types)*4))
|
||||
b = append(b, kindCode)
|
||||
b = binary.BigEndian.AppendUint16(b, uint16(len(c.codeSectionOffsets)))
|
||||
for s := range c.codeSectionOffsets {
|
||||
b = binary.BigEndian.AppendUint16(b, uint16(c.codeSectionSize(s)))
|
||||
b = binary.BigEndian.AppendUint16(b, uint16(len(codeSectionOffsets)))
|
||||
for s := range codeSectionOffsets {
|
||||
b = binary.BigEndian.AppendUint16(b, uint16(len(c.codeSectionAt(s))))
|
||||
}
|
||||
var encodedContainer [][]byte
|
||||
if len(c.subContainers) != 0 {
|
||||
|
@ -181,13 +174,13 @@ func (c *Container) MarshalBinary() []byte {
|
|||
for _, ty := range c.types {
|
||||
b = append(b, []byte{ty.inputs, ty.outputs, byte(ty.maxStackHeight >> 8), byte(ty.maxStackHeight & 0x00ff)}...)
|
||||
}
|
||||
for s := range c.codeSectionOffsets {
|
||||
b = append(b, c.codeSectionBytes(s)...)
|
||||
for s := range codeSectionOffsets {
|
||||
b = append(b, c.codeSectionAt(s)...)
|
||||
}
|
||||
for _, section := range encodedContainer {
|
||||
b = append(b, section...)
|
||||
}
|
||||
b = append(b, c.rawContainer[c.dataOffest:]...)
|
||||
b = append(b, c.rawContainer[c.dataOffset():]...)
|
||||
|
||||
return b
|
||||
}
|
||||
|
@ -333,8 +326,8 @@ func (c *Container) unmarshalContainer(b []byte, isInitcode bool, topLevel bool)
|
|||
codeSectionOffsets[i] = idx
|
||||
idx += size
|
||||
}
|
||||
c.codeSectionOffsets = codeSectionOffsets
|
||||
c.codeSectionEnd = idx
|
||||
// add the end marker to the codeSection offsets
|
||||
c.codeSectionOffsets = append(codeSectionOffsets, idx)
|
||||
// Parse the optional container sizes.
|
||||
if len(containerSizes) != 0 {
|
||||
if len(containerSizes) > maxContainerSections {
|
||||
|
@ -360,15 +353,14 @@ func (c *Container) unmarshalContainer(b []byte, isInitcode bool, topLevel bool)
|
|||
idx += size
|
||||
}
|
||||
c.subContainers = subContainers
|
||||
c.subContainerEnd = idx
|
||||
c.subContainerOffsets = subContainerOffsets
|
||||
// add the end marker to the subContainer offsets
|
||||
c.subContainerOffsets = append(subContainerOffsets, idx)
|
||||
}
|
||||
|
||||
//Parse data section.
|
||||
if topLevel && len(b) != idx+dataSize {
|
||||
return errTruncatedTopLevelContainer
|
||||
}
|
||||
c.dataOffest = idx
|
||||
|
||||
c.rawContainer = b
|
||||
|
||||
|
@ -398,7 +390,7 @@ func (c *Container) validateSubContainer(jt *JumpTable, refBy int) error {
|
|||
// should not mean 2 and 3 should be visited twice
|
||||
var (
|
||||
index = toVisit[0]
|
||||
code = c.codeSectionBytes(index)
|
||||
code = c.codeSectionAt(index)
|
||||
)
|
||||
if _, ok := visited[index]; !ok {
|
||||
res, err := validateCode(code, index, c, jt, refBy == refByEOFCreate)
|
||||
|
@ -430,7 +422,7 @@ func (c *Container) validateSubContainer(jt *JumpTable, refBy int) error {
|
|||
toVisit = toVisit[1:]
|
||||
}
|
||||
// Make sure every code section is visited at least once.
|
||||
if len(visited) != len(c.codeSectionOffsets) {
|
||||
if len(visited) != len(c.codeSectionOffsets)-1 {
|
||||
return errUnreachableCode
|
||||
}
|
||||
for idx, container := range c.subContainers {
|
||||
|
@ -507,6 +499,8 @@ func sum(list []int) (s int) {
|
|||
}
|
||||
|
||||
func (c *Container) String() string {
|
||||
// Drop the end markers
|
||||
codeSectionOffsets := c.codeSectionOffsets[:len(c.codeSectionOffsets)-1]
|
||||
var output = []string{
|
||||
"Header",
|
||||
fmt.Sprintf(" - EOFMagic: %02x", eofMagic),
|
||||
|
@ -514,14 +508,13 @@ func (c *Container) String() string {
|
|||
fmt.Sprintf(" - KindType: %02x", kindTypes),
|
||||
fmt.Sprintf(" - TypesSize: %04x", len(c.types)*4),
|
||||
fmt.Sprintf(" - KindCode: %02x", kindCode),
|
||||
fmt.Sprintf(" - Number of code sections: %d", len(codeSectionOffsets)),
|
||||
fmt.Sprintf(" - KindData: %02x", kindData),
|
||||
fmt.Sprintf(" - DataSize: %04x", c.dataLen()),
|
||||
fmt.Sprintf(" - Number of code sections: %d", len(c.codeSectionOffsets)),
|
||||
fmt.Sprintf(" - DataSize: %04x", c.dataSize),
|
||||
}
|
||||
for i := range c.codeSectionOffsets {
|
||||
output = append(output, fmt.Sprintf(" - Code section %d length: %04x", i, c.codeSectionSize(i)))
|
||||
for i := range codeSectionOffsets {
|
||||
output = append(output, fmt.Sprintf(" - Code section %d length: %04x", i, len(c.codeSectionAt(i))))
|
||||
}
|
||||
|
||||
output = append(output, fmt.Sprintf(" - Number of subcontainers: %d", len(c.subContainers)))
|
||||
if len(c.subContainers) > 0 {
|
||||
for i, section := range c.subContainers {
|
||||
|
@ -533,12 +526,12 @@ func (c *Container) String() string {
|
|||
output = append(output, fmt.Sprintf(" - Type %v: %x", i,
|
||||
[]byte{typ.inputs, typ.outputs, byte(typ.maxStackHeight >> 8), byte(typ.maxStackHeight & 0x00ff)}))
|
||||
}
|
||||
for i := range c.codeSectionOffsets {
|
||||
output = append(output, fmt.Sprintf(" - Code section %d: %#x", i, c.codeSectionBytes(i)))
|
||||
for i := range codeSectionOffsets {
|
||||
output = append(output, fmt.Sprintf(" - Code section %d: %#x", i, c.codeSectionAt(i)))
|
||||
}
|
||||
for i, section := range c.subContainers {
|
||||
output = append(output, fmt.Sprintf(" - Subcontainer %d: %x", i, section.MarshalBinary()))
|
||||
}
|
||||
output = append(output, fmt.Sprintf(" - Data: %#x", c.rawContainer[c.dataOffest:]))
|
||||
output = append(output, fmt.Sprintf(" - Data: %#x", c.rawContainer[c.dataOffset():]))
|
||||
return strings.Join(output, "\n")
|
||||
}
|
||||
|
|
|
@ -134,10 +134,11 @@ func opEOFCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
if int(idx) >= len(scope.Contract.Container.subContainerOffsets) {
|
||||
return nil, fmt.Errorf("invalid subcontainer")
|
||||
}
|
||||
subContainer := scope.Contract.Container.subContainerAt(int(idx))
|
||||
|
||||
// Deduct hashing charge
|
||||
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
||||
hashingCharge := (params.Keccak256WordGas) * ((uint64(scope.Contract.Container.subContainerSize(int(idx))) + 31) / 32)
|
||||
hashingCharge := (params.Keccak256WordGas) * ((uint64(len(subContainer)) + 31) / 32)
|
||||
if ok := scope.Contract.UseGas(hashingCharge, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified); !ok {
|
||||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
|
@ -154,7 +155,7 @@ func opEOFCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
|
||||
// Skip the immediate
|
||||
*pc += 1
|
||||
res, addr, returnGas, suberr := interpreter.evm.EOFCreate(scope.Contract, input, scope.Contract.Container.subContainerBytes(int(idx)), gas, &value, &salt)
|
||||
res, addr, returnGas, suberr := interpreter.evm.EOFCreate(scope.Contract, input, subContainer, gas, &value, &salt)
|
||||
if suberr != nil {
|
||||
stackvalue.Clear()
|
||||
} else {
|
||||
|
@ -185,7 +186,7 @@ func opReturnContract(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
|
|||
return nil, fmt.Errorf("invalid subcontainer")
|
||||
}
|
||||
ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
|
||||
containerCode := scope.Contract.Container.subContainerBytes(int(idx))
|
||||
containerCode := scope.Contract.Container.subContainerAt(int(idx))
|
||||
if len(containerCode) == 0 {
|
||||
return nil, errors.New("nonexistant subcontainer")
|
||||
}
|
||||
|
@ -225,7 +226,7 @@ func opDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
|||
stackItem.Clear()
|
||||
scope.Stack.push(&stackItem)
|
||||
} else {
|
||||
data := getData(scope.Contract.Container.rawContainer, uint64(scope.Contract.Container.dataOffest)+offset, 32)
|
||||
data := scope.Contract.Container.getDataAt(offset, 32)
|
||||
scope.Stack.push(stackItem.SetBytes(data))
|
||||
}
|
||||
return nil, nil
|
||||
|
@ -236,7 +237,7 @@ func opDataLoadN(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
var (
|
||||
offset = uint64(binary.BigEndian.Uint16(scope.Contract.Code[*pc+1:]))
|
||||
)
|
||||
data := getData(scope.Contract.Container.rawContainer, uint64(scope.Contract.Container.dataOffest)+offset, 32)
|
||||
data := scope.Contract.Container.getDataAt(offset, 32)
|
||||
scope.Stack.push(new(uint256.Int).SetBytes(data))
|
||||
*pc += 2 // move past 2 byte immediate
|
||||
return nil, nil
|
||||
|
@ -258,7 +259,7 @@ func opDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
|||
)
|
||||
// These values are checked for overflow during memory expansion calculation
|
||||
// (the memorySize function on the opcode).
|
||||
data := getData(scope.Contract.Container.rawContainer, uint64(scope.Contract.Container.dataOffest)+offset.Uint64(), size.Uint64())
|
||||
data := scope.Contract.Container.getDataAt(offset.Uint64(), size.Uint64())
|
||||
scope.Memory.Set(memOffset.Uint64(), size.Uint64(), data)
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -40,10 +40,9 @@ func MakeTestContainer(
|
|||
idx += len(code)
|
||||
testBytes = append(testBytes, code...)
|
||||
}
|
||||
codeSectionEnd := idx
|
||||
codeSectionOffsets = append(codeSectionOffsets, idx)
|
||||
|
||||
var subContainerOffsets []int
|
||||
subContainerEnd := 0
|
||||
if len(subContainers) > 0 {
|
||||
subContainerOffsets = make([]int, len(subContainers))
|
||||
for _, subContainer := range subContainers {
|
||||
|
@ -52,7 +51,8 @@ func MakeTestContainer(
|
|||
idx += len(containerBytes)
|
||||
testBytes = append(testBytes, containerBytes...)
|
||||
}
|
||||
subContainerEnd = idx
|
||||
// set the subContainer end marker
|
||||
subContainerOffsets = append(subContainerOffsets, idx)
|
||||
}
|
||||
|
||||
testBytes = append(testBytes, data...)
|
||||
|
@ -60,11 +60,8 @@ func MakeTestContainer(
|
|||
return Container{
|
||||
types: types,
|
||||
codeSectionOffsets: codeSectionOffsets,
|
||||
codeSectionEnd: codeSectionEnd,
|
||||
subContainers: subContainers,
|
||||
subContainerOffsets: subContainerOffsets,
|
||||
subContainerEnd: subContainerEnd,
|
||||
dataOffest: subContainerEnd,
|
||||
dataSize: dataSize,
|
||||
rawContainer: testBytes,
|
||||
}
|
||||
|
@ -78,9 +75,7 @@ func TestEOFMarshaling(t *testing.T) {
|
|||
{
|
||||
want: Container{
|
||||
types: []*functionMetadata{{inputs: 0, outputs: 0x80, maxStackHeight: 1}},
|
||||
codeSectionOffsets: []int{19}, // 604200
|
||||
codeSectionEnd: 22,
|
||||
dataOffest: 22,
|
||||
codeSectionOffsets: []int{19, 22}, // 604200, endMarker
|
||||
dataSize: 3,
|
||||
rawContainer: common.Hex2Bytes("ef000101000402000100030400030000800001604200010203"),
|
||||
},
|
||||
|
@ -92,9 +87,7 @@ func TestEOFMarshaling(t *testing.T) {
|
|||
{inputs: 2, outputs: 3, maxStackHeight: 4},
|
||||
{inputs: 1, outputs: 1, maxStackHeight: 1},
|
||||
},
|
||||
codeSectionOffsets: []int{31, 34, 39}, // 604200, 6042604200, 00
|
||||
codeSectionEnd: 40,
|
||||
dataOffest: 40,
|
||||
codeSectionOffsets: []int{31, 34, 39, 40}, // 604200, 6042604200, 00, endMarker
|
||||
rawContainer: common.Hex2Bytes("ef000101000c02000300030005000104000000008000010203000401010001604200604260420000"),
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue