Skip to content

Commit 55edee5

Browse files
committed
core/vm/program: minor UX tweaks
1 parent 6d7e9b9 commit 55edee5

File tree

3 files changed

+178
-105
lines changed

3 files changed

+178
-105
lines changed

core/vm/program/program.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,14 @@ func (p *Program) Push0() *Program {
127127
return p.Op(vm.PUSH0)
128128
}
129129

130-
// Bytecode returns the Program bytecode
131-
func (p *Program) Bytecode() []byte {
130+
// Bytes returns the Program bytecode
131+
func (p *Program) Bytes() []byte {
132132
return p.code
133133
}
134134

135135
// Hex returns the Program bytecode as a hex string
136136
func (p *Program) Hex() string {
137-
return fmt.Sprintf("%02x", p.Bytecode())
137+
return fmt.Sprintf("%02x", p.Bytes())
138138
}
139139

140140
// ExtcodeCopy performsa an extcodecopy invocation
@@ -280,6 +280,29 @@ func (p *Program) Mstore(data []byte, memStart uint32) *Program {
280280
return p
281281
}
282282

283+
// MstorePadded stores the provided data (into the memory area starting at memStart).
284+
// If data does not align on 32 bytes, it will be LHS-padded.
285+
// For example, providing data 0x1122, it will do a PUSH2:
286+
// PUSH2 0x1122, resulting in
287+
// stack: 0x0000000000000000000000000000000000000000000000000000000000001122
288+
// followed by MSTORE(0,0)
289+
// And thus, the resulting memory will be
290+
// [ 0000000000000000000000000000000000000000000000000000000000001122 ]
291+
func (p *Program) MstorePadded(data []byte, memStart uint32) *Program {
292+
var idx = 0
293+
// We need to store it in chunks of 32 bytes
294+
for ; idx < len(data); idx += 32 {
295+
end := min(len(data), idx+32)
296+
chunk := data[idx:end]
297+
// push the value
298+
p.Push(chunk)
299+
// push the memory index
300+
p.Push(uint32(idx) + memStart)
301+
p.Op(vm.MSTORE)
302+
}
303+
return p
304+
}
305+
283306
// MemToStorage copies the given memory area into SSTORE slots,
284307
// It expects data to be aligned to 32 byte, and does not zero out
285308
// remainders if some data is not

core/vm/program/program_test.go

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func TestCreateAndCall(t *testing.T) {
143143
deployed.Return(0, 32)
144144

145145
// Pack them
146-
ctor.ReturnData(deployed.Bytecode())
146+
ctor.ReturnData(deployed.Bytes())
147147
// Verify constructor + runtime code
148148
{
149149
want := "6005600055606060005360006001536054600253606060035360006004536052600553606060065360206007536060600853600060095360f3600a53600b6000f3"
@@ -155,21 +155,134 @@ func TestCreateAndCall(t *testing.T) {
155155

156156
func TestCreate2Call(t *testing.T) {
157157
// Some runtime code
158-
runtime := New().Ops(vm.ADDRESS, vm.SELFDESTRUCT).Bytecode()
158+
runtime := New().Ops(vm.ADDRESS, vm.SELFDESTRUCT).Bytes()
159159
want := common.FromHex("0x30ff")
160160
if !bytes.Equal(want, runtime) {
161161
t.Fatalf("runtime code error\nwant: %x\nhave: %x\n", want, runtime)
162162
}
163163
// A constructor returning the runtime code
164-
initcode := New().ReturnData(runtime).Bytecode()
164+
initcode := New().ReturnData(runtime).Bytes()
165165
want = common.FromHex("603060005360ff60015360026000f3")
166166
if !bytes.Equal(want, initcode) {
167167
t.Fatalf("initcode error\nwant: %x\nhave: %x\n", want, initcode)
168168
}
169169
// A factory invoking the constructor
170-
outer := New().Create2AndCall(initcode, nil).Bytecode()
170+
outer := New().Create2AndCall(initcode, nil).Bytes()
171171
want = common.FromHex("60606000536030600153606060025360006003536053600453606060055360ff6006536060600753600160085360536009536060600a536002600b536060600c536000600d5360f3600e536000600f60006000f560006000600060006000855af15050")
172172
if !bytes.Equal(want, outer) {
173173
t.Fatalf("factory error\nwant: %x\nhave: %x\n", want, outer)
174174
}
175175
}
176+
177+
func TestGenerator(t *testing.T) {
178+
for i, tc := range []struct {
179+
want []byte
180+
haveFn func() []byte
181+
}{
182+
{ // CREATE
183+
want: []byte{
184+
// Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes)
185+
byte(vm.PUSH5),
186+
// Init code: PUSH1 0, PUSH1 0, RETURN (3 steps)
187+
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN),
188+
byte(vm.PUSH1), 0,
189+
byte(vm.MSTORE),
190+
// length, offset, value
191+
byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0,
192+
byte(vm.CREATE),
193+
byte(vm.POP),
194+
},
195+
haveFn: func() []byte {
196+
initcode := New().Return(0, 0).Bytes()
197+
return New().MstorePadded(initcode, 0).
198+
Push(len(initcode)). // length
199+
Push(32 - len(initcode)). // offset
200+
Push(0). // value
201+
Op(vm.CREATE).
202+
Op(vm.POP).Bytes()
203+
},
204+
},
205+
{ // CREATE2
206+
want: []byte{
207+
// Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes)
208+
byte(vm.PUSH5),
209+
// Init code: PUSH1 0, PUSH1 0, RETURN (3 steps)
210+
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN),
211+
byte(vm.PUSH1), 0,
212+
byte(vm.MSTORE),
213+
// salt, length, offset, value
214+
byte(vm.PUSH1), 1, byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0,
215+
byte(vm.CREATE2),
216+
byte(vm.POP),
217+
},
218+
haveFn: func() []byte {
219+
initcode := New().Return(0, 0).Bytes()
220+
return New().MstorePadded(initcode, 0).
221+
Push(1). // salt
222+
Push(len(initcode)). // length
223+
Push(32 - len(initcode)). // offset
224+
Push(0). // value
225+
Op(vm.CREATE2).
226+
Op(vm.POP).Bytes()
227+
},
228+
},
229+
{ // CALL
230+
want: []byte{
231+
// outsize, outoffset, insize, inoffset
232+
byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
233+
byte(vm.DUP1), // value
234+
byte(vm.PUSH1), 0xbb, //address
235+
byte(vm.GAS), // gas
236+
byte(vm.CALL),
237+
byte(vm.POP),
238+
},
239+
haveFn: func() []byte {
240+
return New().Call(nil, 0xbb, 0, 0, 0, 0, 0).Op(vm.POP).Bytes()
241+
},
242+
},
243+
{ // CALLCODE
244+
want: []byte{
245+
// outsize, outoffset, insize, inoffset
246+
byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
247+
byte(vm.PUSH1), 0, // value
248+
byte(vm.PUSH1), 0xcc, //address
249+
byte(vm.GAS), // gas
250+
byte(vm.CALLCODE),
251+
byte(vm.POP),
252+
},
253+
haveFn: func() []byte {
254+
return New().CallCode(nil, 0xcc, 0, 0, 0, 0, 0).Op(vm.POP).Bytes()
255+
},
256+
},
257+
{ // STATICCALL
258+
want: []byte{
259+
// outsize, outoffset, insize, inoffset
260+
byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
261+
byte(vm.PUSH1), 0xdd, //address
262+
byte(vm.GAS), // gas
263+
byte(vm.STATICCALL),
264+
byte(vm.POP),
265+
},
266+
haveFn: func() []byte {
267+
return New().StaticCall(nil, 0xdd, 0, 0, 0, 0).Op(vm.POP).Bytes()
268+
},
269+
},
270+
{ // DELEGATECALL
271+
want: []byte{
272+
// outsize, outoffset, insize, inoffset
273+
byte(vm.PUSH1), 0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
274+
byte(vm.PUSH1), 0xee, //address
275+
byte(vm.GAS), // gas
276+
byte(vm.DELEGATECALL),
277+
byte(vm.POP),
278+
},
279+
haveFn: func() []byte {
280+
return New().DelegateCall(nil, 0xee, 0, 0, 0, 0).Op(vm.POP).Bytes()
281+
},
282+
},
283+
} {
284+
if have := tc.haveFn(); !bytes.Equal(have, tc.want) {
285+
t.Fatalf("test %d error\nhave: %x\nwant: %x\n", i, have, tc.want)
286+
}
287+
}
288+
}

core/vm/runtime/runtime_test.go

Lines changed: 35 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -442,42 +442,42 @@ func BenchmarkSimpleLoop(b *testing.B) {
442442
// Call identity, and pop return value
443443
staticCallIdentity := p.
444444
StaticCall(nil, 0x4, 0, 0, 0, 0).
445-
Op(vm.POP).Jump(lbl).Bytecode() // pop return value and jump to label
445+
Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label
446446

447447
p, lbl = program.New().Jumpdest()
448448
callIdentity := p.
449449
Call(nil, 0x4, 0, 0, 0, 0, 0).
450-
Op(vm.POP).Jump(lbl).Bytecode() // pop return value and jump to label
450+
Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label
451451

452452
p, lbl = program.New().Jumpdest()
453453
callInexistant := p.
454454
Call(nil, 0xff, 0, 0, 0, 0, 0).
455-
Op(vm.POP).Jump(lbl).Bytecode() // pop return value and jump to label
455+
Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label
456456

457457
p, lbl = program.New().Jumpdest()
458458
callEOA := p.
459459
Call(nil, 0xE0, 0, 0, 0, 0, 0). // call addr of EOA
460-
Op(vm.POP).Jump(lbl).Bytecode() // pop return value and jump to label
460+
Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label
461461

462462
p, lbl = program.New().Jumpdest()
463463
// Push as if we were making call, then pop it off again, and loop
464464
loopingCode := p.Push(0).
465465
Ops(vm.DUP1, vm.DUP1, vm.DUP1).
466466
Push(0x4).
467467
Ops(vm.GAS, vm.POP, vm.POP, vm.POP, vm.POP, vm.POP, vm.POP).
468-
Jump(lbl).Bytecode()
468+
Jump(lbl).Bytes()
469469

470470
p, lbl = program.New().Jumpdest()
471471
loopingCode2 := p.
472472
Push(0x01020304).Push(uint64(0x0102030405)).
473473
Ops(vm.POP, vm.POP).
474474
Op(vm.PUSH6).Append(make([]byte, 6)).Op(vm.JUMP). // Jumpdest zero expressed in 6 bytes
475-
Bytecode()
475+
Bytes()
476476

477477
p, lbl = program.New().Jumpdest()
478478
callRevertingContractWithInput := p.
479479
Call(nil, 0xee, 0, 0, 0x20, 0x0, 0x0).
480-
Op(vm.POP).Jump(lbl).Bytecode() // pop return value and jump to label
480+
Op(vm.POP).Jump(lbl).Bytes() // pop return value and jump to label
481481

482482
//tracer := logger.NewJSONLogger(nil, os.Stdout)
483483
//Execute(loopingCode, nil, &Config{
@@ -716,104 +716,49 @@ func TestRuntimeJSTracer(t *testing.T) {
716716
this.exits++;
717717
this.gasUsed = res.getGasUsed();
718718
}}`}
719+
initcode := program.New().Return(0, 0).Bytes()
719720
tests := []struct {
720721
code []byte
721722
// One result per tracer
722723
results []string
723724
}{
724-
{
725-
// CREATE
726-
code: []byte{
727-
// Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes)
728-
byte(vm.PUSH5),
729-
// Init code: PUSH1 0, PUSH1 0, RETURN (3 steps)
730-
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN),
731-
byte(vm.PUSH1), 0,
732-
byte(vm.MSTORE),
733-
// length, offset, value
734-
byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0,
735-
byte(vm.CREATE),
736-
byte(vm.POP),
737-
},
725+
{ // CREATE
726+
code: program.New().MstorePadded(initcode, 0).
727+
Push(len(initcode)). // length
728+
Push(32 - len(initcode)). // offset
729+
Push(0). // value
730+
Op(vm.CREATE).
731+
Op(vm.POP).Bytes(),
738732
results: []string{`"1,1,952853,6,12"`, `"1,1,952853,6,0"`},
739733
},
740-
{
741-
// CREATE2
742-
code: []byte{
743-
// Store initcode in memory at 0x00 (5 bytes left-padded to 32 bytes)
744-
byte(vm.PUSH5),
745-
// Init code: PUSH1 0, PUSH1 0, RETURN (3 steps)
746-
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN),
747-
byte(vm.PUSH1), 0,
748-
byte(vm.MSTORE),
749-
// salt, length, offset, value
750-
byte(vm.PUSH1), 1, byte(vm.PUSH1), 5, byte(vm.PUSH1), 27, byte(vm.PUSH1), 0,
751-
byte(vm.CREATE2),
752-
byte(vm.POP),
753-
},
734+
{ // CREATE2
735+
code: program.New().MstorePadded(initcode, 0).
736+
Push(1). // salt
737+
Push(len(initcode)). // length
738+
Push(32 - len(initcode)). // offset
739+
Push(0). // value
740+
Op(vm.CREATE2).
741+
Op(vm.POP).Bytes(),
754742
results: []string{`"1,1,952844,6,13"`, `"1,1,952844,6,0"`},
755743
},
756-
{
757-
// CALL
758-
code: []byte{
759-
// outsize, outoffset, insize, inoffset
760-
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0,
761-
byte(vm.PUSH1), 0, // value
762-
byte(vm.PUSH1), 0xbb, //address
763-
byte(vm.GAS), // gas
764-
byte(vm.CALL),
765-
byte(vm.POP),
766-
},
744+
{ // CALL
745+
code: program.New().Call(nil, 0xbb, 0, 0, 0, 0, 0).Op(vm.POP).Bytes(),
767746
results: []string{`"1,1,981796,6,13"`, `"1,1,981796,6,0"`},
768747
},
769-
{
770-
// CALLCODE
771-
code: []byte{
772-
// outsize, outoffset, insize, inoffset
773-
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0,
774-
byte(vm.PUSH1), 0, // value
775-
byte(vm.PUSH1), 0xcc, //address
776-
byte(vm.GAS), // gas
777-
byte(vm.CALLCODE),
778-
byte(vm.POP),
779-
},
748+
{ // CALLCODE
749+
code: program.New().CallCode(nil, 0xcc, 0, 0, 0, 0, 0).Op(vm.POP).Bytes(),
780750
results: []string{`"1,1,981796,6,13"`, `"1,1,981796,6,0"`},
781751
},
782-
{
783-
// STATICCALL
784-
code: []byte{
785-
// outsize, outoffset, insize, inoffset
786-
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0,
787-
byte(vm.PUSH1), 0xdd, //address
788-
byte(vm.GAS), // gas
789-
byte(vm.STATICCALL),
790-
byte(vm.POP),
791-
},
752+
{ // STATICCALL
753+
code: program.New().StaticCall(nil, 0xdd, 0, 0, 0, 0).Op(vm.POP).Bytes(),
792754
results: []string{`"1,1,981799,6,12"`, `"1,1,981799,6,0"`},
793755
},
794-
{
795-
// DELEGATECALL
796-
code: []byte{
797-
// outsize, outoffset, insize, inoffset
798-
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0,
799-
byte(vm.PUSH1), 0xee, //address
800-
byte(vm.GAS), // gas
801-
byte(vm.DELEGATECALL),
802-
byte(vm.POP),
803-
},
756+
{ // DELEGATECALL
757+
code: program.New().DelegateCall(nil, 0xee, 0, 0, 0, 0).Op(vm.POP).Bytes(),
804758
results: []string{`"1,1,981799,6,12"`, `"1,1,981799,6,0"`},
805759
},
806-
{
807-
// CALL self-destructing contract
808-
code: []byte{
809-
// outsize, outoffset, insize, inoffset
810-
byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.PUSH1), 0,
811-
byte(vm.PUSH1), 0, // value
812-
byte(vm.PUSH1), 0xff, //address
813-
byte(vm.GAS), // gas
814-
byte(vm.CALL),
815-
byte(vm.POP),
816-
},
760+
{ // CALL self-destructing contract
761+
code: program.New().Call(nil, 0xff, 0, 0, 0, 0, 0).Op(vm.POP).Bytes(),
817762
results: []string{`"2,2,0,5003,12"`, `"2,2,0,5003,0"`},
818763
},
819764
}
@@ -896,16 +841,8 @@ func TestJSTracerCreateTx(t *testing.T) {
896841

897842
func BenchmarkTracerStepVsCallFrame(b *testing.B) {
898843
// Simply pushes and pops some values in a loop
899-
code := []byte{
900-
byte(vm.JUMPDEST),
901-
byte(vm.PUSH1), 0,
902-
byte(vm.PUSH1), 0,
903-
byte(vm.POP),
904-
byte(vm.POP),
905-
byte(vm.PUSH1), 0, // jumpdestination
906-
byte(vm.JUMP),
907-
}
908-
844+
p, lbl := program.New().Jumpdest()
845+
code := p.Push(0).Push(0).Ops(vm.POP, vm.POP).Jump(lbl).Bytes()
909846
stepTracer := `
910847
{
911848
step: function() {},

0 commit comments

Comments
 (0)