mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
Merge branch 'master' into 22_mail
This commit is contained in:
commit
1217e6106b
482 changed files with 26329 additions and 8362 deletions
|
|
@ -90,7 +90,7 @@ install:
|
||||||
- go get golang.org/x/tools/cmd/cover
|
- go get golang.org/x/tools/cmd/cover
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go test -coverage -vet
|
- go run build/ci.go test -coverage -vet -misspell
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
webhooks:
|
webhooks:
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.5.6
|
1.5.8
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,30 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// first we need to create a slice of the type
|
// first we need to create a slice of the type
|
||||||
var refSlice reflect.Value
|
var refSlice reflect.Value
|
||||||
switch elem.T {
|
switch elem.T {
|
||||||
case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int.
|
case IntTy, UintTy, BoolTy:
|
||||||
refSlice = reflect.ValueOf([]*big.Int(nil))
|
// create a new reference slice matching the element type
|
||||||
|
switch t.Type.Kind {
|
||||||
|
case reflect.Bool:
|
||||||
|
refSlice = reflect.ValueOf([]bool(nil))
|
||||||
|
case reflect.Uint8:
|
||||||
|
refSlice = reflect.ValueOf([]uint8(nil))
|
||||||
|
case reflect.Uint16:
|
||||||
|
refSlice = reflect.ValueOf([]uint16(nil))
|
||||||
|
case reflect.Uint32:
|
||||||
|
refSlice = reflect.ValueOf([]uint32(nil))
|
||||||
|
case reflect.Uint64:
|
||||||
|
refSlice = reflect.ValueOf([]uint64(nil))
|
||||||
|
case reflect.Int8:
|
||||||
|
refSlice = reflect.ValueOf([]int8(nil))
|
||||||
|
case reflect.Int16:
|
||||||
|
refSlice = reflect.ValueOf([]int16(nil))
|
||||||
|
case reflect.Int32:
|
||||||
|
refSlice = reflect.ValueOf([]int32(nil))
|
||||||
|
case reflect.Int64:
|
||||||
|
refSlice = reflect.ValueOf([]int64(nil))
|
||||||
|
default:
|
||||||
|
refSlice = reflect.ValueOf([]*big.Int(nil))
|
||||||
|
}
|
||||||
case AddressTy: // address must be of slice Address
|
case AddressTy: // address must be of slice Address
|
||||||
refSlice = reflect.ValueOf([]common.Address(nil))
|
refSlice = reflect.ValueOf([]common.Address(nil))
|
||||||
case HashTy: // hash must be of slice hash
|
case HashTy: // hash must be of slice hash
|
||||||
|
|
@ -147,7 +169,27 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// set inter to the correct type (cast)
|
// set inter to the correct type (cast)
|
||||||
switch elem.T {
|
switch elem.T {
|
||||||
case IntTy, UintTy:
|
case IntTy, UintTy:
|
||||||
inter = common.BytesToBig(returnOutput)
|
bigNum := common.BytesToBig(returnOutput)
|
||||||
|
switch t.Type.Kind {
|
||||||
|
case reflect.Uint8:
|
||||||
|
inter = uint8(bigNum.Uint64())
|
||||||
|
case reflect.Uint16:
|
||||||
|
inter = uint16(bigNum.Uint64())
|
||||||
|
case reflect.Uint32:
|
||||||
|
inter = uint32(bigNum.Uint64())
|
||||||
|
case reflect.Uint64:
|
||||||
|
inter = bigNum.Uint64()
|
||||||
|
case reflect.Int8:
|
||||||
|
inter = int8(bigNum.Int64())
|
||||||
|
case reflect.Int16:
|
||||||
|
inter = int16(bigNum.Int64())
|
||||||
|
case reflect.Int32:
|
||||||
|
inter = int32(bigNum.Int64())
|
||||||
|
case reflect.Int64:
|
||||||
|
inter = bigNum.Int64()
|
||||||
|
default:
|
||||||
|
inter = common.BytesToBig(returnOutput)
|
||||||
|
}
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
inter = common.BytesToBig(returnOutput).Uint64() > 0
|
inter = common.BytesToBig(returnOutput).Uint64() > 0
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
|
|
@ -169,7 +211,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// argument in T.
|
// argument in T.
|
||||||
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
// we need to treat slices differently
|
// we need to treat slices differently
|
||||||
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy {
|
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy {
|
||||||
return toGoSlice(i, t, output)
|
return toGoSlice(i, t, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +275,7 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||||
return common.BytesToAddress(returnOutput), nil
|
return common.BytesToAddress(returnOutput), nil
|
||||||
case HashTy:
|
case HashTy:
|
||||||
return common.BytesToHash(returnOutput), nil
|
return common.BytesToHash(returnOutput), nil
|
||||||
case BytesTy, FixedBytesTy:
|
case BytesTy, FixedBytesTy, FunctionTy:
|
||||||
return returnOutput, nil
|
return returnOutput, nil
|
||||||
case StringTy:
|
case StringTy:
|
||||||
return string(returnOutput), nil
|
return string(returnOutput), nil
|
||||||
|
|
|
||||||
|
|
@ -67,10 +67,10 @@ func TestTypeCheck(t *testing.T) {
|
||||||
{"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
|
{"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
|
||||||
{"uint16[3]", []uint16{1, 2, 3}, ""},
|
{"uint16[3]", []uint16{1, 2, 3}, ""},
|
||||||
{"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
|
{"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
|
||||||
{"address[]", []common.Address{common.Address{1}}, ""},
|
{"address[]", []common.Address{{1}}, ""},
|
||||||
{"address[1]", []common.Address{common.Address{1}}, ""},
|
{"address[1]", []common.Address{{1}}, ""},
|
||||||
{"address[1]", [1]common.Address{common.Address{1}}, ""},
|
{"address[1]", [1]common.Address{{1}}, ""},
|
||||||
{"address[2]", [1]common.Address{common.Address{1}}, "abi: cannot use [1]array as type [2]array as argument"},
|
{"address[2]", [1]common.Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"},
|
||||||
{"bytes32", [32]byte{}, ""},
|
{"bytes32", [32]byte{}, ""},
|
||||||
{"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"},
|
{"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"},
|
||||||
{"bytes32", common.Hash{1}, ""},
|
{"bytes32", common.Hash{1}, ""},
|
||||||
|
|
@ -80,7 +80,8 @@ func TestTypeCheck(t *testing.T) {
|
||||||
{"bytes", [2]byte{0, 1}, ""},
|
{"bytes", [2]byte{0, 1}, ""},
|
||||||
{"bytes", common.Hash{1}, ""},
|
{"bytes", common.Hash{1}, ""},
|
||||||
{"string", "hello world", ""},
|
{"string", "hello world", ""},
|
||||||
{"bytes32[]", [][32]byte{[32]byte{}}, ""},
|
{"bytes32[]", [][32]byte{{}}, ""},
|
||||||
|
{"function", [24]byte{}, ""},
|
||||||
} {
|
} {
|
||||||
typ, err := NewType(test.typ)
|
typ, err := NewType(test.typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -197,6 +198,13 @@ func TestSimpleMethodUnpack(t *testing.T) {
|
||||||
"interface",
|
"interface",
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
`[ { "type": "function" } ]`,
|
||||||
|
pad([]byte{1}, 32, false),
|
||||||
|
[24]byte{1},
|
||||||
|
"function",
|
||||||
|
"",
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
|
abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
|
||||||
abi, err := JSON(strings.NewReader(abiDefinition))
|
abi, err := JSON(strings.NewReader(abiDefinition))
|
||||||
|
|
@ -255,6 +263,10 @@ func TestSimpleMethodUnpack(t *testing.T) {
|
||||||
var v common.Hash
|
var v common.Hash
|
||||||
err = abi.Unpack(&v, "method", test.marshalledOutput)
|
err = abi.Unpack(&v, "method", test.marshalledOutput)
|
||||||
outvar = v
|
outvar = v
|
||||||
|
case "function":
|
||||||
|
var v [24]byte
|
||||||
|
err = abi.Unpack(&v, "method", test.marshalledOutput)
|
||||||
|
outvar = v
|
||||||
case "interface":
|
case "interface":
|
||||||
err = abi.Unpack(&outvar, "method", test.marshalledOutput)
|
err = abi.Unpack(&outvar, "method", test.marshalledOutput)
|
||||||
default:
|
default:
|
||||||
|
|
@ -320,6 +332,30 @@ func TestUnpackSetInterfaceSlice(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnpackSetInterfaceArrayOutput(t *testing.T) {
|
||||||
|
var (
|
||||||
|
var1 = new([1]uint32)
|
||||||
|
var2 = new([1]uint32)
|
||||||
|
)
|
||||||
|
out := []interface{}{var1, var2}
|
||||||
|
abi, err := JSON(strings.NewReader(`[{"type":"function", "name":"ints", "outputs":[{"type":"uint32[1]"}, {"type":"uint32[1]"}]}]`))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
marshalledReturn := append(pad([]byte{1}, 32, true), pad([]byte{2}, 32, true)...)
|
||||||
|
err = abi.Unpack(&out, "ints", marshalledReturn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *var1 != [1]uint32{1} {
|
||||||
|
t.Error("expected var1 to be [1], got", *var1)
|
||||||
|
}
|
||||||
|
if *var2 != [1]uint32{2} {
|
||||||
|
t.Error("expected var2 to be [2], got", *var2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPack(t *testing.T) {
|
func TestPack(t *testing.T) {
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
typ string
|
typ string
|
||||||
|
|
@ -331,8 +367,9 @@ func TestPack(t *testing.T) {
|
||||||
{"uint16[]", []uint16{1, 2}, formatSliceOutput([]byte{1}, []byte{2})},
|
{"uint16[]", []uint16{1, 2}, formatSliceOutput([]byte{1}, []byte{2})},
|
||||||
{"bytes20", [20]byte{1}, pad([]byte{1}, 32, false)},
|
{"bytes20", [20]byte{1}, pad([]byte{1}, 32, false)},
|
||||||
{"uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, formatSliceOutput([]byte{1}, []byte{2})},
|
{"uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, formatSliceOutput([]byte{1}, []byte{2})},
|
||||||
{"address[]", []common.Address{common.Address{1}, common.Address{2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, false))},
|
{"address[]", []common.Address{{1}, {2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, false))},
|
||||||
{"bytes32[]", []common.Hash{common.Hash{1}, common.Hash{2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))},
|
{"bytes32[]", []common.Hash{{1}, {2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))},
|
||||||
|
{"function", [24]byte{1}, pad([]byte{1}, 32, false)},
|
||||||
} {
|
} {
|
||||||
typ, err := NewType(test.typ)
|
typ, err := NewType(test.typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -445,12 +482,12 @@ func TestReader(t *testing.T) {
|
||||||
Uint256, _ := NewType("uint256")
|
Uint256, _ := NewType("uint256")
|
||||||
exp := ABI{
|
exp := ABI{
|
||||||
Methods: map[string]Method{
|
Methods: map[string]Method{
|
||||||
"balance": Method{
|
"balance": {
|
||||||
"balance", true, nil, nil,
|
"balance", true, nil, nil,
|
||||||
},
|
},
|
||||||
"send": Method{
|
"send": {
|
||||||
"send", false, []Argument{
|
"send", false, []Argument{
|
||||||
Argument{"amount", Uint256, false},
|
{"amount", Uint256, false},
|
||||||
}, nil,
|
}, nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -549,7 +586,7 @@ func TestTestSlice(t *testing.T) {
|
||||||
|
|
||||||
func TestMethodSignature(t *testing.T) {
|
func TestMethodSignature(t *testing.T) {
|
||||||
String, _ := NewType("string")
|
String, _ := NewType("string")
|
||||||
m := Method{"foo", false, []Argument{Argument{"bar", String, false}, Argument{"baz", String, false}}, nil}
|
m := Method{"foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil}
|
||||||
exp := "foo(string,string)"
|
exp := "foo(string,string)"
|
||||||
if m.Sig() != exp {
|
if m.Sig() != exp {
|
||||||
t.Error("signature mismatch", exp, "!=", m.Sig())
|
t.Error("signature mismatch", exp, "!=", m.Sig())
|
||||||
|
|
@ -561,7 +598,7 @@ func TestMethodSignature(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uintt, _ := NewType("uint")
|
uintt, _ := NewType("uint")
|
||||||
m = Method{"foo", false, []Argument{Argument{"bar", uintt, false}}, nil}
|
m = Method{"foo", false, []Argument{{"bar", uintt, false}}, nil}
|
||||||
exp = "foo(uint256)"
|
exp = "foo(uint256)"
|
||||||
if m.Sig() != exp {
|
if m.Sig() != exp {
|
||||||
t.Error("signature mismatch", exp, "!=", m.Sig())
|
t.Error("signature mismatch", exp, "!=", m.Sig())
|
||||||
|
|
@ -766,8 +803,8 @@ func TestBareEvents(t *testing.T) {
|
||||||
"balance": {false, nil},
|
"balance": {false, nil},
|
||||||
"anon": {true, nil},
|
"anon": {true, nil},
|
||||||
"args": {false, []Argument{
|
"args": {false, []Argument{
|
||||||
Argument{Name: "arg0", Type: arg0, Indexed: false},
|
{Name: "arg0", Type: arg0, Indexed: false},
|
||||||
Argument{Name: "arg1", Type: arg1, Indexed: true},
|
{Name: "arg1", Type: arg1, Indexed: true},
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ type Argument struct {
|
||||||
|
|
||||||
func (a *Argument) UnmarshalJSON(data []byte) error {
|
func (a *Argument) UnmarshalJSON(data []byte) error {
|
||||||
var extarg struct {
|
var extarg struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
Indexed bool
|
Indexed bool
|
||||||
}
|
}
|
||||||
err := json.Unmarshal(data, &extarg)
|
err := json.Unmarshal(data, &extarg)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
|
||||||
if address != keyAddr {
|
if address != keyAddr {
|
||||||
return nil, errors.New("not authorized to sign this account")
|
return nil, errors.New("not authorized to sign this account")
|
||||||
}
|
}
|
||||||
signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key)
|
signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
|
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEnvironment(evmContext, statedb, chainConfig, vm.Config{})
|
vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{})
|
||||||
gaspool := new(core.GasPool).AddGas(common.MaxBig)
|
gaspool := new(core.GasPool).AddGas(common.MaxBig)
|
||||||
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, err
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
if value == nil {
|
if value == nil {
|
||||||
value = new(big.Int)
|
value = new(big.Int)
|
||||||
}
|
}
|
||||||
nonce := uint64(0)
|
var nonce uint64
|
||||||
if opts.Nonce == nil {
|
if opts.Nonce == nil {
|
||||||
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
|
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -147,21 +147,21 @@ func bindTypeGo(kind abi.Type) string {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(stringKind, "address"):
|
case strings.HasPrefix(stringKind, "address"):
|
||||||
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%scommon.Address", parts[1])
|
return fmt.Sprintf("%scommon.Address", parts[1])
|
||||||
|
|
||||||
case strings.HasPrefix(stringKind, "bytes"):
|
case strings.HasPrefix(stringKind, "bytes"):
|
||||||
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 3 {
|
if len(parts) != 3 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s[%s]byte", parts[2], parts[1])
|
return fmt.Sprintf("%s[%s]byte", parts[2], parts[1])
|
||||||
|
|
||||||
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||||
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 4 {
|
if len(parts) != 4 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +172,7 @@ func bindTypeGo(kind abi.Type) string {
|
||||||
return fmt.Sprintf("%s*big.Int", parts[3])
|
return fmt.Sprintf("%s*big.Int", parts[3])
|
||||||
|
|
||||||
case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"):
|
case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"):
|
||||||
parts := regexp.MustCompile("([a-z]+)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`([a-z]+)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 3 {
|
if len(parts) != 3 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +191,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(stringKind, "address"):
|
case strings.HasPrefix(stringKind, "address"):
|
||||||
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -201,7 +201,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||||
return fmt.Sprintf("Addresses")
|
return fmt.Sprintf("Addresses")
|
||||||
|
|
||||||
case strings.HasPrefix(stringKind, "bytes"):
|
case strings.HasPrefix(stringKind, "bytes"):
|
||||||
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 3 {
|
if len(parts) != 3 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +211,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||||
return "byte[]"
|
return "byte[]"
|
||||||
|
|
||||||
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||||
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 4 {
|
if len(parts) != 4 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -230,7 +230,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||||
return fmt.Sprintf("BigInts")
|
return fmt.Sprintf("BigInts")
|
||||||
|
|
||||||
case strings.HasPrefix(stringKind, "bool"):
|
case strings.HasPrefix(stringKind, "bool"):
|
||||||
parts := regexp.MustCompile("bool(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`bool(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +240,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||||
return fmt.Sprintf("bool[]")
|
return fmt.Sprintf("bool[]")
|
||||||
|
|
||||||
case strings.HasPrefix(stringKind, "string"):
|
case strings.HasPrefix(stringKind, "string"):
|
||||||
parts := regexp.MustCompile("string(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
parts := regexp.MustCompile(`string(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return stringKind
|
return stringKind
|
||||||
}
|
}
|
||||||
|
|
@ -278,7 +278,7 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
|
||||||
case "bool[]":
|
case "bool[]":
|
||||||
return "Bools"
|
return "Bools"
|
||||||
case "BigInt":
|
case "BigInt":
|
||||||
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(solKind.String())
|
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String())
|
||||||
if len(parts) != 4 {
|
if len(parts) != 4 {
|
||||||
return javaKind
|
return javaKind
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) {
|
||||||
|
|
||||||
// Create the transaction.
|
// Create the transaction.
|
||||||
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
|
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
|
||||||
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
||||||
|
|
||||||
// Wait for it to get mined in the background.
|
// Wait for it to get mined in the background.
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
|
||||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||||
}
|
}
|
||||||
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
|
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
|
||||||
case FixedBytesTy:
|
case FixedBytesTy, FunctionTy:
|
||||||
if reflectValue.Kind() == reflect.Array {
|
if reflectValue.Kind() == reflect.Array {
|
||||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ const (
|
||||||
BytesTy
|
BytesTy
|
||||||
HashTy
|
HashTy
|
||||||
FixedpointTy
|
FixedpointTy
|
||||||
|
FunctionTy
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type is the reflection of the supported argument type
|
// Type is the reflection of the supported argument type
|
||||||
|
|
@ -64,7 +65,7 @@ var (
|
||||||
// string int uint fixed
|
// string int uint fixed
|
||||||
// string32 int8 uint8 uint[]
|
// string32 int8 uint8 uint[]
|
||||||
// address int256 uint256 fixed128x128[2]
|
// address int256 uint256 fixed128x128[2]
|
||||||
fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)\\])?")
|
fullTypeRegex = regexp.MustCompile(`([a-zA-Z0-9]+)(\[([0-9]*)\])?`)
|
||||||
// typeRegex parses the abi sub types
|
// typeRegex parses the abi sub types
|
||||||
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
|
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
|
||||||
)
|
)
|
||||||
|
|
@ -90,7 +91,12 @@ func NewType(t string) (typ Type, err error) {
|
||||||
}
|
}
|
||||||
typ.Elem = &sliceType
|
typ.Elem = &sliceType
|
||||||
typ.stringKind = sliceType.stringKind + t[len(res[1]):]
|
typ.stringKind = sliceType.stringKind + t[len(res[1]):]
|
||||||
return typ, nil
|
// Although we know that this is an array, we cannot return
|
||||||
|
// as we don't know the type of the element, however, if it
|
||||||
|
// is still an array, then don't determine the type.
|
||||||
|
if typ.Elem.IsArray || typ.Elem.IsSlice {
|
||||||
|
return typ, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the type and size of the abi-type.
|
// parse the type and size of the abi-type.
|
||||||
|
|
@ -111,7 +117,12 @@ func NewType(t string) (typ Type, err error) {
|
||||||
varSize = 256
|
varSize = 256
|
||||||
t += "256"
|
t += "256"
|
||||||
}
|
}
|
||||||
typ.stringKind = t
|
|
||||||
|
// only set stringKind if not array or slice, as for those,
|
||||||
|
// the correct string type has been set
|
||||||
|
if !(typ.IsArray || typ.IsSlice) {
|
||||||
|
typ.stringKind = t
|
||||||
|
}
|
||||||
|
|
||||||
switch varType {
|
switch varType {
|
||||||
case "int":
|
case "int":
|
||||||
|
|
@ -148,6 +159,12 @@ func NewType(t string) (typ Type, err error) {
|
||||||
typ.T = FixedBytesTy
|
typ.T = FixedBytesTy
|
||||||
typ.SliceSize = varSize
|
typ.SliceSize = varSize
|
||||||
}
|
}
|
||||||
|
case "function":
|
||||||
|
sliceType, _ := NewType("uint8")
|
||||||
|
typ.Elem = &sliceType
|
||||||
|
typ.IsArray = true
|
||||||
|
typ.T = FunctionTy
|
||||||
|
typ.SliceSize = 24
|
||||||
default:
|
default:
|
||||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +185,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy {
|
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy {
|
||||||
var packed []byte
|
var packed []byte
|
||||||
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
|
|
||||||
|
|
@ -34,17 +34,17 @@ func TestTypeRegexp(t *testing.T) {
|
||||||
{"int", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}},
|
{"int", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}},
|
||||||
{"int8", Type{Kind: reflect.Int8, Type: big_t, Size: 8, T: IntTy, stringKind: "int8"}},
|
{"int8", Type{Kind: reflect.Int8, Type: big_t, Size: 8, T: IntTy, stringKind: "int8"}},
|
||||||
{"int256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}},
|
{"int256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}},
|
||||||
{"int[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[]"}},
|
{"int[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[]"}},
|
||||||
{"int[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}},
|
{"int[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, Elem: &Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, stringKind: "int256"}, stringKind: "int256[2]"}},
|
||||||
{"int32[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[]"}},
|
{"int32[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[]"}},
|
||||||
{"int32[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[2]"}},
|
{"int32[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, Elem: &Type{Kind: reflect.Int32, Type: big_t, Size: 32, T: IntTy, stringKind: "int32"}, stringKind: "int32[2]"}},
|
||||||
{"uint", Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}},
|
{"uint", Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}},
|
||||||
{"uint8", Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}},
|
{"uint8", Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}},
|
||||||
{"uint256", Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}},
|
{"uint256", Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}},
|
||||||
{"uint[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[]"}},
|
{"uint[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[]"}},
|
||||||
{"uint[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[2]"}},
|
{"uint[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, Elem: &Type{Kind: reflect.Ptr, Type: ubig_t, Size: 256, T: UintTy, stringKind: "uint256"}, stringKind: "uint256[2]"}},
|
||||||
{"uint32[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[]"}},
|
{"uint32[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.Uint32, Type: ubig_t, Size: 32, T: UintTy, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[]"}},
|
||||||
{"uint32[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[2]"}},
|
{"uint32[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.Uint32, Type: ubig_t, Size: 32, T: UintTy, Elem: &Type{Kind: reflect.Uint32, Type: big_t, Size: 32, T: UintTy, stringKind: "uint32"}, stringKind: "uint32[2]"}},
|
||||||
{"bytes", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: BytesTy, stringKind: "bytes"}},
|
{"bytes", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: BytesTy, stringKind: "bytes"}},
|
||||||
{"bytes32", Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}},
|
{"bytes32", Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}},
|
||||||
{"bytes[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: BytesTy, stringKind: "bytes"}, stringKind: "bytes[]"}},
|
{"bytes[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: BytesTy, stringKind: "bytes"}, stringKind: "bytes[]"}},
|
||||||
|
|
@ -52,11 +52,11 @@ func TestTypeRegexp(t *testing.T) {
|
||||||
{"bytes32[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}, stringKind: "bytes32[]"}},
|
{"bytes32[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}, stringKind: "bytes32[]"}},
|
||||||
{"bytes32[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}, stringKind: "bytes32[2]"}},
|
{"bytes32[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{IsArray: true, SliceSize: 32, Elem: &Type{Kind: reflect.Uint8, Type: ubig_t, Size: 8, T: UintTy, stringKind: "uint8"}, T: FixedBytesTy, stringKind: "bytes32"}, stringKind: "bytes32[2]"}},
|
||||||
{"string", Type{Kind: reflect.String, Size: -1, T: StringTy, stringKind: "string"}},
|
{"string", Type{Kind: reflect.String, Size: -1, T: StringTy, stringKind: "string"}},
|
||||||
{"string[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.String, Size: -1, T: StringTy, stringKind: "string"}, stringKind: "string[]"}},
|
{"string[]", Type{IsSlice: true, SliceSize: -1, Kind: reflect.String, T: StringTy, Size: -1, Elem: &Type{Kind: reflect.String, T: StringTy, Size: -1, stringKind: "string"}, stringKind: "string[]"}},
|
||||||
{"string[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.String, Size: -1, T: StringTy, stringKind: "string"}, stringKind: "string[2]"}},
|
{"string[2]", Type{IsArray: true, SliceSize: 2, Kind: reflect.String, T: StringTy, Size: -1, Elem: &Type{Kind: reflect.String, T: StringTy, Size: -1, stringKind: "string"}, stringKind: "string[2]"}},
|
||||||
{"address", Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}},
|
{"address", Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}},
|
||||||
{"address[]", Type{IsSlice: true, SliceSize: -1, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}},
|
{"address[]", Type{IsSlice: true, SliceSize: -1,Kind: reflect.Array, Type:address_t, T: AddressTy, Size:20, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}},
|
||||||
{"address[2]", Type{IsArray: true, SliceSize: 2, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}},
|
{"address[2]", Type{IsArray: true, SliceSize: 2,Kind: reflect.Array, Type:address_t, T: AddressTy, Size:20, Elem: &Type{Kind: reflect.Array, Type: address_t, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}},
|
||||||
|
|
||||||
// TODO when fixed types are implemented properly
|
// TODO when fixed types are implemented properly
|
||||||
// {"fixed", Type{}},
|
// {"fixed", Type{}},
|
||||||
|
|
|
||||||
|
|
@ -136,13 +136,12 @@ func (am *Manager) DeleteAccount(a Account, passphrase string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign calculates a ECDSA signature for the given hash.
|
// Sign calculates a ECDSA signature for the given hash. The produced signature
|
||||||
// Note, Ethereum signatures have a particular format as described in the
|
// is in the [R || S || V] format where V is 0 or 1.
|
||||||
// yellow paper. Use the SignEthereum function to calculate a signature
|
|
||||||
// in Ethereum format.
|
|
||||||
func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
|
func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
|
||||||
am.mu.RLock()
|
am.mu.RLock()
|
||||||
defer am.mu.RUnlock()
|
defer am.mu.RUnlock()
|
||||||
|
|
||||||
unlockedKey, found := am.unlocked[addr]
|
unlockedKey, found := am.unlocked[addr]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, ErrLocked
|
return nil, ErrLocked
|
||||||
|
|
@ -150,28 +149,16 @@ func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
|
||||||
return crypto.Sign(hash, unlockedKey.PrivateKey)
|
return crypto.Sign(hash, unlockedKey.PrivateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignEthereum calculates a ECDSA signature for the given hash.
|
// SignWithPassphrase signs hash if the private key matching the given address
|
||||||
// The signature has the format as described in the Ethereum yellow paper.
|
// can be decrypted with the given passphrase. The produced signature is in the
|
||||||
func (am *Manager) SignEthereum(addr common.Address, hash []byte) ([]byte, error) {
|
// [R || S || V] format where V is 0 or 1.
|
||||||
am.mu.RLock()
|
func (am *Manager) SignWithPassphrase(a Account, passphrase string, hash []byte) (signature []byte, err error) {
|
||||||
defer am.mu.RUnlock()
|
_, key, err := am.getDecryptedKey(a, passphrase)
|
||||||
unlockedKey, found := am.unlocked[addr]
|
|
||||||
if !found {
|
|
||||||
return nil, ErrLocked
|
|
||||||
}
|
|
||||||
return crypto.SignEthereum(hash, unlockedKey.PrivateKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignWithPassphrase signs hash if the private key matching the given
|
|
||||||
// address can be decrypted with the given passphrase.
|
|
||||||
func (am *Manager) SignWithPassphrase(addr common.Address, passphrase string, hash []byte) (signature []byte, err error) {
|
|
||||||
_, key, err := am.getDecryptedKey(Account{Address: addr}, passphrase)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer zeroKey(key.PrivateKey)
|
defer zeroKey(key.PrivateKey)
|
||||||
return crypto.SignEthereum(hash, key.PrivateKey)
|
return crypto.Sign(hash, key.PrivateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock unlocks the given account indefinitely.
|
// Unlock unlocks the given account indefinitely.
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ func TestSignWithPassphrase(t *testing.T) {
|
||||||
t.Fatal("expected account to be locked")
|
t.Fatal("expected account to be locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = am.SignWithPassphrase(acc.Address, pass, testSigData)
|
_, err = am.SignWithPassphrase(acc, pass, testSigData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +104,7 @@ func TestSignWithPassphrase(t *testing.T) {
|
||||||
t.Fatal("expected account to be locked")
|
t.Fatal("expected account to be locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = am.SignWithPassphrase(acc.Address, "invalid passwd", testSigData); err == nil {
|
if _, err = am.SignWithPassphrase(acc, "invalid passwd", testSigData); err == nil {
|
||||||
t.Fatal("expected SignHash to fail with invalid password")
|
t.Fatal("expected SignHash to fail with invalid password")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,6 +115,9 @@ func TestTimedUnlock(t *testing.T) {
|
||||||
|
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
a1, err := am.NewAccount(pass)
|
a1, err := am.NewAccount(pass)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Signing without passphrase fails because account is locked
|
// Signing without passphrase fails because account is locked
|
||||||
_, err = am.Sign(a1.Address, testSigData)
|
_, err = am.Sign(a1.Address, testSigData)
|
||||||
|
|
@ -147,6 +150,9 @@ func TestOverrideUnlock(t *testing.T) {
|
||||||
|
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
a1, err := am.NewAccount(pass)
|
a1, err := am.NewAccount(pass)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Unlock indefinitely.
|
// Unlock indefinitely.
|
||||||
if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil {
|
if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -53,6 +54,9 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
|
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("invalid hex in encSeed")
|
||||||
|
}
|
||||||
iv := encSeedBytes[:16]
|
iv := encSeedBytes[:16]
|
||||||
cipherText := encSeedBytes[16:]
|
cipherText := encSeedBytes[16:]
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
39
build/ci.go
39
build/ci.go
|
|
@ -24,7 +24,7 @@ Usage: go run ci.go <command> <command flags/arguments>
|
||||||
Available commands are:
|
Available commands are:
|
||||||
|
|
||||||
install [-arch architecture] [ packages... ] -- builds packages and executables
|
install [-arch architecture] [ packages... ] -- builds packages and executables
|
||||||
test [ -coverage ] [ -vet ] [ packages... ] -- runs the tests
|
test [ -coverage ] [ -vet ] [ -misspell ] [ packages... ] -- runs the tests
|
||||||
archive [-arch architecture] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts
|
archive [-arch architecture] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts
|
||||||
importkeys -- imports signing keys from env
|
importkeys -- imports signing keys from env
|
||||||
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
||||||
|
|
@ -195,7 +195,7 @@ func doInstall(cmdline []string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
for name, _ := range pkgs {
|
for name := range pkgs {
|
||||||
if name == "main" {
|
if name == "main" {
|
||||||
gobuild := goToolArch(*arch, "build", buildFlags(env)...)
|
gobuild := goToolArch(*arch, "build", buildFlags(env)...)
|
||||||
gobuild.Args = append(gobuild.Args, "-v")
|
gobuild.Args = append(gobuild.Args, "-v")
|
||||||
|
|
@ -262,6 +262,7 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd {
|
||||||
func doTest(cmdline []string) {
|
func doTest(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
vet = flag.Bool("vet", false, "Whether to run go vet")
|
vet = flag.Bool("vet", false, "Whether to run go vet")
|
||||||
|
misspell = flag.Bool("misspell", false, "Whether to run the spell checker")
|
||||||
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
|
coverage = flag.Bool("coverage", false, "Whether to record code coverage")
|
||||||
)
|
)
|
||||||
flag.CommandLine.Parse(cmdline)
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
|
@ -287,7 +288,9 @@ func doTest(cmdline []string) {
|
||||||
if *vet {
|
if *vet {
|
||||||
build.MustRun(goTool("vet", packages...))
|
build.MustRun(goTool("vet", packages...))
|
||||||
}
|
}
|
||||||
|
if *misspell {
|
||||||
|
spellcheck(packages)
|
||||||
|
}
|
||||||
// Run the actual tests.
|
// Run the actual tests.
|
||||||
gotest := goTool("test")
|
gotest := goTool("test")
|
||||||
// Test a single package at a time. CI builders are slow
|
// Test a single package at a time. CI builders are slow
|
||||||
|
|
@ -300,6 +303,34 @@ func doTest(cmdline []string) {
|
||||||
build.MustRun(gotest)
|
build.MustRun(gotest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// spellcheck runs the client9/misspell spellchecker package on all Go, Cgo and
|
||||||
|
// test files in the requested packages.
|
||||||
|
func spellcheck(packages []string) {
|
||||||
|
// Ensure the spellchecker is available
|
||||||
|
build.MustRun(goTool("get", "github.com/client9/misspell/cmd/misspell"))
|
||||||
|
|
||||||
|
// Windows chokes on long argument lists, check packages individualy
|
||||||
|
for _, pkg := range packages {
|
||||||
|
// The spell checker doesn't work on packages, gather all .go files for it
|
||||||
|
out, err := goTool("list", "-f", "{{.Dir}}{{range .GoFiles}}\n{{.}}{{end}}{{range .CgoFiles}}\n{{.}}{{end}}{{range .TestGoFiles}}\n{{.}}{{end}}", pkg).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("source file listing failed: %v\n%s", err, string(out))
|
||||||
|
}
|
||||||
|
// Retrieve the folder and assemble the source list
|
||||||
|
lines := strings.Split(string(out), "\n")
|
||||||
|
root := lines[0]
|
||||||
|
|
||||||
|
sources := make([]string, 0, len(lines)-1)
|
||||||
|
for _, line := range lines[1:] {
|
||||||
|
if line = strings.TrimSpace(line); line != "" {
|
||||||
|
sources = append(sources, filepath.Join(root, line))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Run the spell checker for this particular package
|
||||||
|
build.MustRunCommand(filepath.Join(GOBIN, "misspell"), append([]string{"-error"}, sources...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Release Packaging
|
// Release Packaging
|
||||||
|
|
||||||
func doArchive(cmdline []string) {
|
func doArchive(cmdline []string) {
|
||||||
|
|
@ -792,7 +823,7 @@ func doXCodeFramework(cmdline []string) {
|
||||||
// Build the iOS XCode framework
|
// Build the iOS XCode framework
|
||||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||||
build.MustRun(gomobileTool("init"))
|
build.MustRun(gomobileTool("init"))
|
||||||
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "--prefix", "i", "-v", "github.com/ethereum/go-ethereum/mobile")
|
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||||
|
|
||||||
if *local {
|
if *local {
|
||||||
// If we're building locally, use the build folder and stop afterwards
|
// If we're building locally, use the build folder and stop afterwards
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ func getFiles() []string {
|
||||||
files = append(files, line)
|
files = append(files, line)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error getting files:", err)
|
log.Fatal("error getting files:", err)
|
||||||
}
|
}
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +294,7 @@ func getInfo(files <-chan string, out chan<- *info, wg *sync.WaitGroup) {
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileInfo finds the lowest year in which the given file was commited.
|
// fileInfo finds the lowest year in which the given file was committed.
|
||||||
func fileInfo(file string) (*info, error) {
|
func fileInfo(file string) (*info, error) {
|
||||||
info := &info{file: file, Year: int64(time.Now().Year())}
|
info := &info{file: file, Year: int64(time.Now().Year())}
|
||||||
cmd := exec.Command("git", "log", "--follow", "--find-renames=80", "--find-copies=80", "--pretty=format:%ai", "--", file)
|
cmd := exec.Command("git", "log", "--follow", "--find-renames=80", "--find-copies=80", "--pretty=format:%ai", "--", file)
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"encoding/hex"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
@ -42,15 +42,19 @@ func main() {
|
||||||
|
|
||||||
for pc := uint64(0); pc < uint64(len(code)); pc++ {
|
for pc := uint64(0); pc < uint64(len(code)); pc++ {
|
||||||
op := vm.OpCode(code[pc])
|
op := vm.OpCode(code[pc])
|
||||||
fmt.Printf("%-5d %v", pc, op)
|
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8, vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15, vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22, vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29, vm.PUSH30, vm.PUSH31, vm.PUSH32:
|
case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8, vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15, vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22, vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29, vm.PUSH30, vm.PUSH31, vm.PUSH32:
|
||||||
a := uint64(op) - uint64(vm.PUSH1) + 1
|
a := uint64(op) - uint64(vm.PUSH1) + 1
|
||||||
fmt.Printf(" => %x", code[pc+1:pc+1+a])
|
u := pc + 1 + a
|
||||||
|
if uint64(len(code)) <= pc || uint64(len(code)) < u {
|
||||||
|
fmt.Printf("Error: incomplete push instruction at %v\n", pc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("%-5d %v => %x\n", pc, op, code[pc+1:u])
|
||||||
pc += a
|
pc += a
|
||||||
|
default:
|
||||||
|
fmt.Printf("%-5d %v\n", pc, op)
|
||||||
}
|
}
|
||||||
fmt.Println()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,12 +88,7 @@ func runTestWithReader(test string, r io.Reader) error {
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("Invalid test type specified: %v", test)
|
err = fmt.Errorf("Invalid test type specified: %v", test)
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFiles(path string) ([]string, error) {
|
func getFiles(path string) ([]string, error) {
|
||||||
|
|
|
||||||
|
|
@ -44,14 +44,6 @@ var (
|
||||||
Name: "debug",
|
Name: "debug",
|
||||||
Usage: "output full trace logs",
|
Usage: "output full trace logs",
|
||||||
}
|
}
|
||||||
ForceJitFlag = cli.BoolFlag{
|
|
||||||
Name: "forcejit",
|
|
||||||
Usage: "forces jit compilation",
|
|
||||||
}
|
|
||||||
DisableJitFlag = cli.BoolFlag{
|
|
||||||
Name: "nojit",
|
|
||||||
Usage: "disabled jit compilation",
|
|
||||||
}
|
|
||||||
CodeFlag = cli.StringFlag{
|
CodeFlag = cli.StringFlag{
|
||||||
Name: "code",
|
Name: "code",
|
||||||
Usage: "EVM code",
|
Usage: "EVM code",
|
||||||
|
|
@ -95,6 +87,10 @@ var (
|
||||||
Name: "create",
|
Name: "create",
|
||||||
Usage: "indicates the action should be create rather than call",
|
Usage: "indicates the action should be create rather than call",
|
||||||
}
|
}
|
||||||
|
DisableGasMeteringFlag = cli.BoolFlag{
|
||||||
|
Name: "nogasmetering",
|
||||||
|
Usage: "disable gas metering",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -102,8 +98,6 @@ func init() {
|
||||||
CreateFlag,
|
CreateFlag,
|
||||||
DebugFlag,
|
DebugFlag,
|
||||||
VerbosityFlag,
|
VerbosityFlag,
|
||||||
ForceJitFlag,
|
|
||||||
DisableJitFlag,
|
|
||||||
SysStatFlag,
|
SysStatFlag,
|
||||||
CodeFlag,
|
CodeFlag,
|
||||||
CodeFileFlag,
|
CodeFileFlag,
|
||||||
|
|
@ -112,6 +106,7 @@ func init() {
|
||||||
ValueFlag,
|
ValueFlag,
|
||||||
DumpFlag,
|
DumpFlag,
|
||||||
InputFlag,
|
InputFlag,
|
||||||
|
DisableGasMeteringFlag,
|
||||||
}
|
}
|
||||||
app.Action = run
|
app.Action = run
|
||||||
}
|
}
|
||||||
|
|
@ -165,7 +160,8 @@ func run(ctx *cli.Context) error {
|
||||||
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||||
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||||
EVMConfig: vm.Config{
|
EVMConfig: vm.Config{
|
||||||
Tracer: logger,
|
Tracer: logger,
|
||||||
|
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -179,7 +175,8 @@ func run(ctx *cli.Context) error {
|
||||||
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||||
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||||
EVMConfig: vm.Config{
|
EVMConfig: vm.Config{
|
||||||
Tracer: logger,
|
Tracer: logger,
|
||||||
|
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ Passphrase: {{.InputLine "foobar"}}
|
||||||
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if strings.Index(geth.stderrText(), m) == -1 {
|
if !strings.Contains(geth.stderrText(), m) {
|
||||||
t.Errorf("stderr text does not contain %q", m)
|
t.Errorf("stderr text does not contain %q", m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +193,7 @@ Passphrase: {{.InputLine "foobar"}}
|
||||||
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if strings.Index(geth.stderrText(), m) == -1 {
|
if !strings.Contains(geth.stderrText(), m) {
|
||||||
t.Errorf("stderr text does not contain %q", m)
|
t.Errorf("stderr text does not contain %q", m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +212,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
|
||||||
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if strings.Index(geth.stderrText(), m) == -1 {
|
if !strings.Contains(geth.stderrText(), m) {
|
||||||
t.Errorf("stderr text does not contain %q", m)
|
t.Errorf("stderr text does not contain %q", m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -260,7 +260,7 @@ In order to avoid this warning, you need to remove the following duplicate key f
|
||||||
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if strings.Index(geth.stderrText(), m) == -1 {
|
if !strings.Contains(geth.stderrText(), m) {
|
||||||
t.Errorf("stderr text does not contain %q", m)
|
t.Errorf("stderr text does not contain %q", m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,6 @@ func init() {
|
||||||
utils.BootnodesFlag,
|
utils.BootnodesFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
utils.KeyStoreDirFlag,
|
utils.KeyStoreDirFlag,
|
||||||
utils.OlympicFlag,
|
|
||||||
utils.FastSyncFlag,
|
utils.FastSyncFlag,
|
||||||
utils.LightModeFlag,
|
utils.LightModeFlag,
|
||||||
utils.LightServFlag,
|
utils.LightServFlag,
|
||||||
|
|
@ -168,7 +167,6 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.After = func(ctx *cli.Context) error {
|
app.After = func(ctx *cli.Context) error {
|
||||||
logger.Flush()
|
|
||||||
debug.Exit()
|
debug.Exit()
|
||||||
console.Stdin.Close() // Resets terminal mode.
|
console.Stdin.Close() // Resets terminal mode.
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -236,8 +236,9 @@ func expandMetrics(metrics map[string]interface{}, path string) []string {
|
||||||
|
|
||||||
// fetchMetric iterates over the metrics map and retrieves a specific one.
|
// fetchMetric iterates over the metrics map and retrieves a specific one.
|
||||||
func fetchMetric(metrics map[string]interface{}, metric string) float64 {
|
func fetchMetric(metrics map[string]interface{}, metric string) float64 {
|
||||||
parts, found := strings.Split(metric, "/"), true
|
parts := strings.Split(metric, "/")
|
||||||
for _, part := range parts[:len(parts)-1] {
|
for _, part := range parts[:len(parts)-1] {
|
||||||
|
var found bool
|
||||||
metrics, found = metrics[part].(map[string]interface{})
|
metrics, found = metrics[part].(map[string]interface{})
|
||||||
if !found {
|
if !found {
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,6 @@ var AppHelpFlagGroups = []flagGroup{
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
utils.KeyStoreDirFlag,
|
utils.KeyStoreDirFlag,
|
||||||
utils.NetworkIdFlag,
|
utils.NetworkIdFlag,
|
||||||
utils.OlympicFlag,
|
|
||||||
utils.TestNetFlag,
|
utils.TestNetFlag,
|
||||||
utils.DevModeFlag,
|
utils.DevModeFlag,
|
||||||
utils.IdentityFlag,
|
utils.IdentityFlag,
|
||||||
|
|
|
||||||
|
|
@ -82,15 +82,15 @@ var (
|
||||||
Name: "bzzconfig",
|
Name: "bzzconfig",
|
||||||
Usage: "Swarm config file path (datadir/bzz)",
|
Usage: "Swarm config file path (datadir/bzz)",
|
||||||
}
|
}
|
||||||
SwarmSwapEnabled = cli.BoolFlag{
|
SwarmSwapEnabledFlag = cli.BoolFlag{
|
||||||
Name: "swap",
|
Name: "swap",
|
||||||
Usage: "Swarm SWAP enabled (default false)",
|
Usage: "Swarm SWAP enabled (default false)",
|
||||||
}
|
}
|
||||||
SwarmSyncEnabled = cli.BoolTFlag{
|
SwarmSyncEnabledFlag = cli.BoolTFlag{
|
||||||
Name: "sync",
|
Name: "sync",
|
||||||
Usage: "Swarm Syncing enabled (default true)",
|
Usage: "Swarm Syncing enabled (default true)",
|
||||||
}
|
}
|
||||||
EthAPI = cli.StringFlag{
|
EthAPIFlag = cli.StringFlag{
|
||||||
Name: "ethapi",
|
Name: "ethapi",
|
||||||
Usage: "URL of the Ethereum API provider",
|
Usage: "URL of the Ethereum API provider",
|
||||||
Value: node.DefaultIPCEndpoint("geth"),
|
Value: node.DefaultIPCEndpoint("geth"),
|
||||||
|
|
@ -112,6 +112,10 @@ var (
|
||||||
Name: "defaultpath",
|
Name: "defaultpath",
|
||||||
Usage: "path to file served for empty url path (none)",
|
Usage: "path to file served for empty url path (none)",
|
||||||
}
|
}
|
||||||
|
CorsStringFlag = cli.StringFlag{
|
||||||
|
Name: "corsdomain",
|
||||||
|
Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -125,7 +129,7 @@ func init() {
|
||||||
app.HideVersion = true // we have a command to print the version
|
app.HideVersion = true // we have a command to print the version
|
||||||
app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
|
app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
cli.Command{
|
{
|
||||||
Action: version,
|
Action: version,
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Usage: "Print version numbers",
|
Usage: "Print version numbers",
|
||||||
|
|
@ -134,7 +138,7 @@ func init() {
|
||||||
The output of this command is supposed to be machine-readable.
|
The output of this command is supposed to be machine-readable.
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
cli.Command{
|
{
|
||||||
Action: upload,
|
Action: upload,
|
||||||
Name: "up",
|
Name: "up",
|
||||||
Usage: "upload a file or directory to swarm using the HTTP API",
|
Usage: "upload a file or directory to swarm using the HTTP API",
|
||||||
|
|
@ -143,7 +147,7 @@ The output of this command is supposed to be machine-readable.
|
||||||
"upload a file or directory to swarm using the HTTP API and prints the root hash",
|
"upload a file or directory to swarm using the HTTP API and prints the root hash",
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
cli.Command{
|
{
|
||||||
Action: hash,
|
Action: hash,
|
||||||
Name: "hash",
|
Name: "hash",
|
||||||
Usage: "print the swarm hash of a file or directory",
|
Usage: "print the swarm hash of a file or directory",
|
||||||
|
|
@ -171,10 +175,11 @@ Prints the swarm hash of file or directory.
|
||||||
utils.IPCApiFlag,
|
utils.IPCApiFlag,
|
||||||
utils.IPCPathFlag,
|
utils.IPCPathFlag,
|
||||||
// bzzd-specific flags
|
// bzzd-specific flags
|
||||||
EthAPI,
|
CorsStringFlag,
|
||||||
|
EthAPIFlag,
|
||||||
SwarmConfigPathFlag,
|
SwarmConfigPathFlag,
|
||||||
SwarmSwapEnabled,
|
SwarmSwapEnabledFlag,
|
||||||
SwarmSyncEnabled,
|
SwarmSyncEnabledFlag,
|
||||||
SwarmPortFlag,
|
SwarmPortFlag,
|
||||||
SwarmAccountFlag,
|
SwarmAccountFlag,
|
||||||
SwarmNetworkIdFlag,
|
SwarmNetworkIdFlag,
|
||||||
|
|
@ -252,10 +257,11 @@ func registerBzzService(ctx *cli.Context, stack *node.Node) {
|
||||||
if len(bzzport) > 0 {
|
if len(bzzport) > 0 {
|
||||||
bzzconfig.Port = bzzport
|
bzzconfig.Port = bzzport
|
||||||
}
|
}
|
||||||
swapEnabled := ctx.GlobalBool(SwarmSwapEnabled.Name)
|
swapEnabled := ctx.GlobalBool(SwarmSwapEnabledFlag.Name)
|
||||||
syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabled.Name)
|
syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabledFlag.Name)
|
||||||
|
|
||||||
ethapi := ctx.GlobalString(EthAPI.Name)
|
ethapi := ctx.GlobalString(EthAPIFlag.Name)
|
||||||
|
cors := ctx.GlobalString(CorsStringFlag.Name)
|
||||||
|
|
||||||
boot := func(ctx *node.ServiceContext) (node.Service, error) {
|
boot := func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
var client *ethclient.Client
|
var client *ethclient.Client
|
||||||
|
|
@ -265,7 +271,7 @@ func registerBzzService(ctx *cli.Context, stack *node.Node) {
|
||||||
utils.Fatalf("Can't connect: %v", err)
|
utils.Fatalf("Can't connect: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled)
|
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled, cors)
|
||||||
}
|
}
|
||||||
if err := stack.Register(boot); err != nil {
|
if err := stack.Register(boot); err != nil {
|
||||||
utils.Fatalf("Failed to register the Swarm service: %v", err)
|
utils.Fatalf("Failed to register the Swarm service: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,6 @@ func upload(ctx *cli.Context) {
|
||||||
var (
|
var (
|
||||||
file = args[0]
|
file = args[0]
|
||||||
client = &client{api: bzzapi}
|
client = &client{api: bzzapi}
|
||||||
mroot manifest
|
|
||||||
entry manifestEntry
|
|
||||||
)
|
)
|
||||||
fi, err := os.Stat(expandPath(file))
|
fi, err := os.Stat(expandPath(file))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -61,14 +59,21 @@ func upload(ctx *cli.Context) {
|
||||||
if !recursive {
|
if !recursive {
|
||||||
log.Fatal("argument is a directory and recursive upload is disabled")
|
log.Fatal("argument is a directory and recursive upload is disabled")
|
||||||
}
|
}
|
||||||
mroot, err = client.uploadDirectory(file, defaultPath)
|
if !wantManifest {
|
||||||
} else {
|
log.Fatal("manifest is required for directory uploads")
|
||||||
entry, err = client.uploadFile(file, fi)
|
}
|
||||||
mroot = manifest{[]manifestEntry{entry}}
|
mhash, err := client.uploadDirectory(file, defaultPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(mhash)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
entry, err := client.uploadFile(file, fi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("upload failed:", err)
|
log.Fatalln("upload failed:", err)
|
||||||
}
|
}
|
||||||
|
mroot := manifest{[]manifestEntry{entry}}
|
||||||
if !wantManifest {
|
if !wantManifest {
|
||||||
// Print the manifest. This is the only output to stdout.
|
// Print the manifest. This is the only output to stdout.
|
||||||
mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
|
mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
|
||||||
|
|
@ -123,6 +128,36 @@ type manifest struct {
|
||||||
Entries []manifestEntry `json:"entries,omitempty"`
|
Entries []manifestEntry `json:"entries,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *client) uploadDirectory(dir string, defaultPath string) (string, error) {
|
||||||
|
mhash, err := c.postRaw("application/json", 2, ioutil.NopCloser(bytes.NewReader([]byte("{}"))))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to upload empty manifest")
|
||||||
|
}
|
||||||
|
if len(defaultPath) > 0 {
|
||||||
|
fi, err := os.Stat(defaultPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
mhash, err = c.uploadToManifest(mhash, "", defaultPath, fi)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefix := filepath.ToSlash(filepath.Clean(dir)) + "/"
|
||||||
|
err = filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
|
||||||
|
if err != nil || fi.IsDir() {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(path, dir) {
|
||||||
|
return fmt.Errorf("path %s outside directory %s", path, dir)
|
||||||
|
}
|
||||||
|
uripath := strings.TrimPrefix(filepath.ToSlash(filepath.Clean(path)), prefix)
|
||||||
|
mhash, err = c.uploadToManifest(mhash, uripath, path, fi)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return mhash, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *client) uploadFile(file string, fi os.FileInfo) (manifestEntry, error) {
|
func (c *client) uploadFile(file string, fi os.FileInfo) (manifestEntry, error) {
|
||||||
hash, err := c.uploadFileContent(file, fi)
|
hash, err := c.uploadFileContent(file, fi)
|
||||||
m := manifestEntry{
|
m := manifestEntry{
|
||||||
|
|
@ -132,36 +167,6 @@ func (c *client) uploadFile(file string, fi os.FileInfo) (manifestEntry, error)
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) uploadDirectory(dir string, defaultPath string) (manifest, error) {
|
|
||||||
dirm := manifest{}
|
|
||||||
if len(defaultPath) > 0 {
|
|
||||||
fi, err := os.Stat(defaultPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
entry, err := c.uploadFile(defaultPath, fi)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
entry.Path = ""
|
|
||||||
dirm.Entries = append(dirm.Entries, entry)
|
|
||||||
}
|
|
||||||
prefix := filepath.ToSlash(filepath.Clean(dir)) + "/"
|
|
||||||
err := filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
|
|
||||||
if err != nil || fi.IsDir() {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(path, dir) {
|
|
||||||
return fmt.Errorf("path %s outside directory %s", path, dir)
|
|
||||||
}
|
|
||||||
entry, err := c.uploadFile(path, fi)
|
|
||||||
entry.Path = strings.TrimPrefix(filepath.ToSlash(filepath.Clean(path)), prefix)
|
|
||||||
dirm.Entries = append(dirm.Entries, entry)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return dirm, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) uploadFileContent(file string, fi os.FileInfo) (string, error) {
|
func (c *client) uploadFileContent(file string, fi os.FileInfo) (string, error) {
|
||||||
fd, err := os.Open(file)
|
fd, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -181,6 +186,31 @@ func (c *client) uploadManifest(m manifest) (string, error) {
|
||||||
return c.postRaw("application/json", int64(len(jsm)), ioutil.NopCloser(bytes.NewReader(jsm)))
|
return c.postRaw("application/json", int64(len(jsm)), ioutil.NopCloser(bytes.NewReader(jsm)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *client) uploadToManifest(mhash string, path string, fpath string, fi os.FileInfo) (string, error) {
|
||||||
|
fd, err := os.Open(fpath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
log.Printf("uploading file %s (%d bytes) and adding path %v", fpath, fi.Size(), path)
|
||||||
|
req, err := http.NewRequest("PUT", c.api+"/bzz:/"+mhash+"/"+path, fd)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("content-type", mime.TypeByExtension(filepath.Ext(fi.Name())))
|
||||||
|
req.ContentLength = fi.Size()
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode >= 400 {
|
||||||
|
return "", fmt.Errorf("bad status: %s", resp.Status)
|
||||||
|
}
|
||||||
|
content, err := ioutil.ReadAll(resp.Body)
|
||||||
|
return string(content), err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *client) postRaw(mimetype string, size int64, body io.ReadCloser) (string, error) {
|
func (c *client) postRaw(mimetype string, size int64, body io.ReadCloser) (string, error) {
|
||||||
req, err := http.NewRequest("POST", c.api+"/bzzr:/", body)
|
req, err := http.NewRequest("POST", c.api+"/bzzr:/", body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,6 @@ func Fatalf(format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
|
fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
|
||||||
logger.Flush()
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,7 +94,7 @@ func StartNode(stack *node.Node) {
|
||||||
|
|
||||||
func FormatTransactionData(data string) []byte {
|
func FormatTransactionData(data string) []byte {
|
||||||
d := common.StringToByteFunc(data, func(s string) (ret []byte) {
|
d := common.StringToByteFunc(data, func(s string) (ret []byte) {
|
||||||
slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
|
slice := regexp.MustCompile(`\n|\s`).Split(s, 1000000000)
|
||||||
for _, dataItem := range slice {
|
for _, dataItem := range slice {
|
||||||
d := common.FormatData(dataItem)
|
d := common.FormatData(dataItem)
|
||||||
ret = append(ret, d...)
|
ret = append(ret, d...)
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ import (
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Custom type which is registered in the flags library which cli uses for
|
// Custom type which is registered in the flags library which cli uses for
|
||||||
|
|
@ -46,7 +44,6 @@ func (self *DirectoryString) Set(value string) error {
|
||||||
// Custom cli.Flag type which expand the received string to an absolute path.
|
// Custom cli.Flag type which expand the received string to an absolute path.
|
||||||
// e.g. ~/.ethereum -> /home/username/.ethereum
|
// e.g. ~/.ethereum -> /home/username/.ethereum
|
||||||
type DirectoryFlag struct {
|
type DirectoryFlag struct {
|
||||||
cli.GenericFlag
|
|
||||||
Name string
|
Name string
|
||||||
Value DirectoryString
|
Value DirectoryString
|
||||||
Usage string
|
Usage string
|
||||||
|
|
@ -54,15 +51,10 @@ type DirectoryFlag struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DirectoryFlag) String() string {
|
func (self DirectoryFlag) String() string {
|
||||||
var fmtString string
|
fmtString := "%s %v\t%v"
|
||||||
fmtString = "%s %v\t%v"
|
|
||||||
|
|
||||||
if len(self.Value.Value) > 0 {
|
if len(self.Value.Value) > 0 {
|
||||||
fmtString = "%s \"%v\"\t%v"
|
fmtString = "%s \"%v\"\t%v"
|
||||||
} else {
|
|
||||||
fmtString = "%s %v\t%v"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage))
|
return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,7 +114,7 @@ func withEnvHint(envVar, str string) string {
|
||||||
return str + envText
|
return str + envText
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self DirectoryFlag) getName() string {
|
func (self DirectoryFlag) GetName() string {
|
||||||
return self.Name
|
return self.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -116,13 +115,9 @@ var (
|
||||||
}
|
}
|
||||||
NetworkIdFlag = cli.IntFlag{
|
NetworkIdFlag = cli.IntFlag{
|
||||||
Name: "networkid",
|
Name: "networkid",
|
||||||
Usage: "Network identifier (integer, 0=Olympic (disused), 1=Frontier, 2=Morden (disused), 3=Ropsten)",
|
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)",
|
||||||
Value: eth.NetworkId,
|
Value: eth.NetworkId,
|
||||||
}
|
}
|
||||||
OlympicFlag = cli.BoolFlag{
|
|
||||||
Name: "olympic",
|
|
||||||
Usage: "Olympic network: pre-configured pre-release test network",
|
|
||||||
}
|
|
||||||
TestNetFlag = cli.BoolFlag{
|
TestNetFlag = cli.BoolFlag{
|
||||||
Name: "testnet",
|
Name: "testnet",
|
||||||
Usage: "Ropsten network: pre-configured test network",
|
Usage: "Ropsten network: pre-configured test network",
|
||||||
|
|
@ -485,17 +480,15 @@ func makeNodeUserIdent(ctx *cli.Context) string {
|
||||||
// MakeBootstrapNodes creates a list of bootstrap nodes from the command line
|
// MakeBootstrapNodes creates a list of bootstrap nodes from the command line
|
||||||
// flags, reverting to pre-configured ones if none have been specified.
|
// flags, reverting to pre-configured ones if none have been specified.
|
||||||
func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
||||||
// Return pre-configured nodes if none were manually requested
|
urls := params.MainnetBootnodes
|
||||||
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
if ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
|
||||||
return params.TestnetBootnodes
|
} else if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
}
|
urls = params.TestnetBootnodes
|
||||||
return params.MainnetBootnodes
|
|
||||||
}
|
}
|
||||||
// Otherwise parse and use the CLI bootstrap nodes
|
|
||||||
bootnodes := []*discover.Node{}
|
|
||||||
|
|
||||||
for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") {
|
bootnodes := make([]*discover.Node, 0, len(urls))
|
||||||
|
for _, url := range urls {
|
||||||
node, err := discover.ParseNode(url)
|
node, err := discover.ParseNode(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||||
|
|
@ -509,14 +502,13 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
||||||
// MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line
|
// MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line
|
||||||
// flags, reverting to pre-configured ones if none have been specified.
|
// flags, reverting to pre-configured ones if none have been specified.
|
||||||
func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
|
func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
|
||||||
// Return pre-configured nodes if none were manually requested
|
urls := params.DiscoveryV5Bootnodes
|
||||||
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
if ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||||
return params.DiscoveryV5Bootnodes
|
urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
|
||||||
}
|
}
|
||||||
// Otherwise parse and use the CLI bootstrap nodes
|
|
||||||
bootnodes := []*discv5.Node{}
|
|
||||||
|
|
||||||
for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") {
|
bootnodes := make([]*discv5.Node, 0, len(urls))
|
||||||
|
for _, url := range urls {
|
||||||
node, err := discv5.ParseNode(url)
|
node, err := discv5.ParseNode(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||||
|
|
@ -715,7 +707,7 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
|
||||||
// given node.
|
// given node.
|
||||||
func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
// Avoid conflicting network flags
|
// Avoid conflicting network flags
|
||||||
networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag}
|
networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag}
|
||||||
for _, flag := range netFlags {
|
for _, flag := range netFlags {
|
||||||
if ctx.GlobalBool(flag.Name) {
|
if ctx.GlobalBool(flag.Name) {
|
||||||
networks++
|
networks++
|
||||||
|
|
@ -753,12 +745,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
|
|
||||||
// Override any default configs in dev mode or the test net
|
// Override any default configs in dev mode or the test net
|
||||||
switch {
|
switch {
|
||||||
case ctx.GlobalBool(OlympicFlag.Name):
|
|
||||||
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
|
|
||||||
ethConf.NetworkId = 1
|
|
||||||
}
|
|
||||||
ethConf.Genesis = core.OlympicGenesisBlock()
|
|
||||||
|
|
||||||
case ctx.GlobalBool(TestNetFlag.Name):
|
case ctx.GlobalBool(TestNetFlag.Name):
|
||||||
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
|
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
|
||||||
ethConf.NetworkId = 3
|
ethConf.NetworkId = 3
|
||||||
|
|
@ -766,7 +752,7 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||||
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
||||||
|
|
||||||
case ctx.GlobalBool(DevModeFlag.Name):
|
case ctx.GlobalBool(DevModeFlag.Name):
|
||||||
ethConf.Genesis = core.OlympicGenesisBlock()
|
ethConf.Genesis = core.DevGenesisBlock()
|
||||||
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
|
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
|
||||||
ethConf.GasPrice = new(big.Int)
|
ethConf.GasPrice = new(big.Int)
|
||||||
}
|
}
|
||||||
|
|
@ -823,16 +809,6 @@ func RegisterEthStatsService(stack *node.Node, url string) {
|
||||||
|
|
||||||
// SetupNetwork configures the system for either the main net or some test network.
|
// SetupNetwork configures the system for either the main net or some test network.
|
||||||
func SetupNetwork(ctx *cli.Context) {
|
func SetupNetwork(ctx *cli.Context) {
|
||||||
switch {
|
|
||||||
case ctx.GlobalBool(OlympicFlag.Name):
|
|
||||||
params.DurationLimit = big.NewInt(8)
|
|
||||||
params.GenesisGasLimit = big.NewInt(3141592)
|
|
||||||
params.MinGasLimit = big.NewInt(125000)
|
|
||||||
params.MaximumExtraDataSize = big.NewInt(1024)
|
|
||||||
NetworkIdFlag.Value = 0
|
|
||||||
core.BlockReward = big.NewInt(1.5e+18)
|
|
||||||
core.ExpDiffPeriod = big.NewInt(math.MaxInt64)
|
|
||||||
}
|
|
||||||
params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name))
|
params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -923,12 +899,13 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
|
||||||
var err error
|
var err error
|
||||||
chainDb = MakeChainDatabase(ctx, stack)
|
chainDb = MakeChainDatabase(ctx, stack)
|
||||||
|
|
||||||
if ctx.GlobalBool(OlympicFlag.Name) {
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
_, err := core.WriteTestNetGenesisBlock(chainDb)
|
_, err := core.WriteTestNetGenesisBlock(chainDb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalln(err)
|
glog.Fatalln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chainConfig := MakeChainConfigFromDb(ctx, chainDb)
|
chainConfig := MakeChainConfigFromDb(ctx, chainDb)
|
||||||
|
|
||||||
pow := pow.PoW(core.FakePow{})
|
pow := pow.PoW(core.FakePow{})
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func TestMisc(t *testing.T) {
|
||||||
c := []byte{1, 2, 3, 4}
|
c := []byte{1, 2, 3, 4}
|
||||||
z := BitTest(a, 1)
|
z := BitTest(a, 1)
|
||||||
|
|
||||||
if z != true {
|
if !z {
|
||||||
t.Error("Expected true got", z)
|
t.Error("Expected true got", z)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,11 +79,11 @@ func TestBigCopy(t *testing.T) {
|
||||||
z := BigToBytes(c, 16)
|
z := BigToBytes(c, 16)
|
||||||
zbytes := []byte{232, 212, 165, 16, 0}
|
zbytes := []byte{232, 212, 165, 16, 0}
|
||||||
|
|
||||||
if bytes.Compare(y, ybytes) != 0 {
|
if !bytes.Equal(y, ybytes) {
|
||||||
t.Error("Got", ybytes)
|
t.Error("Got", ybytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Compare(z, zbytes) != 0 {
|
if !bytes.Equal(z, zbytes) {
|
||||||
t.Error("Got", zbytes)
|
t.Error("Got", zbytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ func Hex2BytesFixed(str string, flen int) []byte {
|
||||||
return h
|
return h
|
||||||
} else {
|
} else {
|
||||||
if len(h) > flen {
|
if len(h) > flen {
|
||||||
return h[len(h)-flen : len(h)]
|
return h[len(h)-flen:]
|
||||||
} else {
|
} else {
|
||||||
hh := make([]byte, flen)
|
hh := make([]byte, flen)
|
||||||
copy(hh[flen-len(h):flen], h[:])
|
copy(hh[flen-len(h):flen], h[:])
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ func TestFromHex(t *testing.T) {
|
||||||
input := "0x01"
|
input := "0x01"
|
||||||
expected := []byte{1}
|
expected := []byte{1}
|
||||||
result := FromHex(input)
|
result := FromHex(input)
|
||||||
if bytes.Compare(expected, result) != 0 {
|
if !bytes.Equal(expected, result) {
|
||||||
t.Errorf("Expected % x got % x", expected, result)
|
t.Errorf("Expected % x got % x", expected, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +190,7 @@ func TestFromHexOddLength(t *testing.T) {
|
||||||
input := "0x1"
|
input := "0x1"
|
||||||
expected := []byte{1}
|
expected := []byte{1}
|
||||||
result := FromHex(input)
|
result := FromHex(input)
|
||||||
if bytes.Compare(expected, result) != 0 {
|
if !bytes.Equal(expected, result) {
|
||||||
t.Errorf("Expected % x got % x", expected, result)
|
t.Errorf("Expected % x got % x", expected, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -34,7 +32,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
versionRegexp = regexp.MustCompile("[0-9]+\\.[0-9]+\\.[0-9]+")
|
versionRegexp = regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`)
|
||||||
solcParams = []string{
|
solcParams = []string{
|
||||||
"--combined-json", "bin,abi,userdoc,devdoc",
|
"--combined-json", "bin,abi,userdoc,devdoc",
|
||||||
"--add-std", // include standard lib contracts
|
"--add-std", // include standard lib contracts
|
||||||
|
|
@ -96,27 +94,16 @@ func CompileSolidityString(solc, source string) (map[string]*Contract, error) {
|
||||||
if solc == "" {
|
if solc == "" {
|
||||||
solc = "solc"
|
solc = "solc"
|
||||||
}
|
}
|
||||||
// Write source to a temporary file. Compiling stdin used to be supported
|
args := append(solcParams, "--")
|
||||||
// but seems to produce an exception with solc 0.3.5.
|
cmd := exec.Command(solc, append(args, "-")...)
|
||||||
infile, err := ioutil.TempFile("", "geth-compile-solidity")
|
cmd.Stdin = strings.NewReader(source)
|
||||||
if err != nil {
|
return runsolc(cmd, source)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer os.Remove(infile.Name())
|
|
||||||
if _, err := io.WriteString(infile, source); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := infile.Close(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return CompileSolidity(solc, infile.Name())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompileSolidity compiles all given Solidity source files.
|
// CompileSolidity compiles all given Solidity source files.
|
||||||
func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
|
func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
|
||||||
if len(sourcefiles) == 0 {
|
if len(sourcefiles) == 0 {
|
||||||
return nil, errors.New("solc: no source ")
|
return nil, errors.New("solc: no source files")
|
||||||
}
|
}
|
||||||
source, err := slurpFiles(sourcefiles)
|
source, err := slurpFiles(sourcefiles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -125,10 +112,13 @@ func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract,
|
||||||
if solc == "" {
|
if solc == "" {
|
||||||
solc = "solc"
|
solc = "solc"
|
||||||
}
|
}
|
||||||
|
|
||||||
var stderr, stdout bytes.Buffer
|
|
||||||
args := append(solcParams, "--")
|
args := append(solcParams, "--")
|
||||||
cmd := exec.Command(solc, append(args, sourcefiles...)...)
|
cmd := exec.Command(solc, append(args, sourcefiles...)...)
|
||||||
|
return runsolc(cmd, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runsolc(cmd *exec.Cmd, source string) (map[string]*Contract, error) {
|
||||||
|
var stderr, stdout bytes.Buffer
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
cmd.Stdout = &stdout
|
cmd.Stdout = &stdout
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -27,8 +28,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
supportedSolcVersion = "0.3.5"
|
testSource = `
|
||||||
testSource = `
|
|
||||||
contract test {
|
contract test {
|
||||||
/// @notice Will multiply ` + "`a`" + ` by 7.
|
/// @notice Will multiply ` + "`a`" + ` by 7.
|
||||||
function multiply(uint a) returns(uint d) {
|
function multiply(uint a) returns(uint d) {
|
||||||
|
|
@ -36,23 +36,18 @@ contract test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
testCode = "0x6060604052602a8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b6007600435026060908152602090f3"
|
|
||||||
testInfo = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}`
|
testInfo = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}`
|
||||||
)
|
)
|
||||||
|
|
||||||
func skipUnsupported(t *testing.T) {
|
func skipWithoutSolc(t *testing.T) {
|
||||||
sol, err := SolidityVersion("")
|
if _, err := exec.LookPath("solc"); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Skip(err)
|
t.Skip(err)
|
||||||
return
|
|
||||||
}
|
|
||||||
if sol.Version != supportedSolcVersion {
|
|
||||||
t.Skipf("unsupported version of solc found (%v, expect %v)", sol.Version, supportedSolcVersion)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompiler(t *testing.T) {
|
func TestCompiler(t *testing.T) {
|
||||||
skipUnsupported(t)
|
skipWithoutSolc(t)
|
||||||
|
|
||||||
contracts, err := CompileSolidityString("", testSource)
|
contracts, err := CompileSolidityString("", testSource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error compiling source. result %v: %v", contracts, err)
|
t.Fatalf("error compiling source. result %v: %v", contracts, err)
|
||||||
|
|
@ -64,19 +59,20 @@ func TestCompiler(t *testing.T) {
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("info for contract 'test' not present in result")
|
t.Fatal("info for contract 'test' not present in result")
|
||||||
}
|
}
|
||||||
if c.Code != testCode {
|
if c.Code == "" {
|
||||||
t.Errorf("wrong code: expected\n%s, got\n%s", testCode, c.Code)
|
t.Error("empty code")
|
||||||
}
|
}
|
||||||
if c.Info.Source != testSource {
|
if c.Info.Source != testSource {
|
||||||
t.Error("wrong source")
|
t.Error("wrong source")
|
||||||
}
|
}
|
||||||
if c.Info.CompilerVersion != supportedSolcVersion {
|
if c.Info.CompilerVersion == "" {
|
||||||
t.Errorf("wrong version: expected %q, got %q", supportedSolcVersion, c.Info.CompilerVersion)
|
t.Error("empty version")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompileError(t *testing.T) {
|
func TestCompileError(t *testing.T) {
|
||||||
skipUnsupported(t)
|
skipWithoutSolc(t)
|
||||||
|
|
||||||
contracts, err := CompileSolidityString("", testSource[4:])
|
contracts, err := CompileSolidityString("", testSource[4:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("error expected compiling source. got none. result %v", contracts)
|
t.Errorf("error expected compiling source. got none. result %v", contracts)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import (
|
||||||
// the unnecessary precision off from the formatted textual representation.
|
// the unnecessary precision off from the formatted textual representation.
|
||||||
type PrettyDuration time.Duration
|
type PrettyDuration time.Duration
|
||||||
|
|
||||||
var prettyDurationRe = regexp.MustCompile("\\.[0-9]+")
|
var prettyDurationRe = regexp.MustCompile(`\.[0-9]+`)
|
||||||
|
|
||||||
// String implements the Stringer interface, allowing pretty printing of duration
|
// String implements the Stringer interface, allowing pretty printing of duration
|
||||||
// values rounded to three decimals.
|
// values rounded to three decimals.
|
||||||
|
|
|
||||||
|
|
@ -169,12 +169,7 @@ func EncodeBig(bigint *big.Int) string {
|
||||||
if nbits == 0 {
|
if nbits == 0 {
|
||||||
return "0x0"
|
return "0x0"
|
||||||
}
|
}
|
||||||
enc := make([]byte, 2, (nbits/8)*2+2)
|
return fmt.Sprintf("0x%x", bigint)
|
||||||
copy(enc, "0x")
|
|
||||||
for i := len(bigint.Bits()) - 1; i >= 0; i-- {
|
|
||||||
enc = strconv.AppendUint(enc, uint64(bigint.Bits()[i]), 16)
|
|
||||||
}
|
|
||||||
return string(enc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func has0xPrefix(input string) bool {
|
func has0xPrefix(input string) bool {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ var (
|
||||||
{referenceBig("1"), "0x1"},
|
{referenceBig("1"), "0x1"},
|
||||||
{referenceBig("ff"), "0xff"},
|
{referenceBig("ff"), "0xff"},
|
||||||
{referenceBig("112233445566778899aabbccddeeff"), "0x112233445566778899aabbccddeeff"},
|
{referenceBig("112233445566778899aabbccddeeff"), "0x112233445566778899aabbccddeeff"},
|
||||||
|
{referenceBig("80a7f2c1bcc396c00"), "0x80a7f2c1bcc396c00"},
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeUint64Tests = []marshalTest{
|
encodeUint64Tests = []marshalTest{
|
||||||
|
|
|
||||||
|
|
@ -109,13 +109,8 @@ func (b *Big) MarshalJSON() ([]byte, error) {
|
||||||
if nbits == 0 {
|
if nbits == 0 {
|
||||||
return jsonZero, nil
|
return jsonZero, nil
|
||||||
}
|
}
|
||||||
enc := make([]byte, 3, (nbits/8)*2+4)
|
enc := fmt.Sprintf(`"0x%x"`, bigint)
|
||||||
copy(enc, `"0x`)
|
return []byte(enc), nil
|
||||||
for i := len(bigint.Bits()) - 1; i >= 0; i-- {
|
|
||||||
enc = strconv.AppendUint(enc, uint64(bigint.Bits()[i]), 16)
|
|
||||||
}
|
|
||||||
enc = append(enc, '"')
|
|
||||||
return enc, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaler.
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
|
@ -237,7 +232,7 @@ func checkJSON(input []byte) (raw []byte, err error) {
|
||||||
return nil, errNonString
|
return nil, errNonString
|
||||||
}
|
}
|
||||||
if len(input) == 2 {
|
if len(input) == 2 {
|
||||||
return nil, ErrEmptyString
|
return nil, nil // empty strings are allowed
|
||||||
}
|
}
|
||||||
if !bytesHave0xPrefix(input[1:]) {
|
if !bytesHave0xPrefix(input[1:]) {
|
||||||
return nil, ErrMissingPrefix
|
return nil, ErrMissingPrefix
|
||||||
|
|
@ -255,7 +250,7 @@ func checkNumberJSON(input []byte) (raw []byte, err error) {
|
||||||
}
|
}
|
||||||
input = input[1 : len(input)-1]
|
input = input[1 : len(input)-1]
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return nil, ErrEmptyString
|
return nil, nil // empty strings are allowed
|
||||||
}
|
}
|
||||||
if !bytesHave0xPrefix(input) {
|
if !bytesHave0xPrefix(input) {
|
||||||
return nil, ErrMissingPrefix
|
return nil, ErrMissingPrefix
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,13 @@ var unmarshalBytesTests = []unmarshalTest{
|
||||||
{input: "", wantErr: errNonString},
|
{input: "", wantErr: errNonString},
|
||||||
{input: "null", wantErr: errNonString},
|
{input: "null", wantErr: errNonString},
|
||||||
{input: "10", wantErr: errNonString},
|
{input: "10", wantErr: errNonString},
|
||||||
{input: `""`, wantErr: ErrEmptyString},
|
|
||||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||||
{input: `"0x0"`, wantErr: ErrOddLength},
|
{input: `"0x0"`, wantErr: ErrOddLength},
|
||||||
{input: `"0xxx"`, wantErr: ErrSyntax},
|
{input: `"0xxx"`, wantErr: ErrSyntax},
|
||||||
{input: `"0x01zz01"`, wantErr: ErrSyntax},
|
{input: `"0x01zz01"`, wantErr: ErrSyntax},
|
||||||
|
|
||||||
// valid encoding
|
// valid encoding
|
||||||
|
{input: `""`, want: referenceBytes("")},
|
||||||
{input: `"0x"`, want: referenceBytes("")},
|
{input: `"0x"`, want: referenceBytes("")},
|
||||||
{input: `"0x02"`, want: referenceBytes("02")},
|
{input: `"0x02"`, want: referenceBytes("02")},
|
||||||
{input: `"0X02"`, want: referenceBytes("02")},
|
{input: `"0X02"`, want: referenceBytes("02")},
|
||||||
|
|
@ -125,7 +125,6 @@ var unmarshalBigTests = []unmarshalTest{
|
||||||
{input: "", wantErr: errNonString},
|
{input: "", wantErr: errNonString},
|
||||||
{input: "null", wantErr: errNonString},
|
{input: "null", wantErr: errNonString},
|
||||||
{input: "10", wantErr: errNonString},
|
{input: "10", wantErr: errNonString},
|
||||||
{input: `""`, wantErr: ErrEmptyString},
|
|
||||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||||
{input: `"0x"`, wantErr: ErrEmptyNumber},
|
{input: `"0x"`, wantErr: ErrEmptyNumber},
|
||||||
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
||||||
|
|
@ -133,6 +132,7 @@ var unmarshalBigTests = []unmarshalTest{
|
||||||
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
||||||
|
|
||||||
// valid encoding
|
// valid encoding
|
||||||
|
{input: `""`, want: big.NewInt(0)},
|
||||||
{input: `"0x0"`, want: big.NewInt(0)},
|
{input: `"0x0"`, want: big.NewInt(0)},
|
||||||
{input: `"0x2"`, want: big.NewInt(0x2)},
|
{input: `"0x2"`, want: big.NewInt(0x2)},
|
||||||
{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
|
{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
|
||||||
|
|
@ -198,7 +198,6 @@ var unmarshalUint64Tests = []unmarshalTest{
|
||||||
{input: "", wantErr: errNonString},
|
{input: "", wantErr: errNonString},
|
||||||
{input: "null", wantErr: errNonString},
|
{input: "null", wantErr: errNonString},
|
||||||
{input: "10", wantErr: errNonString},
|
{input: "10", wantErr: errNonString},
|
||||||
{input: `""`, wantErr: ErrEmptyString},
|
|
||||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||||
{input: `"0x"`, wantErr: ErrEmptyNumber},
|
{input: `"0x"`, wantErr: ErrEmptyNumber},
|
||||||
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
||||||
|
|
@ -207,6 +206,7 @@ var unmarshalUint64Tests = []unmarshalTest{
|
||||||
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
||||||
|
|
||||||
// valid encoding
|
// valid encoding
|
||||||
|
{input: `""`, want: uint64(0)},
|
||||||
{input: `"0x0"`, want: uint64(0)},
|
{input: `"0x0"`, want: uint64(0)},
|
||||||
{input: `"0x2"`, want: uint64(0x2)},
|
{input: `"0x2"`, want: uint64(0x2)},
|
||||||
{input: `"0x2F2"`, want: uint64(0x2f2)},
|
{input: `"0x2F2"`, want: uint64(0x2f2)},
|
||||||
|
|
|
||||||
|
|
@ -41,24 +41,24 @@ func TestSum(t *testing.T) {
|
||||||
|
|
||||||
func TestDist(t *testing.T) {
|
func TestDist(t *testing.T) {
|
||||||
var vectors = []Vector{
|
var vectors = []Vector{
|
||||||
Vector{big.NewInt(1000), big.NewInt(1234)},
|
{big.NewInt(1000), big.NewInt(1234)},
|
||||||
Vector{big.NewInt(500), big.NewInt(10023)},
|
{big.NewInt(500), big.NewInt(10023)},
|
||||||
Vector{big.NewInt(1034), big.NewInt(1987)},
|
{big.NewInt(1034), big.NewInt(1987)},
|
||||||
Vector{big.NewInt(1034), big.NewInt(1987)},
|
{big.NewInt(1034), big.NewInt(1987)},
|
||||||
Vector{big.NewInt(8983), big.NewInt(1977)},
|
{big.NewInt(8983), big.NewInt(1977)},
|
||||||
Vector{big.NewInt(98382), big.NewInt(1887)},
|
{big.NewInt(98382), big.NewInt(1887)},
|
||||||
Vector{big.NewInt(12398), big.NewInt(1287)},
|
{big.NewInt(12398), big.NewInt(1287)},
|
||||||
Vector{big.NewInt(12398), big.NewInt(1487)},
|
{big.NewInt(12398), big.NewInt(1487)},
|
||||||
Vector{big.NewInt(12398), big.NewInt(1987)},
|
{big.NewInt(12398), big.NewInt(1987)},
|
||||||
Vector{big.NewInt(12398), big.NewInt(128)},
|
{big.NewInt(12398), big.NewInt(128)},
|
||||||
Vector{big.NewInt(12398), big.NewInt(1987)},
|
{big.NewInt(12398), big.NewInt(1987)},
|
||||||
Vector{big.NewInt(1398), big.NewInt(187)},
|
{big.NewInt(1398), big.NewInt(187)},
|
||||||
Vector{big.NewInt(12328), big.NewInt(1927)},
|
{big.NewInt(12328), big.NewInt(1927)},
|
||||||
Vector{big.NewInt(12398), big.NewInt(1987)},
|
{big.NewInt(12398), big.NewInt(1987)},
|
||||||
Vector{big.NewInt(22398), big.NewInt(1287)},
|
{big.NewInt(22398), big.NewInt(1287)},
|
||||||
Vector{big.NewInt(1370), big.NewInt(1981)},
|
{big.NewInt(1370), big.NewInt(1981)},
|
||||||
Vector{big.NewInt(12398), big.NewInt(1957)},
|
{big.NewInt(12398), big.NewInt(1957)},
|
||||||
Vector{big.NewInt(42198), big.NewInt(1987)},
|
{big.NewInt(42198), big.NewInt(1987)},
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorsBy(GasSort).Sort(vectors)
|
VectorsBy(GasSort).Sort(vectors)
|
||||||
|
|
|
||||||
|
|
@ -76,9 +76,9 @@ func compressChunk(dat []byte) (ret []byte, n int) {
|
||||||
}
|
}
|
||||||
return []byte{token, byte(j + 2)}, j
|
return []byte{token, byte(j + 2)}, j
|
||||||
case len(dat) >= 32:
|
case len(dat) >= 32:
|
||||||
if dat[0] == empty[0] && bytes.Compare(dat[:32], empty) == 0 {
|
if dat[0] == empty[0] && bytes.Equal(dat[:32], empty) {
|
||||||
return []byte{token, emptyShaToken}, 32
|
return []byte{token, emptyShaToken}, 32
|
||||||
} else if dat[0] == emptyList[0] && bytes.Compare(dat[:32], emptyList) == 0 {
|
} else if dat[0] == emptyList[0] && bytes.Equal(dat[:32], emptyList) {
|
||||||
return []byte{token, emptyListShaToken}, 32
|
return []byte{token, emptyListShaToken}, 32
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func newBridge(client *rpc.Client, prompter UserPrompter, printer io.Writer) *br
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAccount is a wrapper around the personal.newAccount RPC method that uses a
|
// NewAccount is a wrapper around the personal.newAccount RPC method that uses a
|
||||||
// non-echoing password prompt to aquire the passphrase and executes the original
|
// non-echoing password prompt to acquire the passphrase and executes the original
|
||||||
// RPC method (saved in jeth.newAccount) with it to actually execute the RPC call.
|
// RPC method (saved in jeth.newAccount) with it to actually execute the RPC call.
|
||||||
func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
||||||
var (
|
var (
|
||||||
|
|
@ -75,7 +75,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
||||||
default:
|
default:
|
||||||
throwJSException("expected 0 or 1 string argument")
|
throwJSException("expected 0 or 1 string argument")
|
||||||
}
|
}
|
||||||
// Password aquired, execute the call and return
|
// Password acquired, execute the call and return
|
||||||
ret, err := call.Otto.Call("jeth.newAccount", nil, password)
|
ret, err := call.Otto.Call("jeth.newAccount", nil, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throwJSException(err.Error())
|
throwJSException(err.Error())
|
||||||
|
|
@ -84,7 +84,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnlockAccount is a wrapper around the personal.unlockAccount RPC method that
|
// UnlockAccount is a wrapper around the personal.unlockAccount RPC method that
|
||||||
// uses a non-echoing password prompt to aquire the passphrase and executes the
|
// uses a non-echoing password prompt to acquire the passphrase and executes the
|
||||||
// original RPC method (saved in jeth.unlockAccount) with it to actually execute
|
// original RPC method (saved in jeth.unlockAccount) with it to actually execute
|
||||||
// the RPC call.
|
// the RPC call.
|
||||||
func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
|
func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
|
||||||
|
|
@ -127,7 +127,7 @@ func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password
|
// Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password
|
||||||
// prompt to aquire the passphrase and executes the original RPC method (saved in
|
// prompt to acquire the passphrase and executes the original RPC method (saved in
|
||||||
// jeth.sign) with it to actually execute the RPC call.
|
// jeth.sign) with it to actually execute the RPC call.
|
||||||
func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) {
|
func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) {
|
||||||
var (
|
var (
|
||||||
|
|
@ -270,18 +270,15 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
|
||||||
} else {
|
} else {
|
||||||
resultVal, err := JSON.Call("parse", string(result))
|
resultVal, err := JSON.Call("parse", string(result))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object()
|
setError(resp, -32603, err.Error())
|
||||||
} else {
|
} else {
|
||||||
resp.Set("result", resultVal)
|
resp.Set("result", resultVal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case rpc.Error:
|
case rpc.Error:
|
||||||
resp.Set("error", map[string]interface{}{
|
setError(resp, err.ErrorCode(), err.Error())
|
||||||
"code": err.ErrorCode(),
|
|
||||||
"message": err.Error(),
|
|
||||||
})
|
|
||||||
default:
|
default:
|
||||||
resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object()
|
setError(resp, -32603, err.Error())
|
||||||
}
|
}
|
||||||
resps.Call("push", resp)
|
resps.Call("push", resp)
|
||||||
}
|
}
|
||||||
|
|
@ -300,12 +297,8 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
func newErrorResponse(call otto.FunctionCall, code int, msg string, id interface{}) otto.Value {
|
func setError(resp *otto.Object, code int, msg string) {
|
||||||
// Bundle the error into a JSON RPC call response
|
resp.Set("error", map[string]interface{}{"code": code, "message": msg})
|
||||||
m := map[string]interface{}{"version": "2.0", "id": id, "error": map[string]interface{}{"code": code, msg: msg}}
|
|
||||||
res, _ := json.Marshal(m)
|
|
||||||
val, _ := call.Otto.Run("(" + string(res) + ")")
|
|
||||||
return val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// throwJSException panics on an otto.Value. The Otto VM will recover from the
|
// throwJSException panics on an otto.Value. The Otto VM will recover from the
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
passwordRegexp = regexp.MustCompile("personal.[nus]")
|
passwordRegexp = regexp.MustCompile(`personal.[nus]`)
|
||||||
onlyWhitespace = regexp.MustCompile("^\\s*$")
|
onlyWhitespace = regexp.MustCompile(`^\s*$`)
|
||||||
exit = regexp.MustCompile("^\\s*exit\\s*;*\\s*$")
|
exit = regexp.MustCompile(`^\s*exit\s*;*\s*$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// HistoryFile is the file within the data directory to store input scrollback.
|
// HistoryFile is the file within the data directory to store input scrollback.
|
||||||
|
|
@ -226,8 +226,8 @@ func (c *Console) AutoCompleteInput(line string, pos int) (string, []string, str
|
||||||
}
|
}
|
||||||
// Chunck data to relevant part for autocompletion
|
// Chunck data to relevant part for autocompletion
|
||||||
// E.g. in case of nested lines eth.getBalance(eth.coinb<tab><tab>
|
// E.g. in case of nested lines eth.getBalance(eth.coinb<tab><tab>
|
||||||
start := 0
|
start := pos - 1
|
||||||
for start = pos - 1; start > 0; start-- {
|
for ; start > 0; start-- {
|
||||||
// Skip all methods and namespaces (i.e. including te dot)
|
// Skip all methods and namespaces (i.e. including te dot)
|
||||||
if line[start] == '.' || (line[start] >= 'a' && line[start] <= 'z') || (line[start] >= 'A' && line[start] <= 'Z') {
|
if line[start] == '.' || (line[start] >= 'a' && line[start] <= 'z') || (line[start] >= 'A' && line[start] <= 'Z') {
|
||||||
continue
|
continue
|
||||||
|
|
@ -275,10 +275,7 @@ func (c *Console) Evaluate(statement string) error {
|
||||||
fmt.Fprintf(c.printer, "[native] error: %v\n", r)
|
fmt.Fprintf(c.printer, "[native] error: %v\n", r)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err := c.jsre.Evaluate(statement, c.printer); err != nil {
|
return c.jsre.Evaluate(statement, c.printer)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interactive starts an interactive user session, where input is propted from
|
// Interactive starts an interactive user session, where input is propted from
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ type UserPrompter interface {
|
||||||
PromptConfirm(prompt string) (bool, error)
|
PromptConfirm(prompt string) (bool, error)
|
||||||
|
|
||||||
// SetHistory sets the the input scrollback history that the prompter will allow
|
// SetHistory sets the the input scrollback history that the prompter will allow
|
||||||
// the user to scoll back to.
|
// the user to scroll back to.
|
||||||
SetHistory(history []string)
|
SetHistory(history []string)
|
||||||
|
|
||||||
// AppendHistory appends an entry to the scrollback history. It should be called
|
// AppendHistory appends an entry to the scrollback history. It should be called
|
||||||
|
|
@ -147,7 +147,7 @@ func (p *terminalPrompter) PromptConfirm(prompt string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHistory sets the the input scrollback history that the prompter will allow
|
// SetHistory sets the the input scrollback history that the prompter will allow
|
||||||
// the user to scoll back to.
|
// the user to scroll back to.
|
||||||
func (p *terminalPrompter) SetHistory(history []string) {
|
func (p *terminalPrompter) SetHistory(history []string) {
|
||||||
p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n")))
|
p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n")))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *
|
||||||
return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
|
return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
|
||||||
}
|
}
|
||||||
if self.balance.Cmp(amount) < 0 {
|
if self.balance.Cmp(amount) < 0 {
|
||||||
err = fmt.Errorf("insufficent funds to issue cheque for amount: %v. balance: %v", amount, self.balance)
|
err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, self.balance)
|
||||||
} else {
|
} else {
|
||||||
var sig []byte
|
var sig []byte
|
||||||
sent, found := self.sent[beneficiary]
|
sent, found := self.sent[beneficiary]
|
||||||
|
|
@ -277,7 +277,7 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto deposit if threshold is set and balance is less then threshold
|
// auto deposit if threshold is set and balance is less then threshold
|
||||||
// note this is called even if issueing cheque fails
|
// note this is called even if issuing cheque fails
|
||||||
// so we reattempt depositing
|
// so we reattempt depositing
|
||||||
if self.threshold != nil {
|
if self.threshold != nil {
|
||||||
if self.balance.Cmp(self.threshold) < 0 {
|
if self.balance.Cmp(self.threshold) < 0 {
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ func TestIssueAndReceive(t *testing.T) {
|
||||||
}
|
}
|
||||||
chbook.sent[addr1] = new(big.Int).SetUint64(42)
|
chbook.sent[addr1] = new(big.Int).SetUint64(42)
|
||||||
amount := common.Big1
|
amount := common.Big1
|
||||||
ch, err := chbook.Issue(addr1, amount)
|
|
||||||
if err == nil {
|
if _, err = chbook.Issue(addr1, amount); err == nil {
|
||||||
t.Fatalf("expected insufficient funds error, got none")
|
t.Fatalf("expected insufficient funds error, got none")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +83,7 @@ func TestIssueAndReceive(t *testing.T) {
|
||||||
t.Fatalf("expected: %v, got %v", "0", chbook.Balance())
|
t.Fatalf("expected: %v, got %v", "0", chbook.Balance())
|
||||||
}
|
}
|
||||||
|
|
||||||
ch, err = chbook.Issue(addr1, amount)
|
ch, err := chbook.Issue(addr1, amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -128,8 +128,8 @@ func TestCheckbookFile(t *testing.T) {
|
||||||
t.Errorf("expected: %v, got %v", "0", chbook.Balance())
|
t.Errorf("expected: %v, got %v", "0", chbook.Balance())
|
||||||
}
|
}
|
||||||
|
|
||||||
ch, err := chbook.Issue(addr1, common.Big1)
|
var ch *Cheque
|
||||||
if err != nil {
|
if ch, err = chbook.Issue(addr1, common.Big1); err != nil {
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
}
|
}
|
||||||
if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 {
|
if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 {
|
||||||
|
|
@ -155,7 +155,7 @@ func TestVerifyErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json")
|
path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json")
|
||||||
contr1, err := deploy(key1, common.Big2, backend)
|
contr1, _ := deploy(key1, common.Big2, backend)
|
||||||
chbook1, err := NewChequebook(path1, contr1, key1, backend)
|
chbook1, err := NewChequebook(path1, contr1, key1, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected no error, got %v", err)
|
t.Errorf("expected no error, got %v", err)
|
||||||
|
|
@ -223,7 +223,8 @@ func TestVerifyErrors(t *testing.T) {
|
||||||
func TestDeposit(t *testing.T) {
|
func TestDeposit(t *testing.T) {
|
||||||
path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
|
path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
|
||||||
backend := newTestBackend()
|
backend := newTestBackend()
|
||||||
contr0, err := deploy(key0, new(big.Int), backend)
|
contr0, _ := deploy(key0, new(big.Int), backend)
|
||||||
|
|
||||||
chbook, err := NewChequebook(path0, contr0, key0, backend)
|
chbook, err := NewChequebook(path0, contr0, key0, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected no error, got %v", err)
|
t.Errorf("expected no error, got %v", err)
|
||||||
|
|
@ -361,7 +362,8 @@ func TestDeposit(t *testing.T) {
|
||||||
func TestCash(t *testing.T) {
|
func TestCash(t *testing.T) {
|
||||||
path := filepath.Join(os.TempDir(), "chequebook-test.json")
|
path := filepath.Join(os.TempDir(), "chequebook-test.json")
|
||||||
backend := newTestBackend()
|
backend := newTestBackend()
|
||||||
contr0, err := deploy(key0, common.Big2, backend)
|
contr0, _ := deploy(key0, common.Big2, backend)
|
||||||
|
|
||||||
chbook, err := NewChequebook(path, contr0, key0, backend)
|
chbook, err := NewChequebook(path, contr0, key0, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected no error, got %v", err)
|
t.Errorf("expected no error, got %v", err)
|
||||||
|
|
@ -380,11 +382,12 @@ func TestCash(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// cashing latest cheque
|
// cashing latest cheque
|
||||||
_, err = chbox.Receive(ch)
|
if _, err = chbox.Receive(ch); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
}
|
}
|
||||||
_, err = ch.Cash(chbook.session)
|
if _, err = ch.Cash(chbook.session); err != nil {
|
||||||
|
t.Fatal("Cash failed:", err)
|
||||||
|
}
|
||||||
backend.Commit()
|
backend.Commit()
|
||||||
|
|
||||||
chbook.balance = new(big.Int).Set(common.Big3)
|
chbook.balance = new(big.Int).Set(common.Big3)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
name = "my name on ENS"
|
name = "my name on ENS"
|
||||||
hash = crypto.Sha3Hash([]byte("my content"))
|
hash = crypto.Keccak256Hash([]byte("my content"))
|
||||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ contract ReleaseOracle {
|
||||||
}
|
}
|
||||||
|
|
||||||
// signers is an accessor method to retrieve all te signers (public accessor
|
// signers is an accessor method to retrieve all te signers (public accessor
|
||||||
// generates an indexed one, not a retreive-all version).
|
// generates an indexed one, not a retrieve-all version).
|
||||||
function signers() constant returns(address[]) {
|
function signers() constant returns(address[]) {
|
||||||
return voters;
|
return voters;
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +178,7 @@ contract ReleaseOracle {
|
||||||
voters[i] = voters[voters.length - 1];
|
voters[i] = voters[voters.length - 1];
|
||||||
voters.length--;
|
voters.length--;
|
||||||
|
|
||||||
delete verProp; // Nuke any version proposal (no suprise releases!)
|
delete verProp; // Nuke any version proposal (no surprise releases!)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
|
||||||
toaddr := common.Address{}
|
toaddr := common.Address{}
|
||||||
data := make([]byte, nbytes)
|
data := make([]byte, nbytes)
|
||||||
gas := IntrinsicGas(data, false, false)
|
gas := IntrinsicGas(data, false, false)
|
||||||
tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(types.HomesteadSigner{}, benchRootKey)
|
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from])
|
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from])
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
from = to
|
from = to
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow/ezp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func testChainConfig() *params.ChainConfig {
|
func testChainConfig() *params.ChainConfig {
|
||||||
|
|
@ -49,20 +47,19 @@ func proc() (Validator, *BlockChain) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNumber(t *testing.T) {
|
func TestNumber(t *testing.T) {
|
||||||
pow := ezp.New()
|
|
||||||
_, chain := proc()
|
_, chain := proc()
|
||||||
|
|
||||||
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
||||||
cfg := testChainConfig()
|
cfg := testChainConfig()
|
||||||
header := makeHeader(cfg, chain.Genesis(), statedb)
|
header := makeHeader(cfg, chain.Genesis(), statedb)
|
||||||
header.Number = big.NewInt(3)
|
header.Number = big.NewInt(3)
|
||||||
err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
|
err := ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false)
|
||||||
if err != BlockNumberErr {
|
if err != BlockNumberErr {
|
||||||
t.Errorf("expected block number error, got %q", err)
|
t.Errorf("expected block number error, got %q", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
header = makeHeader(cfg, chain.Genesis(), statedb)
|
header = makeHeader(cfg, chain.Genesis(), statedb)
|
||||||
err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
|
err = ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false)
|
||||||
if err == BlockNumberErr {
|
if err == BlockNumberErr {
|
||||||
t.Errorf("didn't expect block number error")
|
t.Errorf("didn't expect block number error")
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +74,7 @@ func TestPutReceipt(t *testing.T) {
|
||||||
hash[0] = 2
|
hash[0] = 2
|
||||||
|
|
||||||
receipt := new(types.Receipt)
|
receipt := new(types.Receipt)
|
||||||
receipt.Logs = vm.Logs{&vm.Log{
|
receipt.Logs = []*types.Log{{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Topics: []common.Hash{hash},
|
Topics: []common.Hash{hash},
|
||||||
Data: []byte("hi"),
|
Data: []byte("hi"),
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
@ -46,9 +47,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
chainlogger = logger.NewLogger("CHAIN")
|
|
||||||
jsonlogger = logger.NewJsonLogger()
|
|
||||||
|
|
||||||
blockInsertTimer = metrics.NewTimer("chain/inserts")
|
blockInsertTimer = metrics.NewTimer("chain/inserts")
|
||||||
|
|
||||||
ErrNoGenesis = errors.New("Genesis not found in chain")
|
ErrNoGenesis = errors.New("Genesis not found in chain")
|
||||||
|
|
@ -150,7 +148,7 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.P
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
|
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
|
||||||
for hash, _ := range BadHashes {
|
for hash := range BadHashes {
|
||||||
if header := bc.GetHeaderByHash(hash); header != nil {
|
if header := bc.GetHeaderByHash(hash); header != nil {
|
||||||
// get the canonical block corresponding to the offending header's number
|
// get the canonical block corresponding to the offending header's number
|
||||||
headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
|
headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
|
||||||
|
|
@ -402,10 +400,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) {
|
||||||
|
|
||||||
// Export writes the active chain to the given writer.
|
// Export writes the active chain to the given writer.
|
||||||
func (self *BlockChain) Export(w io.Writer) error {
|
func (self *BlockChain) Export(w io.Writer) error {
|
||||||
if err := self.ExportN(w, uint64(0), self.currentBlock.NumberU64()); err != nil {
|
return self.ExportN(w, uint64(0), self.currentBlock.NumberU64())
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportN writes a subset of the active chain to the given writer.
|
// ExportN writes a subset of the active chain to the given writer.
|
||||||
|
|
@ -805,7 +800,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
|
||||||
if stats.ignored > 0 {
|
if stats.ignored > 0 {
|
||||||
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
|
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
|
||||||
}
|
}
|
||||||
glog.V(logger.Info).Infof("imported %d receipts in %9v. #%d [%x… / %x…]%s", stats.processed, common.PrettyDuration(time.Since(start)), last.Number(), first.Hash().Bytes()[:4], last.Hash().Bytes()[:4], ignored)
|
glog.V(logger.Info).Infof("imported %4d receipts in %9v. #%d [%x… / %x…]%s", stats.processed, common.PrettyDuration(time.Since(start)), last.Number(), first.Hash().Bytes()[:4], last.Hash().Bytes()[:4], ignored)
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
@ -881,9 +876,9 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
// faster than direct delivery and requires much less mutex
|
// faster than direct delivery and requires much less mutex
|
||||||
// acquiring.
|
// acquiring.
|
||||||
var (
|
var (
|
||||||
stats = insertStats{startTime: time.Now()}
|
stats = insertStats{startTime: mclock.Now()}
|
||||||
events = make([]interface{}, 0, len(chain))
|
events = make([]interface{}, 0, len(chain))
|
||||||
coalescedLogs vm.Logs
|
coalescedLogs []*types.Log
|
||||||
nonceChecked = make([]bool, len(chain))
|
nonceChecked = make([]bool, len(chain))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1037,7 +1032,7 @@ type insertStats struct {
|
||||||
queued, processed, ignored int
|
queued, processed, ignored int
|
||||||
usedGas uint64
|
usedGas uint64
|
||||||
lastIndex int
|
lastIndex int
|
||||||
startTime time.Time
|
startTime mclock.AbsTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// statsReportLimit is the time limit during import after which we always print
|
// statsReportLimit is the time limit during import after which we always print
|
||||||
|
|
@ -1049,28 +1044,24 @@ const statsReportLimit = 8 * time.Second
|
||||||
func (st *insertStats) report(chain []*types.Block, index int) {
|
func (st *insertStats) report(chain []*types.Block, index int) {
|
||||||
// Fetch the timings for the batch
|
// Fetch the timings for the batch
|
||||||
var (
|
var (
|
||||||
now = time.Now()
|
now = mclock.Now()
|
||||||
elapsed = now.Sub(st.startTime)
|
elapsed = time.Duration(now) - time.Duration(st.startTime)
|
||||||
)
|
)
|
||||||
if elapsed == 0 { // Yes Windows, I'm looking at you
|
|
||||||
elapsed = 1
|
|
||||||
}
|
|
||||||
// If we're at the last block of the batch or report period reached, log
|
// If we're at the last block of the batch or report period reached, log
|
||||||
if index == len(chain)-1 || elapsed >= statsReportLimit {
|
if index == len(chain)-1 || elapsed >= statsReportLimit {
|
||||||
start, end := chain[st.lastIndex], chain[index]
|
start, end := chain[st.lastIndex], chain[index]
|
||||||
txcount := countTransactions(chain[st.lastIndex : index+1])
|
txcount := countTransactions(chain[st.lastIndex : index+1])
|
||||||
|
|
||||||
extra := ""
|
var hashes, extra string
|
||||||
if st.queued > 0 || st.ignored > 0 {
|
if st.queued > 0 || st.ignored > 0 {
|
||||||
extra = fmt.Sprintf(" (%d queued %d ignored)", st.queued, st.ignored)
|
extra = fmt.Sprintf(" (%d queued %d ignored)", st.queued, st.ignored)
|
||||||
}
|
}
|
||||||
hashes := ""
|
|
||||||
if st.processed > 1 {
|
if st.processed > 1 {
|
||||||
hashes = fmt.Sprintf("%x… / %x…", start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
|
hashes = fmt.Sprintf("%x… / %x…", start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
|
||||||
} else {
|
} else {
|
||||||
hashes = fmt.Sprintf("%x…", end.Hash().Bytes()[:4])
|
hashes = fmt.Sprintf("%x…", end.Hash().Bytes()[:4])
|
||||||
}
|
}
|
||||||
glog.Infof("imported %d blocks, %5d txs (%7.3f Mg) in %9v (%6.3f Mg/s). #%v [%s]%s", st.processed, txcount, float64(st.usedGas)/1000000, common.PrettyDuration(elapsed), float64(st.usedGas)*1000/float64(elapsed), end.Number(), hashes, extra)
|
glog.Infof("imported %4d blocks, %5d txs (%7.3f Mg) in %9v (%6.3f Mg/s). #%v [%s]%s", st.processed, txcount, float64(st.usedGas)/1000000, common.PrettyDuration(elapsed), float64(st.usedGas)*1000/float64(elapsed), end.Number(), hashes, extra)
|
||||||
|
|
||||||
*st = insertStats{startTime: now, lastIndex: index}
|
*st = insertStats{startTime: now, lastIndex: index}
|
||||||
}
|
}
|
||||||
|
|
@ -1094,7 +1085,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||||
oldStart = oldBlock
|
oldStart = oldBlock
|
||||||
newStart = newBlock
|
newStart = newBlock
|
||||||
deletedTxs types.Transactions
|
deletedTxs types.Transactions
|
||||||
deletedLogs vm.Logs
|
deletedLogs []*types.Log
|
||||||
// collectLogs collects the logs that were generated during the
|
// collectLogs collects the logs that were generated during the
|
||||||
// processing of the block that corresponds with the given hash.
|
// processing of the block that corresponds with the given hash.
|
||||||
// These logs are later announced as deleted.
|
// These logs are later announced as deleted.
|
||||||
|
|
@ -1210,7 +1201,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||||
|
|
||||||
// postChainEvents iterates over the events generated by a chain insertion and
|
// postChainEvents iterates over the events generated by a chain insertion and
|
||||||
// posts them into the event mux.
|
// posts them into the event mux.
|
||||||
func (self *BlockChain) postChainEvents(events []interface{}, logs vm.Logs) {
|
func (self *BlockChain) postChainEvents(events []interface{}, logs []*types.Log) {
|
||||||
// post event logs for further processing
|
// post event logs for further processing
|
||||||
self.eventMux.Post(logs)
|
self.eventMux.Post(logs)
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
|
|
|
||||||
|
|
@ -435,7 +435,7 @@ func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return n
|
||||||
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
|
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
|
func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {
|
||||||
return nil, nil, new(big.Int), nil
|
return nil, nil, new(big.Int), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -719,7 +719,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
||||||
if i%3 == 2 {
|
if i%3 == 2 {
|
||||||
for j := 0; j < i%4+1; j++ {
|
for j := 0; j < i%4+1; j++ {
|
||||||
tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key)
|
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -883,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
// Create two transactions shared between the chains:
|
// Create two transactions shared between the chains:
|
||||||
// - postponed: transaction included at a later block in the forked chain
|
// - postponed: transaction included at a later block in the forked chain
|
||||||
// - swapped: transaction included at the same block number in the forked chain
|
// - swapped: transaction included at the same block number in the forked chain
|
||||||
postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
|
||||||
swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
|
||||||
|
|
||||||
// Create two transactions that will be dropped by the forked chain:
|
// Create two transactions that will be dropped by the forked chain:
|
||||||
// - pastDrop: transaction dropped retroactively from a past block
|
// - pastDrop: transaction dropped retroactively from a past block
|
||||||
|
|
@ -900,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
|
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
|
||||||
|
|
||||||
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
|
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
|
||||||
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
|
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
|
freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
|
||||||
|
|
||||||
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
|
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
|
||||||
gen.AddTx(swapped) // This transaction will be swapped out at the exact height
|
gen.AddTx(swapped) // This transaction will be swapped out at the exact height
|
||||||
|
|
@ -925,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
|
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
|
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
|
||||||
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
|
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
|
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
|
||||||
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
|
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
|
||||||
|
|
||||||
freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
|
freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
|
||||||
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
|
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
|
futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
|
||||||
gen.AddTx(futureAdd) // This transaction will be added after a full reorg
|
gen.AddTx(futureAdd) // This transaction will be added after a full reorg
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -995,7 +995,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
subs := evmux.Subscribe(RemovedLogsEvent{})
|
subs := evmux.Subscribe(RemovedLogsEvent{})
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1035,7 +1035,7 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
|
replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
|
||||||
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
|
||||||
if i == 2 {
|
if i == 2 {
|
||||||
gen.OffsetTime(-1)
|
gen.OffsetTime(-1)
|
||||||
}
|
}
|
||||||
|
|
@ -1107,7 +1107,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
|
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
for i, _ := range chain {
|
for i := range chain {
|
||||||
go func(block *types.Block) {
|
go func(block *types.Block) {
|
||||||
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
||||||
for {
|
for {
|
||||||
|
|
@ -1152,7 +1152,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
err error
|
err error
|
||||||
basicTx = func(signer types.Signer) (*types.Transaction, error) {
|
basicTx = func(signer types.Signer) (*types.Transaction, error) {
|
||||||
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
|
return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
switch i {
|
switch i {
|
||||||
|
|
@ -1215,7 +1215,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
err error
|
err error
|
||||||
basicTx = func(signer types.Signer) (*types.Transaction, error) {
|
basicTx = func(signer types.Signer) (*types.Transaction, error) {
|
||||||
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
|
return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
switch i {
|
switch i {
|
||||||
|
|
@ -1260,11 +1260,11 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
)
|
)
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
|
tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
|
||||||
case 1:
|
case 1:
|
||||||
tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
|
tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
|
||||||
case 2:
|
case 2:
|
||||||
tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
|
tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
b.SetCoinbase(common.Address{})
|
b.SetCoinbase(common.Address{})
|
||||||
}
|
}
|
||||||
b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
|
b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
|
||||||
receipt, _, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
|
receipt, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,13 +55,13 @@ func ExampleGenerateChain() {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, addr1 sends addr2 some ether.
|
// In block 1, addr1 sends addr2 some ether.
|
||||||
tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, addr1 sends some more ether to addr2.
|
// In block 2, addr1 sends some more ether to addr2.
|
||||||
// addr2 passes it on to addr3.
|
// addr2 passes it on to addr3.
|
||||||
tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
|
||||||
tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
|
tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
|
||||||
gen.AddTx(tx1)
|
gen.AddTx(tx1)
|
||||||
gen.AddTx(tx2)
|
gen.AddTx(tx2)
|
||||||
case 2:
|
case 2:
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,11 @@ func ValidateDAOHeaderExtraData(config *params.ChainConfig, header *types.Header
|
||||||
}
|
}
|
||||||
// Depending whether we support or oppose the fork, validate the extra-data contents
|
// Depending whether we support or oppose the fork, validate the extra-data contents
|
||||||
if config.DAOForkSupport {
|
if config.DAOForkSupport {
|
||||||
if bytes.Compare(header.Extra, params.DAOForkBlockExtra) != 0 {
|
if !bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
||||||
return ValidationError("DAO pro-fork bad block extra-data: 0x%x", header.Extra)
|
return ValidationError("DAO pro-fork bad block extra-data: 0x%x", header.Extra)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if bytes.Compare(header.Extra, params.DAOForkBlockExtra) == 0 {
|
if bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
||||||
return ValidationError("DAO no-fork bad block extra-data: 0x%x", header.Extra)
|
return ValidationError("DAO no-fork bad block extra-data: 0x%x", header.Extra)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -63,6 +64,8 @@ var (
|
||||||
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
|
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
|
||||||
|
|
||||||
ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
|
ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
|
||||||
|
|
||||||
|
mipmapBloomMu sync.Mutex // protect against race condition when updating mipmap blooms
|
||||||
)
|
)
|
||||||
|
|
||||||
// encodeBlockNumber encodes a block number as big endian uint64
|
// encodeBlockNumber encodes a block number as big endian uint64
|
||||||
|
|
@ -564,6 +567,9 @@ func mipmapKey(num, level uint64) []byte {
|
||||||
// WriteMapmapBloom writes each address included in the receipts' logs to the
|
// WriteMapmapBloom writes each address included in the receipts' logs to the
|
||||||
// MIP bloom bin.
|
// MIP bloom bin.
|
||||||
func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts) error {
|
func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts) error {
|
||||||
|
mipmapBloomMu.Lock()
|
||||||
|
defer mipmapBloomMu.Unlock()
|
||||||
|
|
||||||
batch := db.NewBatch()
|
batch := db.NewBatch()
|
||||||
for _, level := range MIPMapLevels {
|
for _, level := range MIPMapLevels {
|
||||||
key := mipmapKey(number, level)
|
key := mipmapKey(number, level)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
|
@ -393,9 +392,9 @@ func TestReceiptStorage(t *testing.T) {
|
||||||
receipt1 := &types.Receipt{
|
receipt1 := &types.Receipt{
|
||||||
PostState: []byte{0x01},
|
PostState: []byte{0x01},
|
||||||
CumulativeGasUsed: big.NewInt(1),
|
CumulativeGasUsed: big.NewInt(1),
|
||||||
Logs: vm.Logs{
|
Logs: []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x11})},
|
{Address: common.BytesToAddress([]byte{0x11})},
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
||||||
},
|
},
|
||||||
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
|
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
|
||||||
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
||||||
|
|
@ -404,9 +403,9 @@ func TestReceiptStorage(t *testing.T) {
|
||||||
receipt2 := &types.Receipt{
|
receipt2 := &types.Receipt{
|
||||||
PostState: []byte{0x02},
|
PostState: []byte{0x02},
|
||||||
CumulativeGasUsed: big.NewInt(2),
|
CumulativeGasUsed: big.NewInt(2),
|
||||||
Logs: vm.Logs{
|
Logs: []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x22})},
|
{Address: common.BytesToAddress([]byte{0x22})},
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
||||||
},
|
},
|
||||||
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
|
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
|
||||||
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
||||||
|
|
@ -431,7 +430,7 @@ func TestReceiptStorage(t *testing.T) {
|
||||||
rlpHave, _ := rlp.EncodeToBytes(r)
|
rlpHave, _ := rlp.EncodeToBytes(r)
|
||||||
rlpWant, _ := rlp.EncodeToBytes(receipt)
|
rlpWant, _ := rlp.EncodeToBytes(receipt)
|
||||||
|
|
||||||
if bytes.Compare(rlpHave, rlpWant) != 0 {
|
if !bytes.Equal(rlpHave, rlpWant) {
|
||||||
t.Fatalf("receipt #%d [%x]: receipt mismatch: have %v, want %v", i, receipt.TxHash, r, receipt)
|
t.Fatalf("receipt #%d [%x]: receipt mismatch: have %v, want %v", i, receipt.TxHash, r, receipt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -452,9 +451,9 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||||
receipt1 := &types.Receipt{
|
receipt1 := &types.Receipt{
|
||||||
PostState: []byte{0x01},
|
PostState: []byte{0x01},
|
||||||
CumulativeGasUsed: big.NewInt(1),
|
CumulativeGasUsed: big.NewInt(1),
|
||||||
Logs: vm.Logs{
|
Logs: []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x11})},
|
{Address: common.BytesToAddress([]byte{0x11})},
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
||||||
},
|
},
|
||||||
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
|
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
|
||||||
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
||||||
|
|
@ -463,9 +462,9 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||||
receipt2 := &types.Receipt{
|
receipt2 := &types.Receipt{
|
||||||
PostState: []byte{0x02},
|
PostState: []byte{0x02},
|
||||||
CumulativeGasUsed: big.NewInt(2),
|
CumulativeGasUsed: big.NewInt(2),
|
||||||
Logs: vm.Logs{
|
Logs: []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x22})},
|
{Address: common.BytesToAddress([]byte{0x22})},
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
||||||
},
|
},
|
||||||
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
|
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
|
||||||
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
||||||
|
|
@ -489,7 +488,7 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||||
rlpHave, _ := rlp.EncodeToBytes(rs[i])
|
rlpHave, _ := rlp.EncodeToBytes(rs[i])
|
||||||
rlpWant, _ := rlp.EncodeToBytes(receipts[i])
|
rlpWant, _ := rlp.EncodeToBytes(receipts[i])
|
||||||
|
|
||||||
if bytes.Compare(rlpHave, rlpWant) != 0 {
|
if !bytes.Equal(rlpHave, rlpWant) {
|
||||||
t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i])
|
t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -505,14 +504,14 @@ func TestMipmapBloom(t *testing.T) {
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
|
|
||||||
receipt1 := new(types.Receipt)
|
receipt1 := new(types.Receipt)
|
||||||
receipt1.Logs = vm.Logs{
|
receipt1.Logs = []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte("test"))},
|
{Address: common.BytesToAddress([]byte("test"))},
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte("address"))},
|
{Address: common.BytesToAddress([]byte("address"))},
|
||||||
}
|
}
|
||||||
receipt2 := new(types.Receipt)
|
receipt2 := new(types.Receipt)
|
||||||
receipt2.Logs = vm.Logs{
|
receipt2.Logs = []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte("test"))},
|
{Address: common.BytesToAddress([]byte("test"))},
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte("address1"))},
|
{Address: common.BytesToAddress([]byte("address1"))},
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteMipmapBloom(db, 1, types.Receipts{receipt1})
|
WriteMipmapBloom(db, 1, types.Receipts{receipt1})
|
||||||
|
|
@ -528,14 +527,14 @@ func TestMipmapBloom(t *testing.T) {
|
||||||
// reset
|
// reset
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
receipt := new(types.Receipt)
|
receipt := new(types.Receipt)
|
||||||
receipt.Logs = vm.Logs{
|
receipt.Logs = []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte("test"))},
|
{Address: common.BytesToAddress([]byte("test"))},
|
||||||
}
|
}
|
||||||
WriteMipmapBloom(db, 999, types.Receipts{receipt1})
|
WriteMipmapBloom(db, 999, types.Receipts{receipt1})
|
||||||
|
|
||||||
receipt = new(types.Receipt)
|
receipt = new(types.Receipt)
|
||||||
receipt.Logs = vm.Logs{
|
receipt.Logs = []*types.Log{
|
||||||
&vm.Log{Address: common.BytesToAddress([]byte("test 1"))},
|
{Address: common.BytesToAddress([]byte("test 1"))},
|
||||||
}
|
}
|
||||||
WriteMipmapBloom(db, 1000, types.Receipts{receipt})
|
WriteMipmapBloom(db, 1000, types.Receipts{receipt})
|
||||||
|
|
||||||
|
|
@ -568,17 +567,12 @@ func TestMipmapChain(t *testing.T) {
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, new(big.Int))
|
||||||
receipt.Logs = vm.Logs{
|
receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}}
|
||||||
&vm.Log{
|
|
||||||
Address: addr,
|
|
||||||
Topics: []common.Hash{hash1},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
receipts = types.Receipts{receipt}
|
receipts = types.Receipts{receipt}
|
||||||
case 1000:
|
case 1000:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, new(big.Int))
|
||||||
receipt.Logs = vm.Logs{&vm.Log{Address: addr2}}
|
receipt.Logs = []*types.Log{{Address: addr2}}
|
||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
receipts = types.Receipts{receipt}
|
receipts = types.Receipts{receipt}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -21,7 +21,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TxPreEvent is posted when a transaction enters the transaction pool.
|
// TxPreEvent is posted when a transaction enters the transaction pool.
|
||||||
|
|
@ -32,7 +31,7 @@ type TxPostEvent struct{ Tx *types.Transaction }
|
||||||
|
|
||||||
// PendingLogsEvent is posted pre mining and notifies of pending logs.
|
// PendingLogsEvent is posted pre mining and notifies of pending logs.
|
||||||
type PendingLogsEvent struct {
|
type PendingLogsEvent struct {
|
||||||
Logs vm.Logs
|
Logs []*types.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
// PendingStateEvent is posted pre mining and notifies of pending state changes.
|
// PendingStateEvent is posted pre mining and notifies of pending state changes.
|
||||||
|
|
@ -45,18 +44,18 @@ type NewMinedBlockEvent struct{ Block *types.Block }
|
||||||
type RemovedTransactionEvent struct{ Txs types.Transactions }
|
type RemovedTransactionEvent struct{ Txs types.Transactions }
|
||||||
|
|
||||||
// RemovedLogEvent is posted when a reorg happens
|
// RemovedLogEvent is posted when a reorg happens
|
||||||
type RemovedLogsEvent struct{ Logs vm.Logs }
|
type RemovedLogsEvent struct{ Logs []*types.Log }
|
||||||
|
|
||||||
// ChainSplit is posted when a new head is detected
|
// ChainSplit is posted when a new head is detected
|
||||||
type ChainSplitEvent struct {
|
type ChainSplitEvent struct {
|
||||||
Block *types.Block
|
Block *types.Block
|
||||||
Logs vm.Logs
|
Logs []*types.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainEvent struct {
|
type ChainEvent struct {
|
||||||
Block *types.Block
|
Block *types.Block
|
||||||
Hash common.Hash
|
Hash common.Hash
|
||||||
Logs vm.Logs
|
Logs []*types.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainSideEvent struct {
|
type ChainSideEvent struct {
|
||||||
|
|
@ -65,7 +64,7 @@ type ChainSideEvent struct {
|
||||||
|
|
||||||
type PendingBlockEvent struct {
|
type PendingBlockEvent struct {
|
||||||
Block *types.Block
|
Block *types.Block
|
||||||
Logs vm.Logs
|
Logs []*types.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainUncleEvent struct {
|
type ChainUncleEvent struct {
|
||||||
|
|
|
||||||
|
|
@ -172,18 +172,12 @@ func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
||||||
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
|
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTestNetGenesisBlock assembles the Morden test network genesis block and
|
// WriteTestNetGenesisBlock assembles the test network genesis block and
|
||||||
// writes it - along with all associated state - into a chain database.
|
// writes it - along with all associated state - into a chain database.
|
||||||
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
||||||
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock()))
|
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteOlympicGenesisBlock assembles the Olympic genesis block and writes it
|
|
||||||
// along with all associated state into a chain database.
|
|
||||||
func WriteOlympicGenesisBlock(db ethdb.Database) (*types.Block, error) {
|
|
||||||
return WriteGenesisBlock(db, strings.NewReader(OlympicGenesisBlock()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultGenesisBlock assembles a JSON string representing the default Ethereum
|
// DefaultGenesisBlock assembles a JSON string representing the default Ethereum
|
||||||
// genesis block.
|
// genesis block.
|
||||||
func DefaultGenesisBlock() string {
|
func DefaultGenesisBlock() string {
|
||||||
|
|
@ -198,6 +192,8 @@ func DefaultGenesisBlock() string {
|
||||||
return string(blob)
|
return string(blob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum
|
||||||
|
// test network genesis block.
|
||||||
func DefaultTestnetGenesisBlock() string {
|
func DefaultTestnetGenesisBlock() string {
|
||||||
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
|
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
|
||||||
blob, err := ioutil.ReadAll(reader)
|
blob, err := ioutil.ReadAll(reader)
|
||||||
|
|
@ -207,26 +203,12 @@ func DefaultTestnetGenesisBlock() string {
|
||||||
return string(blob)
|
return string(blob)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OlympicGenesisBlock assembles a JSON string representing the Olympic genesis
|
// DevGenesisBlock assembles a JSON string representing a local dev genesis block.
|
||||||
// block.
|
func DevGenesisBlock() string {
|
||||||
func OlympicGenesisBlock() string {
|
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock)))
|
||||||
return fmt.Sprintf(`{
|
blob, err := ioutil.ReadAll(reader)
|
||||||
"nonce":"0x%x",
|
if err != nil {
|
||||||
"gasLimit":"0x%x",
|
panic(fmt.Sprintf("failed to load dev genesis: %v", err))
|
||||||
"difficulty":"0x%x",
|
}
|
||||||
"alloc": {
|
return string(blob)
|
||||||
"0000000000000000000000000000000000000001": {"balance": "1"},
|
|
||||||
"0000000000000000000000000000000000000002": {"balance": "1"},
|
|
||||||
"0000000000000000000000000000000000000003": {"balance": "1"},
|
|
||||||
"0000000000000000000000000000000000000004": {"balance": "1"},
|
|
||||||
"dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
|
|
||||||
"e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
|
|
||||||
"b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
|
|
||||||
"6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
|
|
||||||
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
|
|
||||||
"2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
|
|
||||||
"e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
|
|
||||||
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
|
|
||||||
}
|
|
||||||
}`, types.EncodeNonce(42), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -339,7 +339,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
|
||||||
if stats.ignored > 0 {
|
if stats.ignored > 0 {
|
||||||
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
|
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
|
||||||
}
|
}
|
||||||
glog.V(logger.Info).Infof("imported %d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4])
|
glog.V(logger.Info).Infof("imported %4d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4])
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ func (it *NodeIterator) step() error {
|
||||||
if !it.dataIt.Next() {
|
if !it.dataIt.Next() {
|
||||||
it.dataIt = nil
|
it.dataIt = nil
|
||||||
}
|
}
|
||||||
if bytes.Compare(account.CodeHash, emptyCodeHash) != 0 {
|
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
|
||||||
it.codeHash = common.BytesToHash(account.CodeHash)
|
it.codeHash = common.BytesToHash(account.CodeHash)
|
||||||
it.code, err = it.state.db.Get(account.CodeHash)
|
it.code, err = it.state.db.Get(account.CodeHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func TestNodeIteratorCoverage(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Cross check the hashes and the database itself
|
// Cross check the hashes and the database itself
|
||||||
for hash, _ := range hashes {
|
for hash := range hashes {
|
||||||
if _, err := db.Get(hash.Bytes()); err != nil {
|
if _, err := db.Get(hash.Bytes()); err != nil {
|
||||||
t.Errorf("failed to retrieve reported node %x: %v", hash, err)
|
t.Errorf("failed to retrieve reported node %x: %v", hash, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func TestRemove(t *testing.T) {
|
||||||
ms, account := create()
|
ms, account := create()
|
||||||
|
|
||||||
nn := make([]bool, 10)
|
nn := make([]bool, 10)
|
||||||
for i, _ := range nn {
|
for i := range nn {
|
||||||
nn[i] = true
|
nn[i] = true
|
||||||
}
|
}
|
||||||
account.nonces = append(account.nonces, nn...)
|
account.nonces = append(account.nonces, nn...)
|
||||||
|
|
@ -68,7 +68,7 @@ func TestReuse(t *testing.T) {
|
||||||
ms, account := create()
|
ms, account := create()
|
||||||
|
|
||||||
nn := make([]bool, 10)
|
nn := make([]bool, 10)
|
||||||
for i, _ := range nn {
|
for i := range nn {
|
||||||
nn[i] = true
|
nn[i] = true
|
||||||
}
|
}
|
||||||
account.nonces = append(account.nonces, nn...)
|
account.nonces = append(account.nonces, nn...)
|
||||||
|
|
@ -84,16 +84,16 @@ func TestReuse(t *testing.T) {
|
||||||
func TestRemoteNonceChange(t *testing.T) {
|
func TestRemoteNonceChange(t *testing.T) {
|
||||||
ms, account := create()
|
ms, account := create()
|
||||||
nn := make([]bool, 10)
|
nn := make([]bool, 10)
|
||||||
for i, _ := range nn {
|
for i := range nn {
|
||||||
nn[i] = true
|
nn[i] = true
|
||||||
}
|
}
|
||||||
account.nonces = append(account.nonces, nn...)
|
account.nonces = append(account.nonces, nn...)
|
||||||
nonce := ms.NewNonce(addr)
|
ms.NewNonce(addr)
|
||||||
|
|
||||||
ms.StateDB.stateObjects[addr].data.Nonce = 200
|
ms.StateDB.stateObjects[addr].data.Nonce = 200
|
||||||
nonce = ms.NewNonce(addr)
|
nonce := ms.NewNonce(addr)
|
||||||
if nonce != 200 {
|
if nonce != 200 {
|
||||||
t.Error("expected nonce after remote update to be", 201, "got", nonce)
|
t.Error("expected nonce after remote update to be", 200, "got", nonce)
|
||||||
}
|
}
|
||||||
ms.NewNonce(addr)
|
ms.NewNonce(addr)
|
||||||
ms.NewNonce(addr)
|
ms.NewNonce(addr)
|
||||||
|
|
@ -101,7 +101,7 @@ func TestRemoteNonceChange(t *testing.T) {
|
||||||
ms.StateDB.stateObjects[addr].data.Nonce = 200
|
ms.StateDB.stateObjects[addr].data.Nonce = 200
|
||||||
nonce = ms.NewNonce(addr)
|
nonce = ms.NewNonce(addr)
|
||||||
if nonce != 204 {
|
if nonce != 204 {
|
||||||
t.Error("expected nonce after remote update to be", 201, "got", nonce)
|
t.Error("expected nonce after remote update to be", 204, "got", nonce)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
|
@ -71,7 +72,7 @@ type StateDB struct {
|
||||||
|
|
||||||
thash, bhash common.Hash
|
thash, bhash common.Hash
|
||||||
txIndex int
|
txIndex int
|
||||||
logs map[common.Hash]vm.Logs
|
logs map[common.Hash][]*types.Log
|
||||||
logSize uint
|
logSize uint
|
||||||
|
|
||||||
// Journal of state modifications. This is the backbone of
|
// Journal of state modifications. This is the backbone of
|
||||||
|
|
@ -97,7 +98,7 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
|
||||||
stateObjects: make(map[common.Address]*StateObject),
|
stateObjects: make(map[common.Address]*StateObject),
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||||
refund: new(big.Int),
|
refund: new(big.Int),
|
||||||
logs: make(map[common.Hash]vm.Logs),
|
logs: make(map[common.Hash][]*types.Log),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +119,7 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) {
|
||||||
stateObjects: make(map[common.Address]*StateObject),
|
stateObjects: make(map[common.Address]*StateObject),
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||||
refund: new(big.Int),
|
refund: new(big.Int),
|
||||||
logs: make(map[common.Hash]vm.Logs),
|
logs: make(map[common.Hash][]*types.Log),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,7 +139,7 @@ func (self *StateDB) Reset(root common.Hash) error {
|
||||||
self.thash = common.Hash{}
|
self.thash = common.Hash{}
|
||||||
self.bhash = common.Hash{}
|
self.bhash = common.Hash{}
|
||||||
self.txIndex = 0
|
self.txIndex = 0
|
||||||
self.logs = make(map[common.Hash]vm.Logs)
|
self.logs = make(map[common.Hash][]*types.Log)
|
||||||
self.logSize = 0
|
self.logSize = 0
|
||||||
self.clearJournalAndRefund()
|
self.clearJournalAndRefund()
|
||||||
|
|
||||||
|
|
@ -175,7 +176,7 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
|
||||||
self.txIndex = ti
|
self.txIndex = ti
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) AddLog(log *vm.Log) {
|
func (self *StateDB) AddLog(log *types.Log) {
|
||||||
self.journal = append(self.journal, addLogChange{txhash: self.thash})
|
self.journal = append(self.journal, addLogChange{txhash: self.thash})
|
||||||
|
|
||||||
log.TxHash = self.thash
|
log.TxHash = self.thash
|
||||||
|
|
@ -186,12 +187,12 @@ func (self *StateDB) AddLog(log *vm.Log) {
|
||||||
self.logSize++
|
self.logSize++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetLogs(hash common.Hash) vm.Logs {
|
func (self *StateDB) GetLogs(hash common.Hash) []*types.Log {
|
||||||
return self.logs[hash]
|
return self.logs[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) Logs() vm.Logs {
|
func (self *StateDB) Logs() []*types.Log {
|
||||||
var logs vm.Logs
|
var logs []*types.Log
|
||||||
for _, lgs := range self.logs {
|
for _, lgs := range self.logs {
|
||||||
logs = append(logs, lgs...)
|
logs = append(logs, lgs...)
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +210,7 @@ func (self *StateDB) Exist(addr common.Address) bool {
|
||||||
return self.GetStateObject(addr) != nil
|
return self.GetStateObject(addr) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty returns whether the state object is either non-existant
|
// Empty returns whether the state object is either non-existent
|
||||||
// or empty according to the EIP161 specification (balance = nonce = code = 0)
|
// or empty according to the EIP161 specification (balance = nonce = code = 0)
|
||||||
func (self *StateDB) Empty(addr common.Address) bool {
|
func (self *StateDB) Empty(addr common.Address) bool {
|
||||||
so := self.GetStateObject(addr)
|
so := self.GetStateObject(addr)
|
||||||
|
|
@ -474,16 +475,16 @@ func (self *StateDB) Copy() *StateDB {
|
||||||
stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
|
stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
|
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
|
||||||
refund: new(big.Int).Set(self.refund),
|
refund: new(big.Int).Set(self.refund),
|
||||||
logs: make(map[common.Hash]vm.Logs, len(self.logs)),
|
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
||||||
logSize: self.logSize,
|
logSize: self.logSize,
|
||||||
}
|
}
|
||||||
// Copy the dirty states and logs
|
// Copy the dirty states and logs
|
||||||
for addr, _ := range self.stateObjectsDirty {
|
for addr := range self.stateObjectsDirty {
|
||||||
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty)
|
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty)
|
||||||
state.stateObjectsDirty[addr] = struct{}{}
|
state.stateObjectsDirty[addr] = struct{}{}
|
||||||
}
|
}
|
||||||
for hash, logs := range self.logs {
|
for hash, logs := range self.logs {
|
||||||
state.logs[hash] = make(vm.Logs, len(logs))
|
state.logs[hash] = make([]*types.Log, len(logs))
|
||||||
copy(state.logs[hash], logs)
|
copy(state.logs[hash], logs)
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
|
@ -529,7 +530,7 @@ func (self *StateDB) GetRefund() *big.Int {
|
||||||
// It is called in between transactions to get the root hash that
|
// It is called in between transactions to get the root hash that
|
||||||
// goes into transaction receipts.
|
// goes into transaction receipts.
|
||||||
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
for addr, _ := range s.stateObjectsDirty {
|
for addr := range s.stateObjectsDirty {
|
||||||
stateObject := s.stateObjects[addr]
|
stateObject := s.stateObjects[addr]
|
||||||
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
|
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
|
||||||
s.deleteStateObject(stateObject)
|
s.deleteStateObject(stateObject)
|
||||||
|
|
@ -552,7 +553,7 @@ func (s *StateDB) DeleteSuicides() {
|
||||||
// Reset refund so that any used-gas calculations can use this method.
|
// Reset refund so that any used-gas calculations can use this method.
|
||||||
s.clearJournalAndRefund()
|
s.clearJournalAndRefund()
|
||||||
|
|
||||||
for addr, _ := range s.stateObjectsDirty {
|
for addr := range s.stateObjectsDirty {
|
||||||
stateObject := s.stateObjects[addr]
|
stateObject := s.stateObjects[addr]
|
||||||
|
|
||||||
// If the object has been removed by a suicide
|
// If the object has been removed by a suicide
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"testing/quick"
|
"testing/quick"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -221,7 +221,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||||
fn: func(a testAction, s *StateDB) {
|
fn: func(a testAction, s *StateDB) {
|
||||||
data := make([]byte, 2)
|
data := make([]byte, 2)
|
||||||
binary.BigEndian.PutUint16(data, uint16(a.args[0]))
|
binary.BigEndian.PutUint16(data, uint16(a.args[0]))
|
||||||
s.AddLog(&vm.Log{Address: addr, Data: data})
|
s.AddLog(&types.Log{Address: addr, Data: data})
|
||||||
},
|
},
|
||||||
args: make([]int64, 1),
|
args: make([]int64, 1),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
@ -32,7 +31,7 @@ import (
|
||||||
type StateSync trie.TrieSync
|
type StateSync trie.TrieSync
|
||||||
|
|
||||||
// NewStateSync create a new state trie download scheduler.
|
// NewStateSync create a new state trie download scheduler.
|
||||||
func NewStateSync(root common.Hash, database ethdb.Database) *StateSync {
|
func NewStateSync(root common.Hash, database trie.DatabaseReader) *StateSync {
|
||||||
var syncer *trie.TrieSync
|
var syncer *trie.TrieSync
|
||||||
|
|
||||||
callback := func(leaf []byte, parent common.Hash) error {
|
callback := func(leaf []byte, parent common.Hash) error {
|
||||||
|
|
@ -62,8 +61,8 @@ func (s *StateSync) Missing(max int) []common.Hash {
|
||||||
// Process injects a batch of retrieved trie nodes data, returning if something
|
// Process injects a batch of retrieved trie nodes data, returning if something
|
||||||
// was committed to the database and also the index of an entry if processing of
|
// was committed to the database and also the index of an entry if processing of
|
||||||
// it failed.
|
// it failed.
|
||||||
func (s *StateSync) Process(list []trie.SyncResult) (bool, int, error) {
|
func (s *StateSync) Process(list []trie.SyncResult, dbw trie.DatabaseWriter) (bool, int, error) {
|
||||||
return (*trie.TrieSync)(s).Process(list)
|
return (*trie.TrieSync)(s).Process(list, dbw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pending returns the number of state entries currently pending for download.
|
// Pending returns the number of state entries currently pending for download.
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou
|
||||||
if nonce := state.GetNonce(acc.address); nonce != acc.nonce {
|
if nonce := state.GetNonce(acc.address); nonce != acc.nonce {
|
||||||
t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce)
|
t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce)
|
||||||
}
|
}
|
||||||
if code := state.GetCode(acc.address); bytes.Compare(code, acc.code) != 0 {
|
if code := state.GetCode(acc.address); !bytes.Equal(code, acc.code) {
|
||||||
t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code)
|
t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +138,7 @@ func testIterativeStateSync(t *testing.T, batch int) {
|
||||||
}
|
}
|
||||||
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
||||||
}
|
}
|
||||||
if _, index, err := sched.Process(results); err != nil {
|
if _, index, err := sched.Process(results, dstDb); err != nil {
|
||||||
t.Fatalf("failed to process result #%d: %v", index, err)
|
t.Fatalf("failed to process result #%d: %v", index, err)
|
||||||
}
|
}
|
||||||
queue = append(queue[:0], sched.Missing(batch)...)
|
queue = append(queue[:0], sched.Missing(batch)...)
|
||||||
|
|
@ -168,7 +168,7 @@ func TestIterativeDelayedStateSync(t *testing.T) {
|
||||||
}
|
}
|
||||||
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
||||||
}
|
}
|
||||||
if _, index, err := sched.Process(results); err != nil {
|
if _, index, err := sched.Process(results, dstDb); err != nil {
|
||||||
t.Fatalf("failed to process result #%d: %v", index, err)
|
t.Fatalf("failed to process result #%d: %v", index, err)
|
||||||
}
|
}
|
||||||
queue = append(queue[len(results):], sched.Missing(0)...)
|
queue = append(queue[len(results):], sched.Missing(0)...)
|
||||||
|
|
@ -198,7 +198,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
|
||||||
for len(queue) > 0 {
|
for len(queue) > 0 {
|
||||||
// Fetch all the queued nodes in a random order
|
// Fetch all the queued nodes in a random order
|
||||||
results := make([]trie.SyncResult, 0, len(queue))
|
results := make([]trie.SyncResult, 0, len(queue))
|
||||||
for hash, _ := range queue {
|
for hash := range queue {
|
||||||
data, err := srcDb.Get(hash.Bytes())
|
data, err := srcDb.Get(hash.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
|
t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
|
||||||
|
|
@ -206,7 +206,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
|
||||||
results = append(results, trie.SyncResult{Hash: hash, Data: data})
|
results = append(results, trie.SyncResult{Hash: hash, Data: data})
|
||||||
}
|
}
|
||||||
// Feed the retrieved results back and queue new tasks
|
// Feed the retrieved results back and queue new tasks
|
||||||
if _, index, err := sched.Process(results); err != nil {
|
if _, index, err := sched.Process(results, dstDb); err != nil {
|
||||||
t.Fatalf("failed to process result #%d: %v", index, err)
|
t.Fatalf("failed to process result #%d: %v", index, err)
|
||||||
}
|
}
|
||||||
queue = make(map[common.Hash]struct{})
|
queue = make(map[common.Hash]struct{})
|
||||||
|
|
@ -235,7 +235,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||||
for len(queue) > 0 {
|
for len(queue) > 0 {
|
||||||
// Sync only half of the scheduled nodes, even those in random order
|
// Sync only half of the scheduled nodes, even those in random order
|
||||||
results := make([]trie.SyncResult, 0, len(queue)/2+1)
|
results := make([]trie.SyncResult, 0, len(queue)/2+1)
|
||||||
for hash, _ := range queue {
|
for hash := range queue {
|
||||||
delete(queue, hash)
|
delete(queue, hash)
|
||||||
|
|
||||||
data, err := srcDb.Get(hash.Bytes())
|
data, err := srcDb.Get(hash.Bytes())
|
||||||
|
|
@ -249,7 +249,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Feed the retrieved results back and queue new tasks
|
// Feed the retrieved results back and queue new tasks
|
||||||
if _, index, err := sched.Process(results); err != nil {
|
if _, index, err := sched.Process(results, dstDb); err != nil {
|
||||||
t.Fatalf("failed to process result #%d: %v", index, err)
|
t.Fatalf("failed to process result #%d: %v", index, err)
|
||||||
}
|
}
|
||||||
for _, hash := range sched.Missing(0) {
|
for _, hash := range sched.Missing(0) {
|
||||||
|
|
@ -283,7 +283,7 @@ func TestIncompleteStateSync(t *testing.T) {
|
||||||
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
||||||
}
|
}
|
||||||
// Process each of the state nodes
|
// Process each of the state nodes
|
||||||
if _, index, err := sched.Process(results); err != nil {
|
if _, index, err := sched.Process(results, dstDb); err != nil {
|
||||||
t.Fatalf("failed to process result #%d: %v", index, err)
|
t.Fatalf("failed to process result #%d: %v", index, err)
|
||||||
}
|
}
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
|
|
@ -294,7 +294,7 @@ func TestIncompleteStateSync(t *testing.T) {
|
||||||
// Skim through the accounts and make sure the root hash is not a code node
|
// Skim through the accounts and make sure the root hash is not a code node
|
||||||
codeHash := false
|
codeHash := false
|
||||||
for _, acc := range srcAccounts {
|
for _, acc := range srcAccounts {
|
||||||
if bytes.Compare(root.Bytes(), crypto.Sha3(acc.code)) == 0 {
|
if root == crypto.Keccak256Hash(acc.code) {
|
||||||
codeHash = true
|
codeHash = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,13 +57,13 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcess
|
||||||
// Process returns the receipts and logs accumulated during the process and
|
// Process returns the receipts and logs accumulated during the process and
|
||||||
// returns the amount of gas that was used in the process. If any of the
|
// returns the amount of gas that was used in the process. If any of the
|
||||||
// transactions failed to execute due to insufficient gas it will return an error.
|
// transactions failed to execute due to insufficient gas it will return an error.
|
||||||
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
|
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {
|
||||||
var (
|
var (
|
||||||
receipts types.Receipts
|
receipts types.Receipts
|
||||||
totalUsedGas = big.NewInt(0)
|
totalUsedGas = big.NewInt(0)
|
||||||
err error
|
err error
|
||||||
header = block.Header()
|
header = block.Header()
|
||||||
allLogs vm.Logs
|
allLogs []*types.Log
|
||||||
gp = new(GasPool).AddGas(block.GasLimit())
|
gp = new(GasPool).AddGas(block.GasLimit())
|
||||||
)
|
)
|
||||||
// Mutate the the block and state according to any hard-fork specs
|
// Mutate the the block and state according to any hard-fork specs
|
||||||
|
|
@ -74,12 +74,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
//fmt.Println("tx:", i)
|
//fmt.Println("tx:", i)
|
||||||
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
||||||
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
}
|
}
|
||||||
AccumulateRewards(statedb, header, block.Uncles())
|
AccumulateRewards(statedb, header, block.Uncles())
|
||||||
|
|
||||||
|
|
@ -87,24 +87,23 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyTransaction attempts to apply a transaction to the given state database
|
// ApplyTransaction attempts to apply a transaction to the given state database
|
||||||
// and uses the input parameters for its environment.
|
// and uses the input parameters for its environment. It returns the receipt
|
||||||
//
|
// for the transaction, gas used and an error if the transaction failed,
|
||||||
// ApplyTransactions returns the generated receipts and vm logs during the
|
// indicating the block was invalid.
|
||||||
// execution of the state transition phase.
|
func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, *big.Int, error) {
|
||||||
func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
|
|
||||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
|
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Create a new context to be used in the EVM environment
|
// Create a new context to be used in the EVM environment
|
||||||
context := NewEVMContext(msg, header, bc)
|
context := NewEVMContext(msg, header, bc)
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEnvironment(context, statedb, config, vm.Config{})
|
vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
|
||||||
// Apply the transaction to the current state (included in the env)
|
// Apply the transaction to the current state (included in the env)
|
||||||
_, gas, err := ApplyMessage(vmenv, msg, gp)
|
_, gas, err := ApplyMessage(vmenv, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the state with pending changes
|
// Update the state with pending changes
|
||||||
|
|
@ -125,7 +124,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, s
|
||||||
|
|
||||||
glog.V(logger.Debug).Infoln(receipt)
|
glog.V(logger.Debug).Infoln(receipt)
|
||||||
|
|
||||||
return receipt, receipt.Logs, gas, err
|
return receipt, gas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccumulateRewards credits the coinbase of the given block with the
|
// AccumulateRewards credits the coinbase of the given block with the
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ type StateTransition struct {
|
||||||
data []byte
|
data []byte
|
||||||
state vm.StateDB
|
state vm.StateDB
|
||||||
|
|
||||||
env *vm.Environment
|
env *vm.EVM
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message represents a message sent to a contract.
|
// Message represents a message sent to a contract.
|
||||||
|
|
@ -106,7 +106,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateTransition initialises and returns a new state transition object.
|
// NewStateTransition initialises and returns a new state transition object.
|
||||||
func NewStateTransition(env *vm.Environment, msg Message, gp *GasPool) *StateTransition {
|
func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition {
|
||||||
return &StateTransition{
|
return &StateTransition{
|
||||||
gp: gp,
|
gp: gp,
|
||||||
env: env,
|
env: env,
|
||||||
|
|
@ -127,7 +127,7 @@ func NewStateTransition(env *vm.Environment, msg Message, gp *GasPool) *StateTra
|
||||||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(env *vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
|
func ApplyMessage(env *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
|
||||||
st := NewStateTransition(env, msg, gp)
|
st := NewStateTransition(env, msg, gp)
|
||||||
|
|
||||||
ret, _, gasUsed, err := st.TransitionDb()
|
ret, _, gasUsed, err := st.TransitionDb()
|
||||||
|
|
@ -159,7 +159,7 @@ func (self *StateTransition) to() vm.Account {
|
||||||
|
|
||||||
func (self *StateTransition) useGas(amount *big.Int) error {
|
func (self *StateTransition) useGas(amount *big.Int) error {
|
||||||
if self.gas.Cmp(amount) < 0 {
|
if self.gas.Cmp(amount) < 0 {
|
||||||
return vm.OutOfGasError
|
return vm.ErrOutOfGas
|
||||||
}
|
}
|
||||||
self.gas.Sub(self.gas, amount)
|
self.gas.Sub(self.gas, amount)
|
||||||
|
|
||||||
|
|
@ -233,7 +233,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value)
|
ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value)
|
||||||
if homestead && err == vm.CodeStoreOutOfGasError {
|
if homestead && err == vm.ErrCodeStoreOutOfGas {
|
||||||
self.gas = Big0
|
self.gas = Big0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transac
|
||||||
// If transactions were removed, the heap and cache are ruined
|
// If transactions were removed, the heap and cache are ruined
|
||||||
if len(removed) > 0 {
|
if len(removed) > 0 {
|
||||||
*m.index = make([]uint64, 0, len(m.items))
|
*m.index = make([]uint64, 0, len(m.items))
|
||||||
for nonce, _ := range m.items {
|
for nonce := range m.items {
|
||||||
*m.index = append(*m.index, nonce)
|
*m.index = append(*m.index, nonce)
|
||||||
}
|
}
|
||||||
heap.Init(m.index)
|
heap.Init(m.index)
|
||||||
|
|
@ -216,7 +216,7 @@ func (m *txSortedMap) Flatten() types.Transactions {
|
||||||
// txList is a "list" of transactions belonging to an account, sorted by account
|
// txList is a "list" of transactions belonging to an account, sorted by account
|
||||||
// nonce. The same type can be used both for storing contiguous transactions for
|
// nonce. The same type can be used both for storing contiguous transactions for
|
||||||
// the executable/pending queue; and for storing gapped transactions for the non-
|
// the executable/pending queue; and for storing gapped transactions for the non-
|
||||||
// executable/future queue, with minor behavoiral changes.
|
// executable/future queue, with minor behavioral changes.
|
||||||
type txList struct {
|
type txList struct {
|
||||||
strict bool // Whether nonces are strictly continuous or not
|
strict bool // Whether nonces are strictly continuous or not
|
||||||
txs *txSortedMap // Heap indexed sorted hash map of the transactions
|
txs *txSortedMap // Heap indexed sorted hash map of the transactions
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||||
// add validates a transaction and inserts it into the non-executable queue for
|
// add validates a transaction and inserts it into the non-executable queue for
|
||||||
// later pending promotion and execution.
|
// later pending promotion and execution.
|
||||||
func (pool *TxPool) add(tx *types.Transaction) error {
|
func (pool *TxPool) add(tx *types.Transaction) error {
|
||||||
// If the transaction is alreayd known, discard it
|
// If the transaction is already known, discard it
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
if pool.all[hash] != nil {
|
if pool.all[hash] != nil {
|
||||||
return fmt.Errorf("Known transaction: %x", hash[:4])
|
return fmt.Errorf("Known transaction: %x", hash[:4])
|
||||||
|
|
@ -609,7 +609,7 @@ func (pool *TxPool) promoteExecutables(state *state.StateDB) {
|
||||||
if queued > maxQueuedInTotal {
|
if queued > maxQueuedInTotal {
|
||||||
// Sort all accounts with queued transactions by heartbeat
|
// Sort all accounts with queued transactions by heartbeat
|
||||||
addresses := make(addresssByHeartbeat, 0, len(pool.queue))
|
addresses := make(addresssByHeartbeat, 0, len(pool.queue))
|
||||||
for addr, _ := range pool.queue {
|
for addr := range pool.queue {
|
||||||
addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]})
|
addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]})
|
||||||
}
|
}
|
||||||
sort.Sort(addresses)
|
sort.Sort(addresses)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||||
tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key)
|
tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,7 +238,7 @@ func TestRemoveTx(t *testing.T) {
|
||||||
func TestNegativeValue(t *testing.T) {
|
func TestNegativeValue(t *testing.T) {
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
|
|
||||||
tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key)
|
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil), types.HomesteadSigner{}, key)
|
||||||
from, _ := deriveSender(tx)
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1))
|
currentState.AddBalance(from, big.NewInt(1))
|
||||||
|
|
@ -287,9 +287,9 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
resetState()
|
resetState()
|
||||||
|
|
||||||
signer := types.HomesteadSigner{}
|
signer := types.HomesteadSigner{}
|
||||||
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, key)
|
tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil), signer, key)
|
||||||
tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(signer, key)
|
tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil), signer, key)
|
||||||
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(signer, key)
|
tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil), signer, key)
|
||||||
|
|
||||||
// Add the first two transaction, ensure higher priced stays only
|
// Add the first two transaction, ensure higher priced stays only
|
||||||
if err := pool.add(tx1); err != nil {
|
if err := pool.add(tx1); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -58,5 +58,5 @@ type HeaderValidator interface {
|
||||||
// of gas used in the process and return an error if any of the internal rules
|
// of gas used in the process and return an error if any of the internal rules
|
||||||
// failed.
|
// failed.
|
||||||
type Processor interface {
|
type Processor interface {
|
||||||
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error)
|
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -423,9 +423,9 @@ func CalcUncleHash(uncles []*Header) common.Hash {
|
||||||
|
|
||||||
// WithMiningResult returns a new block with the data from b
|
// WithMiningResult returns a new block with the data from b
|
||||||
// where nonce and mix digest are set to the provided values.
|
// where nonce and mix digest are set to the provided values.
|
||||||
func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block {
|
func (b *Block) WithMiningResult(nonce BlockNonce, mixDigest common.Hash) *Block {
|
||||||
cpy := *b.header
|
cpy := *b.header
|
||||||
binary.BigEndian.PutUint64(cpy.Nonce[:], nonce)
|
cpy.Nonce = nonce
|
||||||
cpy.MixDigest = mixDigest
|
cpy.MixDigest = mixDigest
|
||||||
return &Block{
|
return &Block{
|
||||||
header: &cpy,
|
header: &cpy,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func TestBlockEncoding(t *testing.T) {
|
||||||
|
|
||||||
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
|
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
|
||||||
|
|
||||||
tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
|
tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100"))
|
||||||
fmt.Println(block.Transactions()[0].Hash())
|
fmt.Println(block.Transactions()[0].Hash())
|
||||||
fmt.Println(tx1.data)
|
fmt.Println(tx1.data)
|
||||||
fmt.Println(tx1.Hash())
|
fmt.Println(tx1.Hash())
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -95,17 +94,11 @@ func CreateBloom(receipts Receipts) Bloom {
|
||||||
return BytesToBloom(bin.Bytes())
|
return BytesToBloom(bin.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func LogsBloom(logs vm.Logs) *big.Int {
|
func LogsBloom(logs []*Log) *big.Int {
|
||||||
bin := new(big.Int)
|
bin := new(big.Int)
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
data := make([]common.Hash, len(log.Topics))
|
|
||||||
bin.Or(bin, bloom9(log.Address.Bytes()))
|
bin.Or(bin, bloom9(log.Address.Bytes()))
|
||||||
|
for _, b := range log.Topics {
|
||||||
for i, topic := range log.Topics {
|
|
||||||
data[i] = topic
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, b := range data {
|
|
||||||
bin.Or(bin, bloom9(b[:]))
|
bin.Or(bin, bloom9(b[:]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package vm
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -79,10 +79,6 @@ type jsonLog struct {
|
||||||
Removed bool `json:"removed"`
|
Removed bool `json:"removed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log {
|
|
||||||
return &Log{Address: address, Topics: topics, Data: data, BlockNumber: number}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeRLP implements rlp.Encoder.
|
// EncodeRLP implements rlp.Encoder.
|
||||||
func (l *Log) EncodeRLP(w io.Writer) error {
|
func (l *Log) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
|
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
|
||||||
|
|
@ -150,8 +146,6 @@ func (l *Log) UnmarshalJSON(input []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Logs []*Log
|
|
||||||
|
|
||||||
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
|
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
|
||||||
// a log including non-consensus fields.
|
// a log including non-consensus fields.
|
||||||
type LogForStorage Log
|
type LogForStorage Log
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package vm
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,7 +39,7 @@ type Receipt struct {
|
||||||
PostState []byte
|
PostState []byte
|
||||||
CumulativeGasUsed *big.Int
|
CumulativeGasUsed *big.Int
|
||||||
Bloom Bloom
|
Bloom Bloom
|
||||||
Logs vm.Logs
|
Logs []*Log
|
||||||
|
|
||||||
// Implementation fields (don't reorder!)
|
// Implementation fields (don't reorder!)
|
||||||
TxHash common.Hash
|
TxHash common.Hash
|
||||||
|
|
@ -52,7 +51,7 @@ type jsonReceipt struct {
|
||||||
PostState *common.Hash `json:"root"`
|
PostState *common.Hash `json:"root"`
|
||||||
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
|
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
|
||||||
Bloom *Bloom `json:"logsBloom"`
|
Bloom *Bloom `json:"logsBloom"`
|
||||||
Logs *vm.Logs `json:"logs"`
|
Logs []*Log `json:"logs"`
|
||||||
TxHash *common.Hash `json:"transactionHash"`
|
TxHash *common.Hash `json:"transactionHash"`
|
||||||
ContractAddress *common.Address `json:"contractAddress"`
|
ContractAddress *common.Address `json:"contractAddress"`
|
||||||
GasUsed *hexutil.Big `json:"gasUsed"`
|
GasUsed *hexutil.Big `json:"gasUsed"`
|
||||||
|
|
@ -76,7 +75,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
||||||
PostState []byte
|
PostState []byte
|
||||||
CumulativeGasUsed *big.Int
|
CumulativeGasUsed *big.Int
|
||||||
Bloom Bloom
|
Bloom Bloom
|
||||||
Logs vm.Logs
|
Logs []*Log
|
||||||
}
|
}
|
||||||
if err := s.Decode(&receipt); err != nil {
|
if err := s.Decode(&receipt); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -93,7 +92,7 @@ func (r *Receipt) MarshalJSON() ([]byte, error) {
|
||||||
PostState: &root,
|
PostState: &root,
|
||||||
CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed),
|
CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed),
|
||||||
Bloom: &r.Bloom,
|
Bloom: &r.Bloom,
|
||||||
Logs: &r.Logs,
|
Logs: r.Logs,
|
||||||
TxHash: &r.TxHash,
|
TxHash: &r.TxHash,
|
||||||
ContractAddress: &r.ContractAddress,
|
ContractAddress: &r.ContractAddress,
|
||||||
GasUsed: (*hexutil.Big)(r.GasUsed),
|
GasUsed: (*hexutil.Big)(r.GasUsed),
|
||||||
|
|
@ -120,7 +119,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||||
PostState: (*dec.PostState)[:],
|
PostState: (*dec.PostState)[:],
|
||||||
CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed),
|
CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed),
|
||||||
Bloom: *dec.Bloom,
|
Bloom: *dec.Bloom,
|
||||||
Logs: *dec.Logs,
|
Logs: dec.Logs,
|
||||||
TxHash: *dec.TxHash,
|
TxHash: *dec.TxHash,
|
||||||
GasUsed: (*big.Int)(dec.GasUsed),
|
GasUsed: (*big.Int)(dec.GasUsed),
|
||||||
}
|
}
|
||||||
|
|
@ -142,9 +141,9 @@ type ReceiptForStorage Receipt
|
||||||
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
|
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
|
||||||
// into an RLP stream.
|
// into an RLP stream.
|
||||||
func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
|
func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
|
||||||
logs := make([]*vm.LogForStorage, len(r.Logs))
|
logs := make([]*LogForStorage, len(r.Logs))
|
||||||
for i, log := range r.Logs {
|
for i, log := range r.Logs {
|
||||||
logs[i] = (*vm.LogForStorage)(log)
|
logs[i] = (*LogForStorage)(log)
|
||||||
}
|
}
|
||||||
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
|
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +157,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
Bloom Bloom
|
Bloom Bloom
|
||||||
TxHash common.Hash
|
TxHash common.Hash
|
||||||
ContractAddress common.Address
|
ContractAddress common.Address
|
||||||
Logs []*vm.LogForStorage
|
Logs []*LogForStorage
|
||||||
GasUsed *big.Int
|
GasUsed *big.Int
|
||||||
}
|
}
|
||||||
if err := s.Decode(&receipt); err != nil {
|
if err := s.Decode(&receipt); err != nil {
|
||||||
|
|
@ -166,9 +165,9 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
}
|
}
|
||||||
// Assign the consensus fields
|
// Assign the consensus fields
|
||||||
r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom
|
r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom
|
||||||
r.Logs = make(vm.Logs, len(receipt.Logs))
|
r.Logs = make([]*Log, len(receipt.Logs))
|
||||||
for i, log := range receipt.Logs {
|
for i, log := range receipt.Logs {
|
||||||
r.Logs[i] = (*vm.Log)(log)
|
r.Logs[i] = (*Log)(log)
|
||||||
}
|
}
|
||||||
// Assign the implementation fields
|
// Assign the implementation fields
|
||||||
r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed
|
r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"container/heap"
|
"container/heap"
|
||||||
"crypto/ecdsa"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -199,9 +198,9 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||||
|
|
||||||
var V byte
|
var V byte
|
||||||
if isProtectedV((*big.Int)(dec.V)) {
|
if isProtectedV((*big.Int)(dec.V)) {
|
||||||
V = normaliseV(NewEIP155Signer(deriveChainId((*big.Int)(dec.V))), (*big.Int)(dec.V))
|
V = byte((new(big.Int).Sub((*big.Int)(dec.V), deriveChainId((*big.Int)(dec.V))).Uint64()) - 35)
|
||||||
} else {
|
} else {
|
||||||
V = byte(((*big.Int)(dec.V)).Uint64())
|
V = byte(((*big.Int)(dec.V)).Uint64() - 27)
|
||||||
}
|
}
|
||||||
if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
|
if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
|
||||||
return ErrInvalidSig
|
return ErrInvalidSig
|
||||||
|
|
@ -272,51 +271,6 @@ func (tx *Transaction) Size() common.StorageSize {
|
||||||
return common.StorageSize(c)
|
return common.StorageSize(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// From returns the address derived from the signature (V, R, S) using secp256k1
|
|
||||||
// elliptic curve and an error if it failed deriving or upon an incorrect
|
|
||||||
// signature.
|
|
||||||
//
|
|
||||||
// From Uses the homestead consensus rules to determine whether the signature is
|
|
||||||
// valid.
|
|
||||||
//
|
|
||||||
// From caches the address, allowing it to be used regardless of
|
|
||||||
// Frontier / Homestead. however, the first time called it runs
|
|
||||||
// signature validations, so we need two versions. This makes it
|
|
||||||
// easier to ensure backwards compatibility of things like package rpc
|
|
||||||
// where eth_getblockbynumber uses tx.From() and needs to work for
|
|
||||||
// both txs before and after the first homestead block. Signatures
|
|
||||||
// valid in homestead are a subset of valid ones in Frontier)
|
|
||||||
func (tx *Transaction) From() (common.Address, error) {
|
|
||||||
if tx.signer == nil {
|
|
||||||
return common.Address{}, errNoSigner
|
|
||||||
}
|
|
||||||
|
|
||||||
if from := tx.from.Load(); from != nil {
|
|
||||||
return from.(common.Address), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pubkey, err := tx.signer.PublicKey(tx)
|
|
||||||
if err != nil {
|
|
||||||
return common.Address{}, err
|
|
||||||
}
|
|
||||||
var addr common.Address
|
|
||||||
copy(addr[:], crypto.Keccak256(pubkey[1:])[12:])
|
|
||||||
tx.from.Store(addr)
|
|
||||||
return addr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignatureValues returns the ECDSA signature values contained in the transaction.
|
|
||||||
func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int, err error) {
|
|
||||||
if tx.signer == nil {
|
|
||||||
return 0, nil, nil,errNoSigner
|
|
||||||
}
|
|
||||||
|
|
||||||
return normaliseV(tx.signer, tx.data.V), new(big.Int).Set(tx.data.R),new(big.Int).Set(tx.data.S), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// AsMessage returns the transaction as a core.Message.
|
// AsMessage returns the transaction as a core.Message.
|
||||||
//
|
//
|
||||||
// AsMessage requires a signer to derive the sender.
|
// AsMessage requires a signer to derive the sender.
|
||||||
|
|
@ -338,14 +292,6 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
|
||||||
return msg, err
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignECDSA signs the transaction using the given signer and private key
|
|
||||||
//
|
|
||||||
// XXX This only makes for a nice API: NewTx(...).SignECDSA(signer, prv). Should
|
|
||||||
// we keep this?
|
|
||||||
func (tx *Transaction) SignECDSA(signer Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
|
||||||
return signer.SignECDSA(tx, prv)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSignature returns a new transaction with the given signature.
|
// WithSignature returns a new transaction with the given signature.
|
||||||
// This signature needs to be formatted as described in the yellow paper (v+27).
|
// This signature needs to be formatted as described in the yellow paper (v+27).
|
||||||
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
|
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,10 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
||||||
return signer
|
return signer
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignECDSA signs the transaction using the given signer and private key
|
// SignTx signs the transaction using the given signer and private key
|
||||||
func SignECDSA(s Signer, tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
||||||
h := s.Hash(tx)
|
h := s.Hash(tx)
|
||||||
sig, err := crypto.SignEthereum(h[:], prv)
|
sig, err := crypto.Sign(h[:], prv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -91,19 +91,13 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignatureValues returns the ECDSA signature values contained in the transaction.
|
|
||||||
func SignatureValues(signer Signer, tx *Transaction) (v byte, r *big.Int, s *big.Int) {
|
|
||||||
return normaliseV(signer, tx.data.V), new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Signer interface {
|
type Signer interface {
|
||||||
// Hash returns the rlp encoded hash for signatures
|
// Hash returns the rlp encoded hash for signatures
|
||||||
Hash(tx *Transaction) common.Hash
|
Hash(tx *Transaction) common.Hash
|
||||||
// PubilcKey returns the public key derived from the signature
|
// PubilcKey returns the public key derived from the signature
|
||||||
PublicKey(tx *Transaction) ([]byte, error)
|
PublicKey(tx *Transaction) ([]byte, error)
|
||||||
// SignECDSA signs the transaction with the given and returns a copy of the tx
|
// WithSignature returns a copy of the transaction with the given signature.
|
||||||
SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error)
|
// The signature must be encoded in [R || S || V] format where V is 0 or 1.
|
||||||
// WithSignature returns a copy of the transaction with the given signature
|
|
||||||
WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
|
WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
|
||||||
// Checks for equality on the signers
|
// Checks for equality on the signers
|
||||||
Equal(Signer) bool
|
Equal(Signer) bool
|
||||||
|
|
@ -129,10 +123,6 @@ func (s EIP155Signer) Equal(s2 Signer) bool {
|
||||||
return ok && eip155.chainId.Cmp(s.chainId) == 0
|
return ok && eip155.chainId.Cmp(s.chainId) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s EIP155Signer) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
|
||||||
return SignECDSA(s, tx, prv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
|
func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
// if the transaction is not protected fall back to homestead signer
|
// if the transaction is not protected fall back to homestead signer
|
||||||
if !tx.Protected() {
|
if !tx.Protected() {
|
||||||
|
|
@ -143,17 +133,16 @@ func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
return nil, ErrInvalidChainId
|
return nil, ErrInvalidChainId
|
||||||
}
|
}
|
||||||
|
|
||||||
V := normaliseV(s, tx.data.V)
|
V := byte(new(big.Int).Sub(tx.data.V, s.chainIdMul).Uint64() - 35)
|
||||||
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
||||||
return nil, ErrInvalidSig
|
return nil, ErrInvalidSig
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode the signature in uncompressed format
|
// encode the signature in uncompressed format
|
||||||
R, S := tx.data.R.Bytes(), tx.data.S.Bytes()
|
R, S := tx.data.R.Bytes(), tx.data.S.Bytes()
|
||||||
sig := make([]byte, 65)
|
sig := make([]byte, 65)
|
||||||
copy(sig[32-len(R):32], R)
|
copy(sig[32-len(R):32], R)
|
||||||
copy(sig[64-len(S):64], S)
|
copy(sig[64-len(S):64], S)
|
||||||
sig[64] = V - 27
|
sig[64] = V
|
||||||
|
|
||||||
// recover the public key from the signature
|
// recover the public key from the signature
|
||||||
hash := s.Hash(tx)
|
hash := s.Hash(tx)
|
||||||
|
|
@ -167,8 +156,8 @@ func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
return pub, nil
|
return pub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSignature returns a new transaction with the given signature.
|
// WithSignature returns a new transaction with the given signature. This signature
|
||||||
// This signature needs to be formatted as described in the yellow paper (v+27).
|
// needs to be in the [R || S || V] format where V is 0 or 1.
|
||||||
func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
||||||
if len(sig) != 65 {
|
if len(sig) != 65 {
|
||||||
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
||||||
|
|
@ -179,7 +168,7 @@ func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction,
|
||||||
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
||||||
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
||||||
if s.chainId.BitLen() > 0 {
|
if s.chainId.BitLen() > 0 {
|
||||||
cpy.data.V = big.NewInt(int64(sig[64] - 27 + 35))
|
cpy.data.V = big.NewInt(int64(sig[64] + 35))
|
||||||
cpy.data.V.Add(cpy.data.V, s.chainIdMul)
|
cpy.data.V.Add(cpy.data.V, s.chainIdMul)
|
||||||
}
|
}
|
||||||
return cpy, nil
|
return cpy, nil
|
||||||
|
|
@ -199,15 +188,6 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s EIP155Signer) SigECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
|
||||||
h := s.Hash(tx)
|
|
||||||
sig, err := crypto.SignEthereum(h[:], prv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return s.WithSignature(tx, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HomesteadTransaction implements TransactionInterface using the
|
// HomesteadTransaction implements TransactionInterface using the
|
||||||
// homestead rules.
|
// homestead rules.
|
||||||
type HomesteadSigner struct{ FrontierSigner }
|
type HomesteadSigner struct{ FrontierSigner }
|
||||||
|
|
@ -217,8 +197,8 @@ func (s HomesteadSigner) Equal(s2 Signer) bool {
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSignature returns a new transaction with the given snature.
|
// WithSignature returns a new transaction with the given signature. This signature
|
||||||
// This snature needs to be formatted as described in the yellow paper (v+27).
|
// needs to be in the [R || S || V] format where V is 0 or 1.
|
||||||
func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
||||||
if len(sig) != 65 {
|
if len(sig) != 65 {
|
||||||
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
||||||
|
|
@ -226,24 +206,15 @@ func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transacti
|
||||||
cpy := &Transaction{data: tx.data}
|
cpy := &Transaction{data: tx.data}
|
||||||
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
||||||
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
||||||
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
|
||||||
return cpy, nil
|
return cpy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hs HomesteadSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
|
||||||
h := hs.Hash(tx)
|
|
||||||
sig, err := crypto.SignEthereum(h[:], prv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return hs.WithSignature(tx, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
if tx.data.V.BitLen() > 8 {
|
if tx.data.V.BitLen() > 8 {
|
||||||
return nil, ErrInvalidSig
|
return nil, ErrInvalidSig
|
||||||
}
|
}
|
||||||
V := byte(tx.data.V.Uint64())
|
V := byte(tx.data.V.Uint64() - 27)
|
||||||
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
||||||
return nil, ErrInvalidSig
|
return nil, ErrInvalidSig
|
||||||
}
|
}
|
||||||
|
|
@ -252,7 +223,7 @@ func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
sig := make([]byte, 65)
|
sig := make([]byte, 65)
|
||||||
copy(sig[32-len(r):32], r)
|
copy(sig[32-len(r):32], r)
|
||||||
copy(sig[64-len(s):64], s)
|
copy(sig[64-len(s):64], s)
|
||||||
sig[64] = V - 27
|
sig[64] = V
|
||||||
|
|
||||||
// recover the public key from the snature
|
// recover the public key from the snature
|
||||||
hash := hs.Hash(tx)
|
hash := hs.Hash(tx)
|
||||||
|
|
@ -273,8 +244,8 @@ func (s FrontierSigner) Equal(s2 Signer) bool {
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSignature returns a new transaction with the given snature.
|
// WithSignature returns a new transaction with the given signature. This signature
|
||||||
// This snature needs to be formatted as described in the yellow paper (v+27).
|
// needs to be in the [R || S || V] format where V is 0 or 1.
|
||||||
func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
||||||
if len(sig) != 65 {
|
if len(sig) != 65 {
|
||||||
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
||||||
|
|
@ -282,19 +253,10 @@ func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transactio
|
||||||
cpy := &Transaction{data: tx.data}
|
cpy := &Transaction{data: tx.data}
|
||||||
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
||||||
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
||||||
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
|
||||||
return cpy, nil
|
return cpy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs FrontierSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
|
||||||
h := fs.Hash(tx)
|
|
||||||
sig, err := crypto.SignEthereum(h[:], prv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return fs.WithSignature(tx, sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be sned by the sender.
|
// Hash returns the hash to be sned by the sender.
|
||||||
// It does not uniquely identify the transaction.
|
// It does not uniquely identify the transaction.
|
||||||
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
||||||
|
|
@ -313,7 +275,7 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
return nil, ErrInvalidSig
|
return nil, ErrInvalidSig
|
||||||
}
|
}
|
||||||
|
|
||||||
V := byte(tx.data.V.Uint64())
|
V := byte(tx.data.V.Uint64() - 27)
|
||||||
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) {
|
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) {
|
||||||
return nil, ErrInvalidSig
|
return nil, ErrInvalidSig
|
||||||
}
|
}
|
||||||
|
|
@ -322,7 +284,7 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
sig := make([]byte, 65)
|
sig := make([]byte, 65)
|
||||||
copy(sig[32-len(r):32], r)
|
copy(sig[32-len(r):32], r)
|
||||||
copy(sig[64-len(s):64], s)
|
copy(sig[64-len(s):64], s)
|
||||||
sig[64] = V - 27
|
sig[64] = V
|
||||||
|
|
||||||
// recover the public key from the snature
|
// recover the public key from the snature
|
||||||
hash := fs.Hash(tx)
|
hash := fs.Hash(tx)
|
||||||
|
|
@ -336,18 +298,6 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
return pub, nil
|
return pub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// normaliseV returns the Ethereum version of the V parameter
|
|
||||||
func normaliseV(s Signer, v *big.Int) byte {
|
|
||||||
if s, ok := s.(EIP155Signer); ok {
|
|
||||||
stdV := v.BitLen() <= 8 && (v.Uint64() == 27 || v.Uint64() == 28)
|
|
||||||
if s.chainId.BitLen() > 0 && !stdV {
|
|
||||||
nv := byte((new(big.Int).Sub(v, s.chainIdMul).Uint64()) - 35 + 27)
|
|
||||||
return nv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return byte(v.Uint64())
|
|
||||||
}
|
|
||||||
|
|
||||||
// deriveChainId derives the chain id from the given v parameter
|
// deriveChainId derives the chain id from the given v parameter
|
||||||
func deriveChainId(v *big.Int) *big.Int {
|
func deriveChainId(v *big.Int) *big.Int {
|
||||||
if v.BitLen() <= 64 {
|
if v.BitLen() <= 64 {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ func TestEIP155Signing(t *testing.T) {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
signer := NewEIP155Signer(big.NewInt(18))
|
signer := NewEIP155Signer(big.NewInt(18))
|
||||||
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key)
|
tx, err := SignTx(NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil), signer, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ func TestEIP155ChainId(t *testing.T) {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
signer := NewEIP155Signer(big.NewInt(18))
|
signer := NewEIP155Signer(big.NewInt(18))
|
||||||
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key)
|
tx, err := SignTx(NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil), signer, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +62,7 @@ func TestEIP155ChainId(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil)
|
tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil)
|
||||||
tx, err = tx.SignECDSA(HomesteadSigner{}, key)
|
tx, err = SignTx(tx, HomesteadSigner{}, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +121,7 @@ func TestChainId(t *testing.T) {
|
||||||
tx := NewTransaction(0, common.Address{}, new(big.Int), new(big.Int), new(big.Int), nil)
|
tx := NewTransaction(0, common.Address{}, new(big.Int), new(big.Int), new(big.Int), nil)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
tx, err = tx.SignECDSA(NewEIP155Signer(big.NewInt(1)), key)
|
tx, err = SignTx(tx, NewEIP155Signer(big.NewInt(1)), key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ var (
|
||||||
common.FromHex("5544"),
|
common.FromHex("5544"),
|
||||||
).WithSignature(
|
).WithSignature(
|
||||||
HomesteadSigner{},
|
HomesteadSigner{},
|
||||||
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"),
|
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
||||||
for start, key := range keys {
|
for start, key := range keys {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
for i := 0; i < 25; i++ {
|
for i := 0; i < 25; i++ {
|
||||||
tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(signer, key)
|
tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil), signer, key)
|
||||||
groups[addr] = append(groups[addr], tx)
|
groups[addr] = append(groups[addr], tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,84 +26,59 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrecompiledAccount represents a native ethereum contract
|
// Precompiled contract is the basic interface for native Go contracts. The implementation
|
||||||
type PrecompiledAccount struct {
|
// requires a deterministic gas count based on the input size of the Run method of the
|
||||||
Gas func(l int) *big.Int
|
// contract.
|
||||||
fn func(in []byte) []byte
|
type PrecompiledContract interface {
|
||||||
}
|
RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
|
||||||
|
Run(input []byte) []byte // Run runs the precompiled contract
|
||||||
// Call calls the native function
|
|
||||||
func (self PrecompiledAccount) Call(in []byte) []byte {
|
|
||||||
return self.fn(in)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Precompiled contains the default set of ethereum contracts
|
// Precompiled contains the default set of ethereum contracts
|
||||||
var Precompiled = PrecompiledContracts()
|
var PrecompiledContracts = map[common.Address]PrecompiledContract{
|
||||||
|
common.BytesToAddress([]byte{1}): &ecrecover{},
|
||||||
|
common.BytesToAddress([]byte{2}): &sha256{},
|
||||||
|
common.BytesToAddress([]byte{3}): &ripemd160{},
|
||||||
|
common.BytesToAddress([]byte{4}): &dataCopy{},
|
||||||
|
}
|
||||||
|
|
||||||
// PrecompiledContracts returns the default set of precompiled ethereum
|
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
||||||
// contracts defined by the ethereum yellow paper.
|
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
||||||
func PrecompiledContracts() map[string]*PrecompiledAccount {
|
gas := p.RequiredGas(len(input))
|
||||||
return map[string]*PrecompiledAccount{
|
if contract.UseGas(gas) {
|
||||||
// ECRECOVER
|
ret = p.Run(input)
|
||||||
string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
|
||||||
return params.EcrecoverGas
|
|
||||||
}, ecrecoverFunc},
|
|
||||||
|
|
||||||
// SHA256
|
return ret, nil
|
||||||
string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
} else {
|
||||||
n := big.NewInt(int64(l+31) / 32)
|
return nil, ErrOutOfGas
|
||||||
n.Mul(n, params.Sha256WordGas)
|
|
||||||
return n.Add(n, params.Sha256Gas)
|
|
||||||
}, sha256Func},
|
|
||||||
|
|
||||||
// RIPEMD160
|
|
||||||
string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
|
||||||
n := big.NewInt(int64(l+31) / 32)
|
|
||||||
n.Mul(n, params.Ripemd160WordGas)
|
|
||||||
return n.Add(n, params.Ripemd160Gas)
|
|
||||||
}, ripemd160Func},
|
|
||||||
|
|
||||||
string(common.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
|
|
||||||
n := big.NewInt(int64(l+31) / 32)
|
|
||||||
n.Mul(n, params.IdentityWordGas)
|
|
||||||
|
|
||||||
return n.Add(n, params.IdentityGas)
|
|
||||||
}, memCpy},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sha256Func(in []byte) []byte {
|
// ECRECOVER implemented as a native contract
|
||||||
return crypto.Sha256(in)
|
type ecrecover struct{}
|
||||||
|
|
||||||
|
func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
|
||||||
|
return params.EcrecoverGas
|
||||||
}
|
}
|
||||||
|
|
||||||
func ripemd160Func(in []byte) []byte {
|
func (c *ecrecover) Run(in []byte) []byte {
|
||||||
return common.LeftPadBytes(crypto.Ripemd160(in), 32)
|
const ecRecoverInputLength = 128
|
||||||
}
|
|
||||||
|
|
||||||
const ecRecoverInputLength = 128
|
in = common.RightPadBytes(in, ecRecoverInputLength)
|
||||||
|
|
||||||
func ecrecoverFunc(in []byte) []byte {
|
|
||||||
in = common.RightPadBytes(in, 128)
|
|
||||||
// "in" is (hash, v, r, s), each 32 bytes
|
// "in" is (hash, v, r, s), each 32 bytes
|
||||||
// but for ecrecover we want (r, s, v)
|
// but for ecrecover we want (r, s, v)
|
||||||
|
|
||||||
r := common.BytesToBig(in[64:96])
|
r := common.BytesToBig(in[64:96])
|
||||||
s := common.BytesToBig(in[96:128])
|
s := common.BytesToBig(in[96:128])
|
||||||
// Treat V as a 256bit integer
|
v := in[63] - 27
|
||||||
vbig := common.Bytes2Big(in[32:64])
|
|
||||||
v := byte(vbig.Uint64())
|
|
||||||
|
|
||||||
// tighter sig s values in homestead only apply to tx sigs
|
// tighter sig s values in homestead only apply to tx sigs
|
||||||
if !crypto.ValidateSignatureValues(v, r, s, false) {
|
if common.Bytes2Big(in[32:63]).BitLen() > 0 || !crypto.ValidateSignatureValues(v, r, s, false) {
|
||||||
glog.V(logger.Detail).Infof("ECRECOVER error: v, r or s value invalid")
|
glog.V(logger.Detail).Infof("ECRECOVER error: v, r or s value invalid")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// v needs to be at the end for libsecp256k1
|
||||||
// v needs to be at the end and normalized for libsecp256k1
|
pubKey, err := crypto.Ecrecover(in[:32], append(in[64:128], v))
|
||||||
vbignormal := new(big.Int).Sub(vbig, big.NewInt(27))
|
|
||||||
vnormal := byte(vbignormal.Uint64())
|
|
||||||
rsv := append(in[64:128], vnormal)
|
|
||||||
pubKey, err := crypto.Ecrecover(in[:32], rsv)
|
|
||||||
// make sure the public key is a valid one
|
// make sure the public key is a valid one
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(logger.Detail).Infoln("ECRECOVER error: ", err)
|
glog.V(logger.Detail).Infoln("ECRECOVER error: ", err)
|
||||||
|
|
@ -114,6 +89,39 @@ func ecrecoverFunc(in []byte) []byte {
|
||||||
return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32)
|
return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
func memCpy(in []byte) []byte {
|
// SHA256 implemented as a native contract
|
||||||
|
type sha256 struct{}
|
||||||
|
|
||||||
|
func (c *sha256) RequiredGas(inputSize int) *big.Int {
|
||||||
|
n := big.NewInt(int64(inputSize+31) / 32)
|
||||||
|
n.Mul(n, params.Sha256WordGas)
|
||||||
|
return n.Add(n, params.Sha256Gas)
|
||||||
|
}
|
||||||
|
func (c *sha256) Run(in []byte) []byte {
|
||||||
|
return crypto.Sha256(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RIPMED160 implemented as a native contract
|
||||||
|
type ripemd160 struct{}
|
||||||
|
|
||||||
|
func (c *ripemd160) RequiredGas(inputSize int) *big.Int {
|
||||||
|
n := big.NewInt(int64(inputSize+31) / 32)
|
||||||
|
n.Mul(n, params.Ripemd160WordGas)
|
||||||
|
return n.Add(n, params.Ripemd160Gas)
|
||||||
|
}
|
||||||
|
func (c *ripemd160) Run(in []byte) []byte {
|
||||||
|
return common.LeftPadBytes(crypto.Ripemd160(in), 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
// data copy implemented as a native contract
|
||||||
|
type dataCopy struct{}
|
||||||
|
|
||||||
|
func (c *dataCopy) RequiredGas(inputSize int) *big.Int {
|
||||||
|
n := big.NewInt(int64(inputSize+31) / 32)
|
||||||
|
n.Mul(n, params.IdentityWordGas)
|
||||||
|
|
||||||
|
return n.Add(n, params.IdentityGas)
|
||||||
|
}
|
||||||
|
func (c *dataCopy) Run(in []byte) []byte {
|
||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package vm
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -33,7 +34,7 @@ type (
|
||||||
GetHashFunc func(uint64) common.Hash
|
GetHashFunc func(uint64) common.Hash
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context provides the EVM with auxilary information. Once provided it shouldn't be modified.
|
// Context provides the EVM with auxiliary information. Once provided it shouldn't be modified.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
// CanTransfer returns whether the account contains
|
// CanTransfer returns whether the account contains
|
||||||
// sufficient ether to transfer the value
|
// sufficient ether to transfer the value
|
||||||
|
|
@ -55,41 +56,54 @@ type Context struct {
|
||||||
Difficulty *big.Int // Provides information for DIFFICULTY
|
Difficulty *big.Int // Provides information for DIFFICULTY
|
||||||
}
|
}
|
||||||
|
|
||||||
// Environment provides information about external sources for the EVM
|
// EVM provides information about external sources for the EVM
|
||||||
//
|
//
|
||||||
// The Environment should never be reused and is not thread safe.
|
// The EVM should never be reused and is not thread safe.
|
||||||
type Environment struct {
|
type EVM struct {
|
||||||
// Context provides auxiliary blockchain related information
|
// Context provides auxiliary blockchain related information
|
||||||
Context
|
Context
|
||||||
// StateDB gives access to the underlying state
|
// StateDB gives access to the underlying state
|
||||||
StateDB StateDB
|
StateDB StateDB
|
||||||
// Depth is the current call stack
|
// Depth is the current call stack
|
||||||
Depth int
|
depth int
|
||||||
|
|
||||||
// evm is the ethereum virtual machine
|
|
||||||
evm Vm
|
|
||||||
// chainConfig contains information about the current chain
|
// chainConfig contains information about the current chain
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
vmConfig Config
|
// virtual machine configuration options used to initialise the
|
||||||
|
// evm.
|
||||||
|
vmConfig Config
|
||||||
|
// global (to this context) ethereum virtual machine
|
||||||
|
// used throughout the execution of the tx.
|
||||||
|
interpreter *Interpreter
|
||||||
|
// abort is used to abort the EVM calling operations
|
||||||
|
// NOTE: must be set atomically
|
||||||
|
abort int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnvironment retutrns a new EVM environment.
|
// NewEVM retutrns a new EVM evmironment.
|
||||||
func NewEnvironment(context Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *Environment {
|
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
|
||||||
env := &Environment{
|
evm := &EVM{
|
||||||
Context: context,
|
Context: ctx,
|
||||||
StateDB: statedb,
|
StateDB: statedb,
|
||||||
vmConfig: vmConfig,
|
vmConfig: vmConfig,
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
}
|
}
|
||||||
env.evm = New(env, vmConfig)
|
|
||||||
return env
|
evm.interpreter = NewInterpreter(evm, vmConfig)
|
||||||
|
return evm
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call executes the contract associated with the addr with the given input as paramaters. It also handles any
|
// Cancel cancels any running EVM operation. This may be called concurrently and it's safe to be
|
||||||
|
// called multiple times.
|
||||||
|
func (evm *EVM) Cancel() {
|
||||||
|
atomic.StoreInt32(&evm.abort, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
|
||||||
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
||||||
// case of an execution error or failed value transfer.
|
// case of an execution error or failed value transfer.
|
||||||
func (env *Environment) Call(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) ([]byte, error) {
|
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
|
||||||
if env.vmConfig.NoRecursion && env.Depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -97,59 +111,59 @@ func (env *Environment) Call(caller ContractRef, addr common.Address, input []by
|
||||||
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth > int(params.CallCreateDepth.Int64()) {
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, DepthError
|
return nil, ErrDepth
|
||||||
}
|
}
|
||||||
if !env.Context.CanTransfer(env.StateDB, caller.Address(), value) {
|
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, ErrInsufficientBalance
|
return nil, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
to Account
|
to Account
|
||||||
snapshotPreTransfer = env.StateDB.Snapshot()
|
snapshot = evm.StateDB.Snapshot()
|
||||||
)
|
)
|
||||||
if !env.StateDB.Exist(addr) {
|
if !evm.StateDB.Exist(addr) {
|
||||||
if Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber) && value.BitLen() == 0 {
|
if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.BitLen() == 0 {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
to = env.StateDB.CreateAccount(addr)
|
to = evm.StateDB.CreateAccount(addr)
|
||||||
} else {
|
} else {
|
||||||
to = env.StateDB.GetAccount(addr)
|
to = evm.StateDB.GetAccount(addr)
|
||||||
}
|
}
|
||||||
env.Transfer(env.StateDB, caller.Address(), to.Address(), value)
|
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
||||||
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped environment for this execution context
|
// E The contract is a scoped evmironment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := NewContract(caller, to, value, gas)
|
contract := NewContract(caller, to, value, gas)
|
||||||
contract.SetCallCode(&addr, env.StateDB.GetCodeHash(addr), env.StateDB.GetCode(addr))
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
defer contract.Finalise()
|
defer contract.Finalise()
|
||||||
|
|
||||||
ret, err := env.EVM().Run(contract, input)
|
ret, err = evm.interpreter.Run(contract, input)
|
||||||
// When an error was returned by the EVM or when setting the creation code
|
// When an error was returned by the EVM or when setting the creation code
|
||||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||||
// when we're in homestead this also counts for code storage gas errors.
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
env.StateDB.RevertToSnapshot(snapshotPreTransfer)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallCode executes the contract associated with the addr with the given input as paramaters. It also handles any
|
// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
|
||||||
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
||||||
// case of an execution error or failed value transfer.
|
// case of an execution error or failed value transfer.
|
||||||
//
|
//
|
||||||
// CallCode differs from Call in the sense that it executes the given address' code with the caller as context.
|
// CallCode differs from Call in the sense that it executes the given address' code with the caller as context.
|
||||||
func (env *Environment) CallCode(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) ([]byte, error) {
|
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
|
||||||
if env.vmConfig.NoRecursion && env.Depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -157,45 +171,45 @@ func (env *Environment) CallCode(caller ContractRef, addr common.Address, input
|
||||||
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth > int(params.CallCreateDepth.Int64()) {
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, DepthError
|
return nil, ErrDepth
|
||||||
}
|
}
|
||||||
if !env.CanTransfer(env.StateDB, caller.Address(), value) {
|
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", value, env.StateDB.GetBalance(caller.Address()))
|
return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", value, evm.StateDB.GetBalance(caller.Address()))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
snapshotPreTransfer = env.StateDB.Snapshot()
|
snapshot = evm.StateDB.Snapshot()
|
||||||
to = env.StateDB.GetAccount(caller.Address())
|
to = evm.StateDB.GetAccount(caller.Address())
|
||||||
)
|
)
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped environment for this execution context
|
// E The contract is a scoped evmironment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := NewContract(caller, to, value, gas)
|
contract := NewContract(caller, to, value, gas)
|
||||||
contract.SetCallCode(&addr, env.StateDB.GetCodeHash(addr), env.StateDB.GetCode(addr))
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
defer contract.Finalise()
|
defer contract.Finalise()
|
||||||
|
|
||||||
ret, err := env.EVM().Run(contract, input)
|
ret, err = evm.interpreter.Run(contract, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
env.StateDB.RevertToSnapshot(snapshotPreTransfer)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelegateCall executes the contract associated with the addr with the given input as paramaters.
|
// DelegateCall executes the contract associated with the addr with the given input as parameters.
|
||||||
// It reverses the state in case of an execution error.
|
// It reverses the state in case of an execution error.
|
||||||
//
|
//
|
||||||
// DelegateCall differs from CallCode in the sense that it executes the given address' code with the caller as context
|
// DelegateCall differs from CallCode in the sense that it executes the given address' code with the caller as context
|
||||||
// and the caller is set to the caller of the caller.
|
// and the caller is set to the caller of the caller.
|
||||||
func (env *Environment) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas *big.Int) ([]byte, error) {
|
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas *big.Int) (ret []byte, err error) {
|
||||||
if env.vmConfig.NoRecursion && env.Depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -203,34 +217,34 @@ func (env *Environment) DelegateCall(caller ContractRef, addr common.Address, in
|
||||||
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth > int(params.CallCreateDepth.Int64()) {
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
return nil, DepthError
|
return nil, ErrDepth
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
snapshot = env.StateDB.Snapshot()
|
snapshot = evm.StateDB.Snapshot()
|
||||||
to = env.StateDB.GetAccount(caller.Address())
|
to = evm.StateDB.GetAccount(caller.Address())
|
||||||
)
|
)
|
||||||
|
|
||||||
// Iinitialise a new contract and make initialise the delegate values
|
// Iinitialise a new contract and make initialise the delegate values
|
||||||
contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
|
contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
|
||||||
contract.SetCallCode(&addr, env.StateDB.GetCodeHash(addr), env.StateDB.GetCode(addr))
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
defer contract.Finalise()
|
defer contract.Finalise()
|
||||||
|
|
||||||
ret, err := env.EVM().Run(contract, input)
|
ret, err = evm.interpreter.Run(contract, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
env.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new contract using code as deployment code.
|
// Create creates a new contract using code as deployment code.
|
||||||
func (env *Environment) Create(caller ContractRef, code []byte, gas, value *big.Int) ([]byte, common.Address, error) {
|
func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (ret []byte, contractAddr common.Address, err error) {
|
||||||
if env.vmConfig.NoRecursion && env.Depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, common.Address{}, nil
|
return nil, common.Address{}, nil
|
||||||
|
|
@ -238,39 +252,38 @@ func (env *Environment) Create(caller ContractRef, code []byte, gas, value *big.
|
||||||
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth > int(params.CallCreateDepth.Int64()) {
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, common.Address{}, DepthError
|
return nil, common.Address{}, ErrDepth
|
||||||
}
|
}
|
||||||
if !env.CanTransfer(env.StateDB, caller.Address(), value) {
|
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
caller.ReturnGas(gas)
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
return nil, common.Address{}, ErrInsufficientBalance
|
return nil, common.Address{}, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new account on the state
|
// Create a new account on the state
|
||||||
nonce := env.StateDB.GetNonce(caller.Address())
|
nonce := evm.StateDB.GetNonce(caller.Address())
|
||||||
env.StateDB.SetNonce(caller.Address(), nonce+1)
|
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||||
|
|
||||||
snapshotPreTransfer := env.StateDB.Snapshot()
|
snapshot := evm.StateDB.Snapshot()
|
||||||
var (
|
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
|
||||||
addr = crypto.CreateAddress(caller.Address(), nonce)
|
to := evm.StateDB.CreateAccount(contractAddr)
|
||||||
to = env.StateDB.CreateAccount(addr)
|
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||||
)
|
evm.StateDB.SetNonce(contractAddr, 1)
|
||||||
if env.ChainConfig().IsEIP158(env.BlockNumber) {
|
|
||||||
env.StateDB.SetNonce(addr, 1)
|
|
||||||
}
|
}
|
||||||
env.Transfer(env.StateDB, caller.Address(), to.Address(), value)
|
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
||||||
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped environment for this execution context
|
// E The contract is a scoped evmironment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := NewContract(caller, to, value, gas)
|
contract := NewContract(caller, to, value, gas)
|
||||||
contract.SetCallCode(&addr, crypto.Keccak256Hash(code), code)
|
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
||||||
defer contract.Finalise()
|
defer contract.Finalise()
|
||||||
|
|
||||||
ret, err := env.EVM().Run(contract, nil)
|
ret, err = evm.interpreter.Run(contract, nil)
|
||||||
|
|
||||||
// check whether the max code size has been exceeded
|
// check whether the max code size has been exceeded
|
||||||
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
|
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
|
||||||
// if the contract creation ran successfully and no errors were returned
|
// if the contract creation ran successfully and no errors were returned
|
||||||
|
|
@ -281,9 +294,9 @@ func (env *Environment) Create(caller ContractRef, code []byte, gas, value *big.
|
||||||
dataGas := big.NewInt(int64(len(ret)))
|
dataGas := big.NewInt(int64(len(ret)))
|
||||||
dataGas.Mul(dataGas, params.CreateDataGas)
|
dataGas.Mul(dataGas, params.CreateDataGas)
|
||||||
if contract.UseGas(dataGas) {
|
if contract.UseGas(dataGas) {
|
||||||
env.StateDB.SetCode(addr, ret)
|
evm.StateDB.SetCode(contractAddr, ret)
|
||||||
} else {
|
} else {
|
||||||
err = CodeStoreOutOfGasError
|
err = ErrCodeStoreOutOfGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,12 +304,12 @@ func (env *Environment) Create(caller ContractRef, code []byte, gas, value *big.
|
||||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||||
// when we're in homestead this also counts for code storage gas errors.
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
if maxCodeSizeExceeded ||
|
if maxCodeSizeExceeded ||
|
||||||
(err != nil && (env.ChainConfig().IsHomestead(env.BlockNumber) || err != CodeStoreOutOfGasError)) {
|
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
env.StateDB.RevertToSnapshot(snapshotPreTransfer)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
// Nothing should be returned when an error is thrown.
|
// Nothing should be returned when an error is thrown.
|
||||||
return nil, addr, err
|
return nil, contractAddr, err
|
||||||
}
|
}
|
||||||
// If the vm returned with an error the return value should be set to nil.
|
// If the vm returned with an error the return value should be set to nil.
|
||||||
// This isn't consensus critical but merely to for behaviour reasons such as
|
// This isn't consensus critical but merely to for behaviour reasons such as
|
||||||
|
|
@ -305,11 +318,11 @@ func (env *Environment) Create(caller ContractRef, code []byte, gas, value *big.
|
||||||
ret = nil
|
ret = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, addr, err
|
return ret, contractAddr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainConfig returns the environment's chain configuration
|
// ChainConfig returns the evmironment's chain configuration
|
||||||
func (env *Environment) ChainConfig() *params.ChainConfig { return env.chainConfig }
|
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||||
|
|
||||||
// EVM returns the environments EVM
|
// Interpreter returns the EVM interpreter
|
||||||
func (env *Environment) EVM() Vm { return env.evm }
|
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,12 @@
|
||||||
|
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import "errors"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
OutOfGasError = errors.New("Out of gas")
|
ErrOutOfGas = errors.New("out of gas")
|
||||||
CodeStoreOutOfGasError = errors.New("Contract creation code storage out of gas")
|
ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas")
|
||||||
DepthError = fmt.Errorf("Max call depth exceeded (%d)", params.CallCreateDepth)
|
ErrDepth = errors.New("max call depth exceeded")
|
||||||
TraceLimitReachedError = errors.New("The number of logs reached the specified limit")
|
ErrTraceLimitReached = errors.New("the number of logs reached the specified limit")
|
||||||
ErrInsufficientBalance = errors.New("insufficient balance for transfer")
|
ErrInsufficientBalance = errors.New("insufficient balance for transfer")
|
||||||
)
|
)
|
||||||
|
|
|
||||||
246
core/vm/gas_table.go
Normal file
246
core/vm/gas_table.go
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int {
|
||||||
|
gas := new(big.Int)
|
||||||
|
if newMemSize.Cmp(common.Big0) > 0 {
|
||||||
|
newMemSizeWords := toWordSize(newMemSize)
|
||||||
|
|
||||||
|
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
|
||||||
|
// be careful reusing variables here when changing.
|
||||||
|
// The order has been optimised to reduce allocation
|
||||||
|
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
|
||||||
|
pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
|
||||||
|
linCoef := oldSize.Mul(oldSize, params.MemoryGas)
|
||||||
|
quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
|
||||||
|
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
|
||||||
|
|
||||||
|
pow.Exp(newMemSizeWords, common.Big2, Zero)
|
||||||
|
linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
|
||||||
|
quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
|
||||||
|
newTotalFee := linCoef.Add(linCoef, quadCoef)
|
||||||
|
|
||||||
|
fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
|
||||||
|
gas.Add(gas, fee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gas
|
||||||
|
}
|
||||||
|
|
||||||
|
func constGasFunc(gas *big.Int) gasFunc {
|
||||||
|
return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return gas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := memoryGasCost(mem, memorySize)
|
||||||
|
gas.Add(gas, GasFastestStep)
|
||||||
|
words := toWordSize(stack.Back(2))
|
||||||
|
|
||||||
|
return gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
var (
|
||||||
|
y, x = stack.Back(1), stack.Back(0)
|
||||||
|
val = env.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
||||||
|
)
|
||||||
|
// This checks for 3 scenario's and calculates gas accordingly
|
||||||
|
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||||
|
// 2. From a non-zero value address to a zero-value address (DELETE)
|
||||||
|
// 3. From a non-zero to a non-zero (CHANGE)
|
||||||
|
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
|
||||||
|
// 0 => non 0
|
||||||
|
return new(big.Int).Set(params.SstoreSetGas)
|
||||||
|
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
|
||||||
|
env.StateDB.AddRefund(params.SstoreRefundGas)
|
||||||
|
|
||||||
|
return new(big.Int).Set(params.SstoreClearGas)
|
||||||
|
} else {
|
||||||
|
// non 0 => non 0 (or 0 => 0)
|
||||||
|
return new(big.Int).Set(params.SstoreResetGas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeGasLog(n uint) gasFunc {
|
||||||
|
return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
mSize := stack.Back(1)
|
||||||
|
|
||||||
|
gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas)
|
||||||
|
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
|
||||||
|
gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
|
||||||
|
return gas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := memoryGasCost(mem, memorySize)
|
||||||
|
gas.Add(gas, params.Sha3Gas)
|
||||||
|
words := toWordSize(stack.Back(1))
|
||||||
|
return gas.Add(gas, words.Mul(words, params.Sha3WordGas))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := memoryGasCost(mem, memorySize)
|
||||||
|
gas.Add(gas, GasFastestStep)
|
||||||
|
words := toWordSize(stack.Back(2))
|
||||||
|
|
||||||
|
return gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := memoryGasCost(mem, memorySize)
|
||||||
|
gas.Add(gas, gt.ExtcodeCopy)
|
||||||
|
words := toWordSize(stack.Back(3))
|
||||||
|
|
||||||
|
return gas.Add(gas, words.Mul(words, params.CopyGas))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize))
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return gt.Balance
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return gt.ExtcodeSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return gt.SLoad
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
||||||
|
gas := big.NewInt(expByteLen)
|
||||||
|
gas.Mul(gas, gt.ExpByte)
|
||||||
|
return gas.Add(gas, GasSlowStep)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := new(big.Int).Set(gt.Calls)
|
||||||
|
|
||||||
|
transfersValue := stack.Back(2).BitLen() > 0
|
||||||
|
var (
|
||||||
|
address = common.BigToAddress(stack.Back(1))
|
||||||
|
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
|
||||||
|
)
|
||||||
|
if eip158 {
|
||||||
|
if env.StateDB.Empty(address) && transfersValue {
|
||||||
|
gas.Add(gas, params.CallNewAccountGas)
|
||||||
|
}
|
||||||
|
} else if !env.StateDB.Exist(address) {
|
||||||
|
gas.Add(gas, params.CallNewAccountGas)
|
||||||
|
}
|
||||||
|
if transfersValue {
|
||||||
|
gas.Add(gas, params.CallValueTransferGas)
|
||||||
|
}
|
||||||
|
gas.Add(gas, memoryGasCost(mem, memorySize))
|
||||||
|
|
||||||
|
cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
|
||||||
|
// Replace the stack item with the new gas calculation. This means that
|
||||||
|
// either the original item is left on the stack or the item is replaced by:
|
||||||
|
// (availableGas - gas) * 63 / 64
|
||||||
|
// We replace the stack item so that it's available when the opCall instruction is
|
||||||
|
// called. This information is otherwise lost due to the dependency on *current*
|
||||||
|
// available gas.
|
||||||
|
stack.data[stack.len()-1] = cg
|
||||||
|
|
||||||
|
return gas.Add(gas, cg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := new(big.Int).Set(gt.Calls)
|
||||||
|
if stack.Back(2).BitLen() > 0 {
|
||||||
|
gas.Add(gas, params.CallValueTransferGas)
|
||||||
|
}
|
||||||
|
gas.Add(gas, memoryGasCost(mem, memorySize))
|
||||||
|
|
||||||
|
cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
|
||||||
|
// Replace the stack item with the new gas calculation. This means that
|
||||||
|
// either the original item is left on the stack or the item is replaced by:
|
||||||
|
// (availableGas - gas) * 63 / 64
|
||||||
|
// We replace the stack item so that it's available when the opCall instruction is
|
||||||
|
// called. This information is otherwise lost due to the dependency on *current*
|
||||||
|
// available gas.
|
||||||
|
stack.data[stack.len()-1] = cg
|
||||||
|
|
||||||
|
return gas.Add(gas, cg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasReturn(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return memoryGasCost(mem, memorySize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := new(big.Int)
|
||||||
|
// EIP150 homestead gas reprice fork:
|
||||||
|
if env.ChainConfig().IsEIP150(env.BlockNumber) {
|
||||||
|
gas.Set(gt.Suicide)
|
||||||
|
var (
|
||||||
|
address = common.BigToAddress(stack.Back(0))
|
||||||
|
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber)
|
||||||
|
)
|
||||||
|
|
||||||
|
if eip158 {
|
||||||
|
// if empty and transfers value
|
||||||
|
if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 {
|
||||||
|
gas.Add(gas, gt.CreateBySuicide)
|
||||||
|
}
|
||||||
|
} else if !env.StateDB.Exist(address) {
|
||||||
|
gas.Add(gas, gt.CreateBySuicide)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !env.StateDB.HasSuicided(contract.Address()) {
|
||||||
|
env.StateDB.AddRefund(params.SuicideRefundGas)
|
||||||
|
}
|
||||||
|
return gas
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize))
|
||||||
|
|
||||||
|
cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1])
|
||||||
|
// Replace the stack item with the new gas calculation. This means that
|
||||||
|
// either the original item is left on the stack or the item is replaced by:
|
||||||
|
// (availableGas - gas) * 63 / 64
|
||||||
|
// We replace the stack item so that it's available when the opCall instruction is
|
||||||
|
// called.
|
||||||
|
stack.data[stack.len()-1] = cg
|
||||||
|
|
||||||
|
return gas.Add(gas, cg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return GasFastestStep
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return GasFastestStep
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int {
|
||||||
|
return GasFastestStep
|
||||||
|
}
|
||||||
|
|
@ -22,132 +22,44 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
type programInstruction interface {
|
func opAdd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// executes the program instruction and allows the instruction to modify the state of the program
|
x, y := stack.pop(), stack.pop()
|
||||||
do(program *Program, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
|
stack.push(U256(x.Add(x, y)))
|
||||||
// returns whether the program instruction halts the execution of the JIT
|
|
||||||
halts() bool
|
|
||||||
// Returns the current op code (debugging purposes)
|
|
||||||
Op() OpCode
|
|
||||||
}
|
|
||||||
|
|
||||||
type instrFn func(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack)
|
|
||||||
|
|
||||||
type instruction struct {
|
|
||||||
op OpCode
|
|
||||||
pc uint64
|
|
||||||
fn instrFn
|
|
||||||
data *big.Int
|
|
||||||
|
|
||||||
gas *big.Int
|
|
||||||
spop int
|
|
||||||
spush int
|
|
||||||
|
|
||||||
returns bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func jump(mapping map[uint64]uint64, destinations map[uint64]struct{}, contract *Contract, to *big.Int) (uint64, error) {
|
|
||||||
if !validDest(destinations, to) {
|
|
||||||
nop := contract.GetOp(to.Uint64())
|
|
||||||
return 0, fmt.Errorf("invalid jump destination (%v) %v", nop, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapping[to.Uint64()], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (instr instruction) do(program *Program, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
|
||||||
// calculate the new memory size and gas price for the current executing opcode
|
|
||||||
newMemSize, cost, err := jitCalculateGasAndSize(env, contract, instr, memory, stack)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the calculated gas. When insufficient gas is present, use all gas and return an
|
|
||||||
// Out Of Gas error
|
|
||||||
if !contract.UseGas(cost) {
|
|
||||||
return nil, OutOfGasError
|
|
||||||
}
|
|
||||||
// Resize the memory calculated previously
|
|
||||||
memory.Resize(newMemSize.Uint64())
|
|
||||||
|
|
||||||
// These opcodes return an argument and are therefor handled
|
|
||||||
// differently from the rest of the opcodes
|
|
||||||
switch instr.op {
|
|
||||||
case JUMP:
|
|
||||||
if pos, err := jump(program.mapping, program.destinations, contract, stack.pop()); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
*pc = pos
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
case JUMPI:
|
|
||||||
pos, cond := stack.pop(), stack.pop()
|
|
||||||
if cond.Cmp(common.BigTrue) >= 0 {
|
|
||||||
if pos, err := jump(program.mapping, program.destinations, contract, pos); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
*pc = pos
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case RETURN:
|
|
||||||
offset, size := stack.pop(), stack.pop()
|
|
||||||
return memory.GetPtr(offset.Int64(), size.Int64()), nil
|
|
||||||
default:
|
|
||||||
if instr.fn == nil {
|
|
||||||
return nil, fmt.Errorf("Invalid opcode 0x%x", instr.op)
|
|
||||||
}
|
|
||||||
instr.fn(instr, pc, env, contract, memory, stack)
|
|
||||||
}
|
|
||||||
*pc++
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (instr instruction) halts() bool {
|
func opSub(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
return instr.returns
|
|
||||||
}
|
|
||||||
|
|
||||||
func (instr instruction) Op() OpCode {
|
|
||||||
return instr.op
|
|
||||||
}
|
|
||||||
|
|
||||||
func opStaticJump(instr instruction, pc *uint64, ret *big.Int, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
|
||||||
ret.Set(instr.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func opAdd(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
|
||||||
x, y := stack.pop(), stack.pop()
|
|
||||||
stack.push(U256(x.Add(x, y)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func opSub(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
stack.push(U256(x.Sub(x, y)))
|
stack.push(U256(x.Sub(x, y)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMul(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opMul(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
stack.push(U256(x.Mul(x, y)))
|
stack.push(U256(x.Mul(x, y)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDiv(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opDiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
if y.Cmp(common.Big0) != 0 {
|
if y.Cmp(common.Big0) != 0 {
|
||||||
stack.push(U256(x.Div(x, y)))
|
stack.push(U256(x.Div(x, y)))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSdiv(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
if y.Cmp(common.Big0) == 0 {
|
if y.Cmp(common.Big0) == 0 {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
return
|
return nil, nil
|
||||||
} else {
|
} else {
|
||||||
n := new(big.Int)
|
n := new(big.Int)
|
||||||
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
|
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
|
||||||
|
|
@ -161,18 +73,20 @@ func opSdiv(instr instruction, pc *uint64, env *Environment, contract *Contract,
|
||||||
|
|
||||||
stack.push(U256(res))
|
stack.push(U256(res))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMod(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opMod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
if y.Cmp(common.Big0) == 0 {
|
if y.Cmp(common.Big0) == 0 {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
} else {
|
} else {
|
||||||
stack.push(U256(x.Mod(x, y)))
|
stack.push(U256(x.Mod(x, y)))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSmod(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
|
|
||||||
if y.Cmp(common.Big0) == 0 {
|
if y.Cmp(common.Big0) == 0 {
|
||||||
|
|
@ -190,14 +104,16 @@ func opSmod(instr instruction, pc *uint64, env *Environment, contract *Contract,
|
||||||
|
|
||||||
stack.push(U256(res))
|
stack.push(U256(res))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExp(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opExp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
base, exponent := stack.pop(), stack.pop()
|
base, exponent := stack.pop(), stack.pop()
|
||||||
stack.push(math.Exp(base, exponent))
|
stack.push(math.Exp(base, exponent))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSignExtend(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
back := stack.pop()
|
back := stack.pop()
|
||||||
if back.Cmp(big.NewInt(31)) < 0 {
|
if back.Cmp(big.NewInt(31)) < 0 {
|
||||||
bit := uint(back.Uint64()*8 + 7)
|
bit := uint(back.Uint64()*8 + 7)
|
||||||
|
|
@ -212,80 +128,91 @@ func opSignExtend(instr instruction, pc *uint64, env *Environment, contract *Con
|
||||||
|
|
||||||
stack.push(U256(num))
|
stack.push(U256(num))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNot(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opNot(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x := stack.pop()
|
x := stack.pop()
|
||||||
stack.push(U256(x.Not(x)))
|
stack.push(U256(x.Not(x)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opLt(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opLt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
if x.Cmp(y) < 0 {
|
if x.Cmp(y) < 0 {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(big.NewInt(1))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGt(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opGt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
if x.Cmp(y) > 0 {
|
if x.Cmp(y) > 0 {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(big.NewInt(1))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSlt(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSlt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
if x.Cmp(S256(y)) < 0 {
|
if x.Cmp(S256(y)) < 0 {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(big.NewInt(1))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSgt(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSgt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
if x.Cmp(y) > 0 {
|
if x.Cmp(y) > 0 {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(big.NewInt(1))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opEq(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opEq(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
if x.Cmp(y) == 0 {
|
if x.Cmp(y) == 0 {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(big.NewInt(1))
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opIszero(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opIszero(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x := stack.pop()
|
x := stack.pop()
|
||||||
if x.Cmp(common.Big0) > 0 {
|
if x.Cmp(common.Big0) > 0 {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
} else {
|
} else {
|
||||||
stack.push(big.NewInt(1))
|
stack.push(big.NewInt(1))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opAnd(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opAnd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
stack.push(x.And(x, y))
|
stack.push(x.And(x, y))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opOr(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opOr(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
stack.push(x.Or(x, y))
|
stack.push(x.Or(x, y))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opXor(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opXor(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
stack.push(x.Xor(x, y))
|
stack.push(x.Xor(x, y))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opByte(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opByte(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
th, val := stack.pop(), stack.pop()
|
th, val := stack.pop(), stack.pop()
|
||||||
if th.Cmp(big.NewInt(32)) < 0 {
|
if th.Cmp(big.NewInt(32)) < 0 {
|
||||||
byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
||||||
|
|
@ -293,8 +220,9 @@ func opByte(instr instruction, pc *uint64, env *Environment, contract *Contract,
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opAddmod(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opAddmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||||
if z.Cmp(Zero) > 0 {
|
if z.Cmp(Zero) > 0 {
|
||||||
add := x.Add(x, y)
|
add := x.Add(x, y)
|
||||||
|
|
@ -303,8 +231,9 @@ func opAddmod(instr instruction, pc *uint64, env *Environment, contract *Contrac
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opMulmod(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opMulmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
||||||
if z.Cmp(Zero) > 0 {
|
if z.Cmp(Zero) > 0 {
|
||||||
mul := x.Mul(x, y)
|
mul := x.Mul(x, y)
|
||||||
|
|
@ -313,67 +242,79 @@ func opMulmod(instr instruction, pc *uint64, env *Environment, contract *Contrac
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSha3(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSha3(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
offset, size := stack.pop(), stack.pop()
|
offset, size := stack.pop(), stack.pop()
|
||||||
hash := crypto.Keccak256(memory.Get(offset.Int64(), size.Int64()))
|
hash := crypto.Keccak256(memory.Get(offset.Int64(), size.Int64()))
|
||||||
|
|
||||||
stack.push(common.BytesToBig(hash))
|
stack.push(common.BytesToBig(hash))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opAddress(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opAddress(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(common.Bytes2Big(contract.Address().Bytes()))
|
stack.push(common.Bytes2Big(contract.Address().Bytes()))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBalance(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opBalance(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
addr := common.BigToAddress(stack.pop())
|
addr := common.BigToAddress(stack.pop())
|
||||||
balance := env.StateDB.GetBalance(addr)
|
balance := env.StateDB.GetBalance(addr)
|
||||||
|
|
||||||
stack.push(new(big.Int).Set(balance))
|
stack.push(new(big.Int).Set(balance))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opOrigin(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opOrigin(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(env.Origin.Big())
|
stack.push(env.Origin.Big())
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCaller(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCaller(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(contract.Caller().Big())
|
stack.push(contract.Caller().Big())
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallValue(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCallValue(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(new(big.Int).Set(contract.value))
|
stack.push(new(big.Int).Set(contract.value))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCalldataLoad(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCalldataLoad(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(common.Bytes2Big(getData(contract.Input, stack.pop(), common.Big32)))
|
stack.push(common.Bytes2Big(getData(contract.Input, stack.pop(), common.Big32)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCalldataSize(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCalldataSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(big.NewInt(int64(len(contract.Input))))
|
stack.push(big.NewInt(int64(len(contract.Input))))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCalldataCopy(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCalldataCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
mOff = stack.pop()
|
mOff = stack.pop()
|
||||||
cOff = stack.pop()
|
cOff = stack.pop()
|
||||||
l = stack.pop()
|
l = stack.pop()
|
||||||
)
|
)
|
||||||
memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l))
|
memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeSize(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opExtCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
addr := common.BigToAddress(stack.pop())
|
addr := common.BigToAddress(stack.pop())
|
||||||
l := big.NewInt(int64(env.StateDB.GetCodeSize(addr)))
|
l := big.NewInt(int64(env.StateDB.GetCodeSize(addr)))
|
||||||
stack.push(l)
|
stack.push(l)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCodeSize(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
l := big.NewInt(int64(len(contract.Code)))
|
l := big.NewInt(int64(len(contract.Code)))
|
||||||
stack.push(l)
|
stack.push(l)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCodeCopy(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
mOff = stack.pop()
|
mOff = stack.pop()
|
||||||
cOff = stack.pop()
|
cOff = stack.pop()
|
||||||
|
|
@ -382,9 +323,10 @@ func opCodeCopy(instr instruction, pc *uint64, env *Environment, contract *Contr
|
||||||
codeCopy := getData(contract.Code, cOff, l)
|
codeCopy := getData(contract.Code, cOff, l)
|
||||||
|
|
||||||
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeCopy(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opExtCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
addr = common.BigToAddress(stack.pop())
|
addr = common.BigToAddress(stack.pop())
|
||||||
mOff = stack.pop()
|
mOff = stack.pop()
|
||||||
|
|
@ -394,13 +336,15 @@ func opExtCodeCopy(instr instruction, pc *uint64, env *Environment, contract *Co
|
||||||
codeCopy := getData(env.StateDB.GetCode(addr), cOff, l)
|
codeCopy := getData(env.StateDB.GetCode(addr), cOff, l)
|
||||||
|
|
||||||
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
memory.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasprice(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opGasprice(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(new(big.Int).Set(env.GasPrice))
|
stack.push(new(big.Int).Set(env.GasPrice))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBlockhash(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opBlockhash(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
num := stack.pop()
|
num := stack.pop()
|
||||||
|
|
||||||
n := new(big.Int).Sub(env.BlockNumber, common.Big257)
|
n := new(big.Int).Sub(env.BlockNumber, common.Big257)
|
||||||
|
|
@ -409,106 +353,115 @@ func opBlockhash(instr instruction, pc *uint64, env *Environment, contract *Cont
|
||||||
} else {
|
} else {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCoinbase(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCoinbase(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(env.Coinbase.Big())
|
stack.push(env.Coinbase.Big())
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opTimestamp(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opTimestamp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(U256(new(big.Int).Set(env.Time)))
|
stack.push(U256(new(big.Int).Set(env.Time)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNumber(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opNumber(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(U256(new(big.Int).Set(env.BlockNumber)))
|
stack.push(U256(new(big.Int).Set(env.BlockNumber)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDifficulty(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opDifficulty(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(U256(new(big.Int).Set(env.Difficulty)))
|
stack.push(U256(new(big.Int).Set(env.Difficulty)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasLimit(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opGasLimit(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(U256(new(big.Int).Set(env.GasLimit)))
|
stack.push(U256(new(big.Int).Set(env.GasLimit)))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPop(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opPop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.pop()
|
stack.pop()
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPush(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opMload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(new(big.Int).Set(instr.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func opDup(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
|
||||||
stack.dup(int(instr.data.Int64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func opSwap(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
|
||||||
stack.swap(int(instr.data.Int64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func opLog(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
|
||||||
n := int(instr.data.Int64())
|
|
||||||
topics := make([]common.Hash, n)
|
|
||||||
mStart, mSize := stack.pop(), stack.pop()
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
topics[i] = common.BigToHash(stack.pop())
|
|
||||||
}
|
|
||||||
|
|
||||||
d := memory.Get(mStart.Int64(), mSize.Int64())
|
|
||||||
log := NewLog(contract.Address(), topics, d, env.BlockNumber.Uint64())
|
|
||||||
env.StateDB.AddLog(log)
|
|
||||||
}
|
|
||||||
|
|
||||||
func opMload(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
|
||||||
offset := stack.pop()
|
offset := stack.pop()
|
||||||
val := common.BigD(memory.Get(offset.Int64(), 32))
|
val := common.BigD(memory.Get(offset.Int64(), 32))
|
||||||
stack.push(val)
|
stack.push(val)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMstore(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opMstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// pop value of the stack
|
// pop value of the stack
|
||||||
mStart, val := stack.pop(), stack.pop()
|
mStart, val := stack.pop(), stack.pop()
|
||||||
memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
|
memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMstore8(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opMstore8(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
off, val := stack.pop().Int64(), stack.pop().Int64()
|
off, val := stack.pop().Int64(), stack.pop().Int64()
|
||||||
memory.store[off] = byte(val & 0xff)
|
memory.store[off] = byte(val & 0xff)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSload(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
loc := common.BigToHash(stack.pop())
|
loc := common.BigToHash(stack.pop())
|
||||||
val := env.StateDB.GetState(contract.Address(), loc).Big()
|
val := env.StateDB.GetState(contract.Address(), loc).Big()
|
||||||
stack.push(val)
|
stack.push(val)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSstore(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opSstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
loc := common.BigToHash(stack.pop())
|
loc := common.BigToHash(stack.pop())
|
||||||
val := stack.pop()
|
val := stack.pop()
|
||||||
env.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
|
env.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opJump(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opJump(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
pos := stack.pop()
|
||||||
|
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
|
||||||
|
nop := contract.GetOp(pos.Uint64())
|
||||||
|
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
|
||||||
|
}
|
||||||
|
*pc = pos.Uint64()
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opJumpi(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
pos, cond := stack.pop(), stack.pop()
|
||||||
|
if cond.Cmp(common.BigTrue) >= 0 {
|
||||||
|
if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) {
|
||||||
|
nop := contract.GetOp(pos.Uint64())
|
||||||
|
return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos)
|
||||||
|
}
|
||||||
|
*pc = pos.Uint64()
|
||||||
|
} else {
|
||||||
|
*pc++
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
func opJumpdest(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opJumpdest(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPc(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opPc(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(new(big.Int).Set(instr.data))
|
stack.push(new(big.Int).SetUint64(*pc))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMsize(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opMsize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(big.NewInt(int64(memory.Len())))
|
stack.push(big.NewInt(int64(memory.Len())))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGas(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opGas(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(new(big.Int).Set(contract.Gas))
|
stack.push(new(big.Int).Set(contract.Gas))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCreate(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCreate(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
value = stack.pop()
|
value = stack.pop()
|
||||||
offset, size = stack.pop(), stack.pop()
|
offset, size = stack.pop(), stack.pop()
|
||||||
|
|
@ -526,16 +479,17 @@ func opCreate(instr instruction, pc *uint64, env *Environment, contract *Contrac
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
// ignore this error and pretend the operation was successful.
|
// ignore this error and pretend the operation was successful.
|
||||||
if env.ChainConfig().IsHomestead(env.BlockNumber) && suberr == CodeStoreOutOfGasError {
|
if env.ChainConfig().IsHomestead(env.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
} else if suberr != nil && suberr != CodeStoreOutOfGasError {
|
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
} else {
|
} else {
|
||||||
stack.push(addr.Big())
|
stack.push(addr.Big())
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCall(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
gas := stack.pop()
|
gas := stack.pop()
|
||||||
// pop gas and value of the stack.
|
// pop gas and value of the stack.
|
||||||
addr, value := stack.pop(), stack.pop()
|
addr, value := stack.pop(), stack.pop()
|
||||||
|
|
@ -564,9 +518,10 @@ func opCall(instr instruction, pc *uint64, env *Environment, contract *Contract,
|
||||||
|
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallCode(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
gas := stack.pop()
|
gas := stack.pop()
|
||||||
// pop gas and value of the stack.
|
// pop gas and value of the stack.
|
||||||
addr, value := stack.pop(), stack.pop()
|
addr, value := stack.pop(), stack.pop()
|
||||||
|
|
@ -595,9 +550,16 @@ func opCallCode(instr instruction, pc *uint64, env *Environment, contract *Contr
|
||||||
|
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDelegateCall(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opDelegateCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
// if not homestead return an error. DELEGATECALL is not supported
|
||||||
|
// during pre-homestead.
|
||||||
|
if !env.ChainConfig().IsHomestead(env.BlockNumber) {
|
||||||
|
return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL)
|
||||||
|
}
|
||||||
|
|
||||||
gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
|
|
||||||
toAddr := common.BigToAddress(to)
|
toAddr := common.BigToAddress(to)
|
||||||
|
|
@ -609,25 +571,34 @@ func opDelegateCall(instr instruction, pc *uint64, env *Environment, contract *C
|
||||||
stack.push(big.NewInt(1))
|
stack.push(big.NewInt(1))
|
||||||
memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
|
memory.Set(outOffset.Uint64(), outSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opReturn(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opReturn(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
}
|
offset, size := stack.pop(), stack.pop()
|
||||||
func opStop(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
ret := memory.GetPtr(offset.Int64(), size.Int64())
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSuicide(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
func opStop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
balance := env.StateDB.GetBalance(contract.Address())
|
balance := env.StateDB.GetBalance(contract.Address())
|
||||||
env.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
|
env.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
|
||||||
|
|
||||||
env.StateDB.Suicide(contract.Address())
|
env.StateDB.Suicide(contract.Address())
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// following functions are used by the instruction jump table
|
// following functions are used by the instruction jump table
|
||||||
|
|
||||||
// make log instruction function
|
// make log instruction function
|
||||||
func makeLog(size int) instrFn {
|
func makeLog(size int) executionFunc {
|
||||||
return func(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
topics := make([]common.Hash, size)
|
topics := make([]common.Hash, size)
|
||||||
mStart, mSize := stack.pop(), stack.pop()
|
mStart, mSize := stack.pop(), stack.pop()
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
|
|
@ -635,32 +606,42 @@ func makeLog(size int) instrFn {
|
||||||
}
|
}
|
||||||
|
|
||||||
d := memory.Get(mStart.Int64(), mSize.Int64())
|
d := memory.Get(mStart.Int64(), mSize.Int64())
|
||||||
log := NewLog(contract.Address(), topics, d, env.BlockNumber.Uint64())
|
env.StateDB.AddLog(&types.Log{
|
||||||
env.StateDB.AddLog(log)
|
Address: contract.Address(),
|
||||||
|
Topics: topics,
|
||||||
|
Data: d,
|
||||||
|
// This is a non-consensus field, but assigned here because
|
||||||
|
// core/state doesn't know the current block number.
|
||||||
|
BlockNumber: env.BlockNumber.Uint64(),
|
||||||
|
})
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make push instruction function
|
// make push instruction function
|
||||||
func makePush(size uint64, bsize *big.Int) instrFn {
|
func makePush(size uint64, bsize *big.Int) executionFunc {
|
||||||
return func(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
byts := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize)
|
byts := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize)
|
||||||
stack.push(common.Bytes2Big(byts))
|
stack.push(common.Bytes2Big(byts))
|
||||||
*pc += size
|
*pc += size
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make push instruction function
|
// make push instruction function
|
||||||
func makeDup(size int64) instrFn {
|
func makeDup(size int64) executionFunc {
|
||||||
return func(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.dup(int(size))
|
stack.dup(int(size))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make swap instruction function
|
// make swap instruction function
|
||||||
func makeSwap(size int64) instrFn {
|
func makeSwap(size int64) executionFunc {
|
||||||
// switch n + 1 otherwise n would be swapped with n
|
// switch n + 1 otherwise n would be swapped with n
|
||||||
size += 1
|
size += 1
|
||||||
return func(instr instruction, pc *uint64, env *Environment, contract *Contract, memory *Memory, stack *Stack) {
|
return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.swap(int(size))
|
stack.swap(int(size))
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,9 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Vm is the basic interface for an implementation of the EVM.
|
|
||||||
type Vm interface {
|
|
||||||
// Run should execute the given contract with the input given in in
|
|
||||||
// and return the contract execution return bytes or an error if it
|
|
||||||
// failed.
|
|
||||||
Run(c *Contract, in []byte) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StateDB is an EVM database for full state querying.
|
// StateDB is an EVM database for full state querying.
|
||||||
type StateDB interface {
|
type StateDB interface {
|
||||||
GetAccount(common.Address) Account
|
GetAccount(common.Address) Account
|
||||||
|
|
@ -66,7 +59,7 @@ type StateDB interface {
|
||||||
RevertToSnapshot(int)
|
RevertToSnapshot(int)
|
||||||
Snapshot() int
|
Snapshot() int
|
||||||
|
|
||||||
AddLog(*Log)
|
AddLog(*types.Log)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account represents a contract or basic ethereum account.
|
// Account represents a contract or basic ethereum account.
|
||||||
|
|
@ -83,15 +76,15 @@ type Account interface {
|
||||||
Value() *big.Int
|
Value() *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM Environment
|
// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM
|
||||||
// depends on this context being implemented for doing subcalls and initialising new EVM contracts.
|
// depends on this context being implemented for doing subcalls and initialising new EVM contracts.
|
||||||
type CallContext interface {
|
type CallContext interface {
|
||||||
// Call another contract
|
// Call another contract
|
||||||
Call(env *Environment, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error)
|
Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error)
|
||||||
// Take another's contract code and execute within our own context
|
// Take another's contract code and execute within our own context
|
||||||
CallCode(env *Environment, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error)
|
CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error)
|
||||||
// Same as CallCode except sender and value is propagated from parent to child scope
|
// Same as CallCode except sender and value is propagated from parent to child scope
|
||||||
DelegateCall(env *Environment, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error)
|
DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error)
|
||||||
// Create a new contract
|
// Create a new contract
|
||||||
Create(env *Environment, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error)
|
Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
512
core/vm/jit.go
512
core/vm/jit.go
|
|
@ -1,512 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package vm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/hashicorp/golang-lru"
|
|
||||||
)
|
|
||||||
|
|
||||||
// progStatus is the type for the JIT program status.
|
|
||||||
type progStatus int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
progUnknown progStatus = iota // unknown status
|
|
||||||
progCompile // compile status
|
|
||||||
progReady // ready for use status
|
|
||||||
progError // error status (usually caused during compilation)
|
|
||||||
|
|
||||||
defaultJitMaxCache int = 64 // maximum amount of jit cached programs
|
|
||||||
)
|
|
||||||
|
|
||||||
var MaxProgSize int // Max cache size for JIT programs
|
|
||||||
|
|
||||||
var programs *lru.Cache // lru cache for the JIT programs.
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
SetJITCacheSize(defaultJitMaxCache)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetJITCacheSize recreates the program cache with the max given size. Setting
|
|
||||||
// a new cache is **not** thread safe. Use with caution.
|
|
||||||
func SetJITCacheSize(size int) {
|
|
||||||
programs, _ = lru.New(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProgram returns the program by id or nil when non-existent
|
|
||||||
func GetProgram(id common.Hash) *Program {
|
|
||||||
if p, ok := programs.Get(id); ok {
|
|
||||||
return p.(*Program)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenProgramStatus returns the status of the given program id
|
|
||||||
func GetProgramStatus(id common.Hash) progStatus {
|
|
||||||
program := GetProgram(id)
|
|
||||||
if program != nil {
|
|
||||||
return progStatus(atomic.LoadInt32(&program.status))
|
|
||||||
}
|
|
||||||
|
|
||||||
return progUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
// Program is a compiled program for the JIT VM and holds all required for
|
|
||||||
// running a compiled JIT program.
|
|
||||||
type Program struct {
|
|
||||||
Id common.Hash // Id of the program
|
|
||||||
status int32 // status should be accessed atomically
|
|
||||||
|
|
||||||
contract *Contract
|
|
||||||
|
|
||||||
instructions []programInstruction // instruction set
|
|
||||||
mapping map[uint64]uint64 // real PC mapping to array indices
|
|
||||||
destinations map[uint64]struct{} // cached jump destinations
|
|
||||||
|
|
||||||
code []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProgram returns a new JIT program
|
|
||||||
func NewProgram(code []byte) *Program {
|
|
||||||
program := &Program{
|
|
||||||
Id: crypto.Keccak256Hash(code),
|
|
||||||
mapping: make(map[uint64]uint64),
|
|
||||||
destinations: make(map[uint64]struct{}),
|
|
||||||
code: code,
|
|
||||||
}
|
|
||||||
|
|
||||||
programs.Add(program.Id, program)
|
|
||||||
return program
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) {
|
|
||||||
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
|
|
||||||
// PUSH is also allowed to calculate the same price for all PUSHes
|
|
||||||
// DUP requirements are handled elsewhere (except for the stack limit check)
|
|
||||||
baseOp := op
|
|
||||||
if op >= PUSH1 && op <= PUSH32 {
|
|
||||||
baseOp = PUSH1
|
|
||||||
}
|
|
||||||
if op >= DUP1 && op <= DUP16 {
|
|
||||||
baseOp = DUP1
|
|
||||||
}
|
|
||||||
base := _baseCheck[baseOp]
|
|
||||||
|
|
||||||
returns := op == RETURN || op == SUICIDE || op == STOP
|
|
||||||
instr := instruction{op, pc, fn, data, base.gas, base.stackPop, base.stackPush, returns}
|
|
||||||
|
|
||||||
p.instructions = append(p.instructions, instr)
|
|
||||||
p.mapping[pc] = uint64(len(p.instructions) - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompileProgram compiles the given program and return an error when it fails
|
|
||||||
func CompileProgram(program *Program) (err error) {
|
|
||||||
if progStatus(atomic.LoadInt32(&program.status)) == progCompile {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
atomic.StoreInt32(&program.status, int32(progCompile))
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
atomic.StoreInt32(&program.status, int32(progError))
|
|
||||||
} else {
|
|
||||||
atomic.StoreInt32(&program.status, int32(progReady))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if glog.V(logger.Debug) {
|
|
||||||
glog.Infof("compiling %x\n", program.Id[:4])
|
|
||||||
tstart := time.Now()
|
|
||||||
defer func() {
|
|
||||||
glog.Infof("compiled %x instrc: %d time: %v\n", program.Id[:4], len(program.instructions), time.Since(tstart))
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop thru the opcodes and "compile" in to instructions
|
|
||||||
for pc := uint64(0); pc < uint64(len(program.code)); pc++ {
|
|
||||||
switch op := OpCode(program.code[pc]); op {
|
|
||||||
case ADD:
|
|
||||||
program.addInstr(op, pc, opAdd, nil)
|
|
||||||
case SUB:
|
|
||||||
program.addInstr(op, pc, opSub, nil)
|
|
||||||
case MUL:
|
|
||||||
program.addInstr(op, pc, opMul, nil)
|
|
||||||
case DIV:
|
|
||||||
program.addInstr(op, pc, opDiv, nil)
|
|
||||||
case SDIV:
|
|
||||||
program.addInstr(op, pc, opSdiv, nil)
|
|
||||||
case MOD:
|
|
||||||
program.addInstr(op, pc, opMod, nil)
|
|
||||||
case SMOD:
|
|
||||||
program.addInstr(op, pc, opSmod, nil)
|
|
||||||
case EXP:
|
|
||||||
program.addInstr(op, pc, opExp, nil)
|
|
||||||
case SIGNEXTEND:
|
|
||||||
program.addInstr(op, pc, opSignExtend, nil)
|
|
||||||
case NOT:
|
|
||||||
program.addInstr(op, pc, opNot, nil)
|
|
||||||
case LT:
|
|
||||||
program.addInstr(op, pc, opLt, nil)
|
|
||||||
case GT:
|
|
||||||
program.addInstr(op, pc, opGt, nil)
|
|
||||||
case SLT:
|
|
||||||
program.addInstr(op, pc, opSlt, nil)
|
|
||||||
case SGT:
|
|
||||||
program.addInstr(op, pc, opSgt, nil)
|
|
||||||
case EQ:
|
|
||||||
program.addInstr(op, pc, opEq, nil)
|
|
||||||
case ISZERO:
|
|
||||||
program.addInstr(op, pc, opIszero, nil)
|
|
||||||
case AND:
|
|
||||||
program.addInstr(op, pc, opAnd, nil)
|
|
||||||
case OR:
|
|
||||||
program.addInstr(op, pc, opOr, nil)
|
|
||||||
case XOR:
|
|
||||||
program.addInstr(op, pc, opXor, nil)
|
|
||||||
case BYTE:
|
|
||||||
program.addInstr(op, pc, opByte, nil)
|
|
||||||
case ADDMOD:
|
|
||||||
program.addInstr(op, pc, opAddmod, nil)
|
|
||||||
case MULMOD:
|
|
||||||
program.addInstr(op, pc, opMulmod, nil)
|
|
||||||
case SHA3:
|
|
||||||
program.addInstr(op, pc, opSha3, nil)
|
|
||||||
case ADDRESS:
|
|
||||||
program.addInstr(op, pc, opAddress, nil)
|
|
||||||
case BALANCE:
|
|
||||||
program.addInstr(op, pc, opBalance, nil)
|
|
||||||
case ORIGIN:
|
|
||||||
program.addInstr(op, pc, opOrigin, nil)
|
|
||||||
case CALLER:
|
|
||||||
program.addInstr(op, pc, opCaller, nil)
|
|
||||||
case CALLVALUE:
|
|
||||||
program.addInstr(op, pc, opCallValue, nil)
|
|
||||||
case CALLDATALOAD:
|
|
||||||
program.addInstr(op, pc, opCalldataLoad, nil)
|
|
||||||
case CALLDATASIZE:
|
|
||||||
program.addInstr(op, pc, opCalldataSize, nil)
|
|
||||||
case CALLDATACOPY:
|
|
||||||
program.addInstr(op, pc, opCalldataCopy, nil)
|
|
||||||
case CODESIZE:
|
|
||||||
program.addInstr(op, pc, opCodeSize, nil)
|
|
||||||
case EXTCODESIZE:
|
|
||||||
program.addInstr(op, pc, opExtCodeSize, nil)
|
|
||||||
case CODECOPY:
|
|
||||||
program.addInstr(op, pc, opCodeCopy, nil)
|
|
||||||
case EXTCODECOPY:
|
|
||||||
program.addInstr(op, pc, opExtCodeCopy, nil)
|
|
||||||
case GASPRICE:
|
|
||||||
program.addInstr(op, pc, opGasprice, nil)
|
|
||||||
case BLOCKHASH:
|
|
||||||
program.addInstr(op, pc, opBlockhash, nil)
|
|
||||||
case COINBASE:
|
|
||||||
program.addInstr(op, pc, opCoinbase, nil)
|
|
||||||
case TIMESTAMP:
|
|
||||||
program.addInstr(op, pc, opTimestamp, nil)
|
|
||||||
case NUMBER:
|
|
||||||
program.addInstr(op, pc, opNumber, nil)
|
|
||||||
case DIFFICULTY:
|
|
||||||
program.addInstr(op, pc, opDifficulty, nil)
|
|
||||||
case GASLIMIT:
|
|
||||||
program.addInstr(op, pc, opGasLimit, nil)
|
|
||||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
|
||||||
size := uint64(op - PUSH1 + 1)
|
|
||||||
bytes := getData([]byte(program.code), new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
|
|
||||||
|
|
||||||
program.addInstr(op, pc, opPush, common.Bytes2Big(bytes))
|
|
||||||
|
|
||||||
pc += size
|
|
||||||
|
|
||||||
case POP:
|
|
||||||
program.addInstr(op, pc, opPop, nil)
|
|
||||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
|
||||||
program.addInstr(op, pc, opDup, big.NewInt(int64(op-DUP1+1)))
|
|
||||||
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
|
||||||
program.addInstr(op, pc, opSwap, big.NewInt(int64(op-SWAP1+2)))
|
|
||||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
|
||||||
program.addInstr(op, pc, opLog, big.NewInt(int64(op-LOG0)))
|
|
||||||
case MLOAD:
|
|
||||||
program.addInstr(op, pc, opMload, nil)
|
|
||||||
case MSTORE:
|
|
||||||
program.addInstr(op, pc, opMstore, nil)
|
|
||||||
case MSTORE8:
|
|
||||||
program.addInstr(op, pc, opMstore8, nil)
|
|
||||||
case SLOAD:
|
|
||||||
program.addInstr(op, pc, opSload, nil)
|
|
||||||
case SSTORE:
|
|
||||||
program.addInstr(op, pc, opSstore, nil)
|
|
||||||
case JUMP:
|
|
||||||
program.addInstr(op, pc, opJump, nil)
|
|
||||||
case JUMPI:
|
|
||||||
program.addInstr(op, pc, opJumpi, nil)
|
|
||||||
case JUMPDEST:
|
|
||||||
program.addInstr(op, pc, opJumpdest, nil)
|
|
||||||
program.destinations[pc] = struct{}{}
|
|
||||||
case PC:
|
|
||||||
program.addInstr(op, pc, opPc, big.NewInt(int64(pc)))
|
|
||||||
case MSIZE:
|
|
||||||
program.addInstr(op, pc, opMsize, nil)
|
|
||||||
case GAS:
|
|
||||||
program.addInstr(op, pc, opGas, nil)
|
|
||||||
case CREATE:
|
|
||||||
program.addInstr(op, pc, opCreate, nil)
|
|
||||||
case DELEGATECALL:
|
|
||||||
// Instruction added regardless of homestead phase.
|
|
||||||
// Homestead (and execution of the opcode) is checked during
|
|
||||||
// runtime.
|
|
||||||
program.addInstr(op, pc, opDelegateCall, nil)
|
|
||||||
case CALL:
|
|
||||||
program.addInstr(op, pc, opCall, nil)
|
|
||||||
case CALLCODE:
|
|
||||||
program.addInstr(op, pc, opCallCode, nil)
|
|
||||||
case RETURN:
|
|
||||||
program.addInstr(op, pc, opReturn, nil)
|
|
||||||
case SUICIDE:
|
|
||||||
program.addInstr(op, pc, opSuicide, nil)
|
|
||||||
case STOP: // Stop the contract
|
|
||||||
program.addInstr(op, pc, opStop, nil)
|
|
||||||
default:
|
|
||||||
program.addInstr(op, pc, nil, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
optimiseProgram(program)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunProgram runs the program given the environment and contract and returns an
|
|
||||||
// error if the execution failed (non-consensus)
|
|
||||||
func RunProgram(program *Program, env *Environment, contract *Contract, input []byte) ([]byte, error) {
|
|
||||||
return runProgram(program, 0, NewMemory(), newstack(), env, contract, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runProgram(program *Program, pcstart uint64, mem *Memory, stack *Stack, env *Environment, contract *Contract, input []byte) ([]byte, error) {
|
|
||||||
contract.Input = input
|
|
||||||
|
|
||||||
var (
|
|
||||||
pc uint64 = program.mapping[pcstart]
|
|
||||||
instrCount = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
if glog.V(logger.Debug) {
|
|
||||||
glog.Infof("running JIT program %x\n", program.Id[:4])
|
|
||||||
tstart := time.Now()
|
|
||||||
defer func() {
|
|
||||||
glog.Infof("JIT program %x done. time: %v instrc: %v\n", program.Id[:4], time.Since(tstart), instrCount)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
homestead := env.ChainConfig().IsHomestead(env.BlockNumber)
|
|
||||||
for pc < uint64(len(program.instructions)) {
|
|
||||||
instrCount++
|
|
||||||
|
|
||||||
instr := program.instructions[pc]
|
|
||||||
if instr.Op() == DELEGATECALL && !homestead {
|
|
||||||
return nil, fmt.Errorf("Invalid opcode 0x%x", instr.Op())
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err := instr.do(program, &pc, env, contract, mem, stack)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if instr.halts() {
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract.Input = nil
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// validDest checks if the given destination is a valid one given the
|
|
||||||
// destination table of the program
|
|
||||||
func validDest(dests map[uint64]struct{}, dest *big.Int) bool {
|
|
||||||
// PC cannot go beyond len(code) and certainly can't be bigger than 64bits.
|
|
||||||
// Don't bother checking for JUMPDEST in that case.
|
|
||||||
if dest.Cmp(bigMaxUint64) > 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
_, ok := dests[dest.Uint64()]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// jitCalculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
|
|
||||||
// the operation. This does not reduce gas or resizes the memory.
|
|
||||||
func jitCalculateGasAndSize(env *Environment, contract *Contract, instr instruction, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) {
|
|
||||||
var (
|
|
||||||
gas = new(big.Int)
|
|
||||||
newMemSize *big.Int = new(big.Int)
|
|
||||||
)
|
|
||||||
err := jitBaseCheck(instr, stack, gas)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// stack Check, memory resize & gas phase
|
|
||||||
switch op := instr.op; op {
|
|
||||||
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
|
||||||
n := int(op - SWAP1 + 2)
|
|
||||||
err := stack.require(n)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
gas.Set(GasFastestStep)
|
|
||||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
|
||||||
n := int(op - DUP1 + 1)
|
|
||||||
err := stack.require(n)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
gas.Set(GasFastestStep)
|
|
||||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
|
||||||
n := int(op - LOG0)
|
|
||||||
err := stack.require(n + 2)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
|
||||||
|
|
||||||
add := new(big.Int)
|
|
||||||
gas.Add(gas, params.LogGas)
|
|
||||||
gas.Add(gas, add.Mul(big.NewInt(int64(n)), params.LogTopicGas))
|
|
||||||
gas.Add(gas, add.Mul(mSize, params.LogDataGas))
|
|
||||||
|
|
||||||
newMemSize = calcMemSize(mStart, mSize)
|
|
||||||
case EXP:
|
|
||||||
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
|
|
||||||
case SSTORE:
|
|
||||||
err := stack.require(2)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var g *big.Int
|
|
||||||
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
|
||||||
val := env.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
|
||||||
|
|
||||||
// This checks for 3 scenario's and calculates gas accordingly
|
|
||||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
|
||||||
// 2. From a non-zero value address to a zero-value address (DELETE)
|
|
||||||
// 3. From a non-zero to a non-zero (CHANGE)
|
|
||||||
if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
|
|
||||||
g = params.SstoreSetGas
|
|
||||||
} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
|
|
||||||
env.StateDB.AddRefund(params.SstoreRefundGas)
|
|
||||||
|
|
||||||
g = params.SstoreClearGas
|
|
||||||
} else {
|
|
||||||
g = params.SstoreResetGas
|
|
||||||
}
|
|
||||||
gas.Set(g)
|
|
||||||
case SUICIDE:
|
|
||||||
if !env.StateDB.HasSuicided(contract.Address()) {
|
|
||||||
env.StateDB.AddRefund(params.SuicideRefundGas)
|
|
||||||
}
|
|
||||||
case MLOAD:
|
|
||||||
newMemSize = calcMemSize(stack.peek(), u256(32))
|
|
||||||
case MSTORE8:
|
|
||||||
newMemSize = calcMemSize(stack.peek(), u256(1))
|
|
||||||
case MSTORE:
|
|
||||||
newMemSize = calcMemSize(stack.peek(), u256(32))
|
|
||||||
case RETURN:
|
|
||||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
|
|
||||||
case SHA3:
|
|
||||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
|
|
||||||
|
|
||||||
words := toWordSize(stack.data[stack.len()-2])
|
|
||||||
gas.Add(gas, words.Mul(words, params.Sha3WordGas))
|
|
||||||
case CALLDATACOPY:
|
|
||||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
|
|
||||||
|
|
||||||
words := toWordSize(stack.data[stack.len()-3])
|
|
||||||
gas.Add(gas, words.Mul(words, params.CopyGas))
|
|
||||||
case CODECOPY:
|
|
||||||
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
|
|
||||||
|
|
||||||
words := toWordSize(stack.data[stack.len()-3])
|
|
||||||
gas.Add(gas, words.Mul(words, params.CopyGas))
|
|
||||||
case EXTCODECOPY:
|
|
||||||
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
|
|
||||||
|
|
||||||
words := toWordSize(stack.data[stack.len()-4])
|
|
||||||
gas.Add(gas, words.Mul(words, params.CopyGas))
|
|
||||||
|
|
||||||
case CREATE:
|
|
||||||
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
|
|
||||||
case CALL, CALLCODE:
|
|
||||||
gas.Add(gas, stack.data[stack.len()-1])
|
|
||||||
|
|
||||||
if op == CALL {
|
|
||||||
if !env.StateDB.Exist(common.BigToAddress(stack.data[stack.len()-2])) {
|
|
||||||
gas.Add(gas, params.CallNewAccountGas)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(stack.data[stack.len()-3].Bytes()) > 0 {
|
|
||||||
gas.Add(gas, params.CallValueTransferGas)
|
|
||||||
}
|
|
||||||
|
|
||||||
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
|
|
||||||
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
|
|
||||||
|
|
||||||
newMemSize = common.BigMax(x, y)
|
|
||||||
case DELEGATECALL:
|
|
||||||
gas.Add(gas, stack.data[stack.len()-1])
|
|
||||||
|
|
||||||
x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6])
|
|
||||||
y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4])
|
|
||||||
|
|
||||||
newMemSize = common.BigMax(x, y)
|
|
||||||
}
|
|
||||||
quadMemGas(mem, newMemSize, gas)
|
|
||||||
|
|
||||||
return newMemSize, gas, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// jitBaseCheck is the same as baseCheck except it doesn't do the look up in the
|
|
||||||
// gas table. This is done during compilation instead.
|
|
||||||
func jitBaseCheck(instr instruction, stack *Stack, gas *big.Int) error {
|
|
||||||
err := stack.require(instr.spop)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if instr.spush > 0 && stack.len()-instr.spop+instr.spush > int(params.StackLimit.Int64()) {
|
|
||||||
return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
|
|
||||||
}
|
|
||||||
|
|
||||||
// nil on gas means no base calculation
|
|
||||||
if instr.gas == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
gas.Add(gas, instr.gas)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package vm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// optimeProgram optimises a JIT program creating segments out of program
|
|
||||||
// instructions. Currently covered are multi-pushes and static jumps
|
|
||||||
func optimiseProgram(program *Program) {
|
|
||||||
var load []instruction
|
|
||||||
|
|
||||||
var (
|
|
||||||
statsJump = 0
|
|
||||||
statsPush = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
if glog.V(logger.Debug) {
|
|
||||||
glog.Infof("optimising %x\n", program.Id[:4])
|
|
||||||
tstart := time.Now()
|
|
||||||
defer func() {
|
|
||||||
glog.Infof("optimised %x done in %v with JMP: %d PSH: %d\n", program.Id[:4], time.Since(tstart), statsJump, statsPush)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
code := Parse(program.code)
|
|
||||||
for _, test := range [][]OpCode{
|
|
||||||
[]OpCode{PUSH, PUSH, ADD},
|
|
||||||
[]OpCode{PUSH, PUSH, SUB},
|
|
||||||
[]OpCode{PUSH, PUSH, MUL},
|
|
||||||
[]OpCode{PUSH, PUSH, DIV},
|
|
||||||
} {
|
|
||||||
matchCount := 0
|
|
||||||
MatchFn(code, test, func(i int) bool {
|
|
||||||
matchCount++
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
fmt.Printf("found %d match count on: %v\n", matchCount, test)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
for i := 0; i < len(program.instructions); i++ {
|
|
||||||
instr := program.instructions[i].(instruction)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case instr.op.IsPush():
|
|
||||||
load = append(load, instr)
|
|
||||||
case instr.op.IsStaticJump():
|
|
||||||
if len(load) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// if the push load is greater than 1, finalise that
|
|
||||||
// segment first
|
|
||||||
if len(load) > 2 {
|
|
||||||
seg, size := makePushSeg(load[:len(load)-1])
|
|
||||||
program.instructions[i-size-1] = seg
|
|
||||||
statsPush++
|
|
||||||
}
|
|
||||||
// create a segment consisting of a pre determined
|
|
||||||
// jump, destination and validity.
|
|
||||||
seg := makeStaticJumpSeg(load[len(load)-1].data, program)
|
|
||||||
program.instructions[i-1] = seg
|
|
||||||
statsJump++
|
|
||||||
|
|
||||||
load = nil
|
|
||||||
default:
|
|
||||||
// create a new N pushes segment
|
|
||||||
if len(load) > 1 {
|
|
||||||
seg, size := makePushSeg(load)
|
|
||||||
program.instructions[i-size] = seg
|
|
||||||
statsPush++
|
|
||||||
}
|
|
||||||
load = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// makePushSeg creates a new push segment from N amount of push instructions
|
|
||||||
func makePushSeg(instrs []instruction) (pushSeg, int) {
|
|
||||||
var (
|
|
||||||
data []*big.Int
|
|
||||||
gas = new(big.Int)
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, instr := range instrs {
|
|
||||||
data = append(data, instr.data)
|
|
||||||
gas.Add(gas, instr.gas)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pushSeg{data, gas}, len(instrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeStaticJumpSeg creates a new static jump segment from a predefined
|
|
||||||
// destination (PUSH, JUMP).
|
|
||||||
func makeStaticJumpSeg(to *big.Int, program *Program) jumpSeg {
|
|
||||||
gas := new(big.Int)
|
|
||||||
gas.Add(gas, _baseCheck[PUSH1].gas)
|
|
||||||
gas.Add(gas, _baseCheck[JUMP].gas)
|
|
||||||
|
|
||||||
contract := &Contract{Code: program.code}
|
|
||||||
pos, err := jump(program.mapping, program.destinations, contract, to)
|
|
||||||
return jumpSeg{pos, err, gas}
|
|
||||||
}
|
|
||||||
|
|
@ -1,160 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package vm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
const maxRun = 1000
|
|
||||||
|
|
||||||
func TestSegmenting(t *testing.T) {
|
|
||||||
prog := NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, 0x0})
|
|
||||||
err := CompileProgram(prog)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if instr, ok := prog.instructions[0].(pushSeg); ok {
|
|
||||||
if len(instr.data) != 2 {
|
|
||||||
t.Error("expected 2 element width pushSegment, got", len(instr.data))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Errorf("expected instr[0] to be a pushSeg, got %T", prog.instructions[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
prog = NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(JUMP)})
|
|
||||||
err = CompileProgram(prog)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if _, ok := prog.instructions[1].(jumpSeg); ok {
|
|
||||||
} else {
|
|
||||||
t.Errorf("expected instr[1] to be jumpSeg, got %T", prog.instructions[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
prog = NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(JUMP)})
|
|
||||||
err = CompileProgram(prog)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if instr, ok := prog.instructions[0].(pushSeg); ok {
|
|
||||||
if len(instr.data) != 2 {
|
|
||||||
t.Error("expected 2 element width pushSegment, got", len(instr.data))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Errorf("expected instr[0] to be a pushSeg, got %T", prog.instructions[0])
|
|
||||||
}
|
|
||||||
if _, ok := prog.instructions[2].(jumpSeg); ok {
|
|
||||||
} else {
|
|
||||||
t.Errorf("expected instr[1] to be jumpSeg, got %T", prog.instructions[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCompiling(t *testing.T) {
|
|
||||||
prog := NewProgram([]byte{0x60, 0x10})
|
|
||||||
err := CompileProgram(prog)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("didn't expect compile error")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(prog.instructions) != 1 {
|
|
||||||
t.Error("expected 1 compiled instruction, got", len(prog.instructions))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResetInput(t *testing.T) {
|
|
||||||
var sender account
|
|
||||||
|
|
||||||
env := NewEnvironment(Context{}, nil, params.TestChainConfig, Config{})
|
|
||||||
contract := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000))
|
|
||||||
contract.CodeAddr = &common.Address{}
|
|
||||||
|
|
||||||
program := NewProgram([]byte{})
|
|
||||||
RunProgram(program, env, contract, []byte{0xbe, 0xef})
|
|
||||||
if contract.Input != nil {
|
|
||||||
t.Errorf("expected input to be nil, got %x", contract.Input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPcMappingToInstruction(t *testing.T) {
|
|
||||||
program := NewProgram([]byte{byte(PUSH2), 0xbe, 0xef, byte(ADD)})
|
|
||||||
CompileProgram(program)
|
|
||||||
if program.mapping[3] != 1 {
|
|
||||||
t.Error("expected mapping PC 4 to me instr no. 2, got", program.mapping[4])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var benchmarks = map[string]vmBench{
|
|
||||||
"pushes": vmBench{
|
|
||||||
false, false, false,
|
|
||||||
common.Hex2Bytes("600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01"), nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkPushes(b *testing.B) {
|
|
||||||
runVmBench(benchmarks["pushes"], b)
|
|
||||||
}
|
|
||||||
|
|
||||||
type vmBench struct {
|
|
||||||
precompile bool // compile prior to executing
|
|
||||||
nojit bool // ignore jit (sets DisbaleJit = true
|
|
||||||
forcejit bool // forces the jit, precompile is ignored
|
|
||||||
|
|
||||||
code []byte
|
|
||||||
input []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type account struct{}
|
|
||||||
|
|
||||||
func (account) SubBalance(amount *big.Int) {}
|
|
||||||
func (account) AddBalance(amount *big.Int) {}
|
|
||||||
func (account) SetAddress(common.Address) {}
|
|
||||||
func (account) Value() *big.Int { return nil }
|
|
||||||
func (account) SetBalance(*big.Int) {}
|
|
||||||
func (account) SetNonce(uint64) {}
|
|
||||||
func (account) Balance() *big.Int { return nil }
|
|
||||||
func (account) Address() common.Address { return common.Address{} }
|
|
||||||
func (account) ReturnGas(*big.Int) {}
|
|
||||||
func (account) SetCode(common.Hash, []byte) {}
|
|
||||||
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
|
|
||||||
|
|
||||||
func runVmBench(test vmBench, b *testing.B) {
|
|
||||||
var sender account
|
|
||||||
|
|
||||||
if test.precompile && !test.forcejit {
|
|
||||||
NewProgram(test.code)
|
|
||||||
}
|
|
||||||
env := NewEnvironment(Context{}, nil, params.TestChainConfig, Config{EnableJit: !test.nojit, ForceJit: test.forcejit})
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
context := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000))
|
|
||||||
context.Code = test.code
|
|
||||||
context.CodeAddr = &common.Address{}
|
|
||||||
_, err := env.EVM().Run(context, test.input)
|
|
||||||
if err != nil {
|
|
||||||
b.Error(err)
|
|
||||||
b.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package vm
|
|
||||||
|
|
||||||
// Parse parses all opcodes from the given code byte slice. This function
|
|
||||||
// performs no error checking and may return non-existing opcodes.
|
|
||||||
func Parse(code []byte) (opcodes []OpCode) {
|
|
||||||
for pc := uint64(0); pc < uint64(len(code)); pc++ {
|
|
||||||
op := OpCode(code[pc])
|
|
||||||
|
|
||||||
switch op {
|
|
||||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
|
||||||
a := uint64(op) - uint64(PUSH1) + 1
|
|
||||||
pc += a
|
|
||||||
opcodes = append(opcodes, PUSH)
|
|
||||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
|
||||||
opcodes = append(opcodes, DUP)
|
|
||||||
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
|
||||||
opcodes = append(opcodes, SWAP)
|
|
||||||
default:
|
|
||||||
opcodes = append(opcodes, op)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return opcodes
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchFn searcher for match in the given input and calls matcheFn if it finds
|
|
||||||
// an appropriate match. matcherFn yields the starting position in the input.
|
|
||||||
// MatchFn will continue to search for a match until it reaches the end of the
|
|
||||||
// buffer or if matcherFn return false.
|
|
||||||
func MatchFn(input, match []OpCode, matcherFn func(int) bool) {
|
|
||||||
// short circuit if either input or match is empty or if the match is
|
|
||||||
// greater than the input
|
|
||||||
if len(input) == 0 || len(match) == 0 || len(match) > len(input) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
main:
|
|
||||||
for i, op := range input[:len(input)+1-len(match)] {
|
|
||||||
// match first opcode and continue search
|
|
||||||
if op == match[0] {
|
|
||||||
for j := 1; j < len(match); j++ {
|
|
||||||
if input[i+j] != match[j] {
|
|
||||||
continue main
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check for abort instruction
|
|
||||||
if !matcherFn(i) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package vm
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
type matchTest struct {
|
|
||||||
input []OpCode
|
|
||||||
match []OpCode
|
|
||||||
matches int
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMatchFn(t *testing.T) {
|
|
||||||
tests := []matchTest{
|
|
||||||
matchTest{
|
|
||||||
[]OpCode{PUSH1, PUSH1, MSTORE, JUMP},
|
|
||||||
[]OpCode{PUSH1, MSTORE},
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
matchTest{
|
|
||||||
[]OpCode{PUSH1, PUSH1, MSTORE, JUMP},
|
|
||||||
[]OpCode{PUSH1, MSTORE, PUSH1},
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
matchTest{
|
|
||||||
[]OpCode{},
|
|
||||||
[]OpCode{PUSH1},
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, test := range tests {
|
|
||||||
var matchCount int
|
|
||||||
MatchFn(test.input, test.match, func(i int) bool {
|
|
||||||
matchCount++
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
if matchCount != test.matches {
|
|
||||||
t.Errorf("match count failed on test[%d]: expected %d matches, got %d", i, test.matches, matchCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type parseTest struct {
|
|
||||||
base OpCode
|
|
||||||
size int
|
|
||||||
output OpCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParser(t *testing.T) {
|
|
||||||
tests := []parseTest{
|
|
||||||
parseTest{PUSH1, 32, PUSH},
|
|
||||||
parseTest{DUP1, 16, DUP},
|
|
||||||
parseTest{SWAP1, 16, SWAP},
|
|
||||||
parseTest{MSTORE, 1, MSTORE},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
for i := 0; i < test.size; i++ {
|
|
||||||
code := append([]byte{byte(byte(test.base) + byte(i))}, make([]byte, i+1)...)
|
|
||||||
output := Parse(code)
|
|
||||||
if len(output) == 0 {
|
|
||||||
t.Fatal("empty output")
|
|
||||||
}
|
|
||||||
if output[0] != test.output {
|
|
||||||
t.Errorf("%v failed: expected %v but got %v", test.base+OpCode(i), test.output, output[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -22,152 +22,838 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
type jumpPtr struct {
|
type (
|
||||||
fn instrFn
|
executionFunc func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)
|
||||||
|
gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, *big.Int) *big.Int
|
||||||
|
stackValidationFunc func(*Stack) error
|
||||||
|
memorySizeFunc func(*Stack) *big.Int
|
||||||
|
)
|
||||||
|
|
||||||
|
type operation struct {
|
||||||
|
// op is the operation function
|
||||||
|
execute executionFunc
|
||||||
|
// gasCost is the gas function and returns the gas required for execution
|
||||||
|
gasCost gasFunc
|
||||||
|
// validateStack validates the stack (size) for the operation
|
||||||
|
validateStack stackValidationFunc
|
||||||
|
// memorySize returns the memory size required for the operation
|
||||||
|
memorySize memorySizeFunc
|
||||||
|
// halts indicates whether the operation shoult halt further execution
|
||||||
|
// and return
|
||||||
|
halts bool
|
||||||
|
// jumps indicates whether operation made a jump. This prevents the program
|
||||||
|
// counter from further incrementing.
|
||||||
|
jumps bool
|
||||||
|
// valid is used to check whether the retrieved operation is valid and known
|
||||||
valid bool
|
valid bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type vmJumpTable [256]jumpPtr
|
var defaultJumpTable = NewJumpTable()
|
||||||
|
|
||||||
func newJumpTable(ruleset *params.ChainConfig, blockNumber *big.Int) vmJumpTable {
|
func NewJumpTable() [256]operation {
|
||||||
var jumpTable vmJumpTable
|
return [256]operation{
|
||||||
|
ADD: {
|
||||||
|
execute: opAdd,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SUB: {
|
||||||
|
execute: opSub,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
MUL: {
|
||||||
|
execute: opMul,
|
||||||
|
gasCost: constGasFunc(GasFastStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DIV: {
|
||||||
|
execute: opDiv,
|
||||||
|
gasCost: constGasFunc(GasFastStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SDIV: {
|
||||||
|
execute: opSdiv,
|
||||||
|
gasCost: constGasFunc(GasFastStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
MOD: {
|
||||||
|
execute: opMod,
|
||||||
|
gasCost: constGasFunc(GasFastStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SMOD: {
|
||||||
|
execute: opSmod,
|
||||||
|
gasCost: constGasFunc(GasFastStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
EXP: {
|
||||||
|
execute: opExp,
|
||||||
|
gasCost: gasExp,
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SIGNEXTEND: {
|
||||||
|
execute: opSignExtend,
|
||||||
|
gasCost: constGasFunc(GasFastStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
NOT: {
|
||||||
|
execute: opNot,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
LT: {
|
||||||
|
execute: opLt,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
GT: {
|
||||||
|
execute: opGt,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SLT: {
|
||||||
|
execute: opSlt,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SGT: {
|
||||||
|
execute: opSgt,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
EQ: {
|
||||||
|
execute: opEq,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
ISZERO: {
|
||||||
|
execute: opIszero,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
AND: {
|
||||||
|
execute: opAnd,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
OR: {
|
||||||
|
execute: opOr,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
XOR: {
|
||||||
|
execute: opXor,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
BYTE: {
|
||||||
|
execute: opByte,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
ADDMOD: {
|
||||||
|
execute: opAddmod,
|
||||||
|
gasCost: constGasFunc(GasMidStep),
|
||||||
|
validateStack: makeStackFunc(3, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
MULMOD: {
|
||||||
|
execute: opMulmod,
|
||||||
|
gasCost: constGasFunc(GasMidStep),
|
||||||
|
validateStack: makeStackFunc(3, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SHA3: {
|
||||||
|
execute: opSha3,
|
||||||
|
gasCost: gasSha3,
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
memorySize: memorySha3,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
ADDRESS: {
|
||||||
|
execute: opAddress,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
BALANCE: {
|
||||||
|
execute: opBalance,
|
||||||
|
gasCost: gasBalance,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
ORIGIN: {
|
||||||
|
execute: opOrigin,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CALLER: {
|
||||||
|
execute: opCaller,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CALLVALUE: {
|
||||||
|
execute: opCallValue,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CALLDATALOAD: {
|
||||||
|
execute: opCalldataLoad,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CALLDATASIZE: {
|
||||||
|
execute: opCalldataSize,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CALLDATACOPY: {
|
||||||
|
execute: opCalldataCopy,
|
||||||
|
gasCost: gasCalldataCopy,
|
||||||
|
validateStack: makeStackFunc(3, 1),
|
||||||
|
memorySize: memoryCalldataCopy,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CODESIZE: {
|
||||||
|
execute: opCodeSize,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
EXTCODESIZE: {
|
||||||
|
execute: opExtCodeSize,
|
||||||
|
gasCost: gasExtCodeSize,
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CODECOPY: {
|
||||||
|
execute: opCodeCopy,
|
||||||
|
gasCost: gasCodeCopy,
|
||||||
|
validateStack: makeStackFunc(3, 0),
|
||||||
|
memorySize: memoryCodeCopy,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
EXTCODECOPY: {
|
||||||
|
execute: opExtCodeCopy,
|
||||||
|
gasCost: gasExtCodeCopy,
|
||||||
|
validateStack: makeStackFunc(4, 0),
|
||||||
|
memorySize: memoryExtCodeCopy,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
GASPRICE: {
|
||||||
|
execute: opGasprice,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
BLOCKHASH: {
|
||||||
|
execute: opBlockhash,
|
||||||
|
gasCost: constGasFunc(GasExtStep),
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
COINBASE: {
|
||||||
|
execute: opCoinbase,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
TIMESTAMP: {
|
||||||
|
execute: opTimestamp,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
NUMBER: {
|
||||||
|
execute: opNumber,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DIFFICULTY: {
|
||||||
|
execute: opDifficulty,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
GASLIMIT: {
|
||||||
|
execute: opGasLimit,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
POP: {
|
||||||
|
execute: opPop,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(1, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
MLOAD: {
|
||||||
|
execute: opMload,
|
||||||
|
gasCost: gasMLoad,
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
memorySize: memoryMLoad,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
MSTORE: {
|
||||||
|
execute: opMstore,
|
||||||
|
gasCost: gasMStore,
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
memorySize: memoryMStore,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
MSTORE8: {
|
||||||
|
execute: opMstore8,
|
||||||
|
gasCost: gasMStore8,
|
||||||
|
memorySize: memoryMStore8,
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
|
||||||
// when initialising a new VM execution we must first check the homestead
|
valid: true,
|
||||||
// changes.
|
},
|
||||||
if ruleset.IsHomestead(blockNumber) {
|
SLOAD: {
|
||||||
jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true}
|
execute: opSload,
|
||||||
|
gasCost: gasSLoad,
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SSTORE: {
|
||||||
|
execute: opSstore,
|
||||||
|
gasCost: gasSStore,
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
JUMPDEST: {
|
||||||
|
execute: opJumpdest,
|
||||||
|
gasCost: constGasFunc(params.JumpdestGas),
|
||||||
|
validateStack: makeStackFunc(0, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PC: {
|
||||||
|
execute: opPc,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
MSIZE: {
|
||||||
|
execute: opMsize,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
GAS: {
|
||||||
|
execute: opGas,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CREATE: {
|
||||||
|
execute: opCreate,
|
||||||
|
gasCost: gasCreate,
|
||||||
|
validateStack: makeStackFunc(3, 1),
|
||||||
|
memorySize: memoryCreate,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CALL: {
|
||||||
|
execute: opCall,
|
||||||
|
gasCost: gasCall,
|
||||||
|
validateStack: makeStackFunc(7, 1),
|
||||||
|
memorySize: memoryCall,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
CALLCODE: {
|
||||||
|
execute: opCallCode,
|
||||||
|
gasCost: gasCallCode,
|
||||||
|
validateStack: makeStackFunc(7, 1),
|
||||||
|
memorySize: memoryCall,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DELEGATECALL: {
|
||||||
|
execute: opDelegateCall,
|
||||||
|
gasCost: gasDelegateCall,
|
||||||
|
validateStack: makeStackFunc(6, 1),
|
||||||
|
memorySize: memoryDelegateCall,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
RETURN: {
|
||||||
|
execute: opReturn,
|
||||||
|
gasCost: gasReturn,
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
memorySize: memoryReturn,
|
||||||
|
halts: true,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SUICIDE: {
|
||||||
|
execute: opSuicide,
|
||||||
|
gasCost: gasSuicide,
|
||||||
|
validateStack: makeStackFunc(1, 0),
|
||||||
|
halts: true,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
JUMP: {
|
||||||
|
execute: opJump,
|
||||||
|
gasCost: constGasFunc(GasMidStep),
|
||||||
|
validateStack: makeStackFunc(1, 0),
|
||||||
|
jumps: true,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
JUMPI: {
|
||||||
|
execute: opJumpi,
|
||||||
|
gasCost: constGasFunc(GasSlowStep),
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
jumps: true,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
STOP: {
|
||||||
|
execute: opStop,
|
||||||
|
gasCost: constGasFunc(Zero),
|
||||||
|
validateStack: makeStackFunc(0, 0),
|
||||||
|
halts: true,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
LOG0: {
|
||||||
|
execute: makeLog(0),
|
||||||
|
gasCost: makeGasLog(0),
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
memorySize: memoryLog,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
LOG1: {
|
||||||
|
execute: makeLog(1),
|
||||||
|
gasCost: makeGasLog(1),
|
||||||
|
validateStack: makeStackFunc(3, 0),
|
||||||
|
memorySize: memoryLog,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
LOG2: {
|
||||||
|
execute: makeLog(2),
|
||||||
|
gasCost: makeGasLog(2),
|
||||||
|
validateStack: makeStackFunc(4, 0),
|
||||||
|
memorySize: memoryLog,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
LOG3: {
|
||||||
|
execute: makeLog(3),
|
||||||
|
gasCost: makeGasLog(3),
|
||||||
|
validateStack: makeStackFunc(5, 0),
|
||||||
|
memorySize: memoryLog,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
LOG4: {
|
||||||
|
execute: makeLog(4),
|
||||||
|
gasCost: makeGasLog(4),
|
||||||
|
validateStack: makeStackFunc(6, 0),
|
||||||
|
memorySize: memoryLog,
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP1: {
|
||||||
|
execute: makeSwap(1),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP2: {
|
||||||
|
execute: makeSwap(2),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(3, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP3: {
|
||||||
|
execute: makeSwap(3),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(4, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP4: {
|
||||||
|
execute: makeSwap(4),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(5, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP5: {
|
||||||
|
execute: makeSwap(5),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(6, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP6: {
|
||||||
|
execute: makeSwap(6),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(7, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP7: {
|
||||||
|
execute: makeSwap(7),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(8, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP8: {
|
||||||
|
execute: makeSwap(8),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(9, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP9: {
|
||||||
|
execute: makeSwap(9),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(10, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP10: {
|
||||||
|
execute: makeSwap(10),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(11, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP11: {
|
||||||
|
execute: makeSwap(11),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(12, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP12: {
|
||||||
|
execute: makeSwap(12),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(13, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP13: {
|
||||||
|
execute: makeSwap(13),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(14, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP14: {
|
||||||
|
execute: makeSwap(14),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(15, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP15: {
|
||||||
|
execute: makeSwap(15),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(16, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
SWAP16: {
|
||||||
|
execute: makeSwap(16),
|
||||||
|
gasCost: gasSwap,
|
||||||
|
validateStack: makeStackFunc(17, 0),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH1: {
|
||||||
|
execute: makePush(1, big.NewInt(1)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH2: {
|
||||||
|
execute: makePush(2, big.NewInt(2)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH3: {
|
||||||
|
execute: makePush(3, big.NewInt(3)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH4: {
|
||||||
|
execute: makePush(4, big.NewInt(4)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH5: {
|
||||||
|
execute: makePush(5, big.NewInt(5)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH6: {
|
||||||
|
execute: makePush(6, big.NewInt(6)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH7: {
|
||||||
|
execute: makePush(7, big.NewInt(7)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH8: {
|
||||||
|
execute: makePush(8, big.NewInt(8)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH9: {
|
||||||
|
execute: makePush(9, big.NewInt(9)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH10: {
|
||||||
|
execute: makePush(10, big.NewInt(10)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH11: {
|
||||||
|
execute: makePush(11, big.NewInt(11)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH12: {
|
||||||
|
execute: makePush(12, big.NewInt(12)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH13: {
|
||||||
|
execute: makePush(13, big.NewInt(13)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH14: {
|
||||||
|
execute: makePush(14, big.NewInt(14)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH15: {
|
||||||
|
execute: makePush(15, big.NewInt(15)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH16: {
|
||||||
|
execute: makePush(16, big.NewInt(16)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH17: {
|
||||||
|
execute: makePush(17, big.NewInt(17)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH18: {
|
||||||
|
execute: makePush(18, big.NewInt(18)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH19: {
|
||||||
|
execute: makePush(19, big.NewInt(19)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH20: {
|
||||||
|
execute: makePush(20, big.NewInt(20)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH21: {
|
||||||
|
execute: makePush(21, big.NewInt(21)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH22: {
|
||||||
|
execute: makePush(22, big.NewInt(22)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH23: {
|
||||||
|
execute: makePush(23, big.NewInt(23)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH24: {
|
||||||
|
execute: makePush(24, big.NewInt(24)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH25: {
|
||||||
|
execute: makePush(25, big.NewInt(25)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH26: {
|
||||||
|
execute: makePush(26, big.NewInt(26)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH27: {
|
||||||
|
execute: makePush(27, big.NewInt(27)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH28: {
|
||||||
|
execute: makePush(28, big.NewInt(28)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH29: {
|
||||||
|
execute: makePush(29, big.NewInt(29)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH30: {
|
||||||
|
execute: makePush(30, big.NewInt(30)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH31: {
|
||||||
|
execute: makePush(31, big.NewInt(31)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
PUSH32: {
|
||||||
|
execute: makePush(32, big.NewInt(32)),
|
||||||
|
gasCost: gasPush,
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP1: {
|
||||||
|
execute: makeDup(1),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(1, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP2: {
|
||||||
|
execute: makeDup(2),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(2, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP3: {
|
||||||
|
execute: makeDup(3),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(3, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP4: {
|
||||||
|
execute: makeDup(4),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(4, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP5: {
|
||||||
|
execute: makeDup(5),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(5, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP6: {
|
||||||
|
execute: makeDup(6),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(6, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP7: {
|
||||||
|
execute: makeDup(7),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(7, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP8: {
|
||||||
|
execute: makeDup(8),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(8, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP9: {
|
||||||
|
execute: makeDup(9),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(9, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP10: {
|
||||||
|
execute: makeDup(10),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(10, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP11: {
|
||||||
|
execute: makeDup(11),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(11, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP12: {
|
||||||
|
execute: makeDup(12),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(12, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP13: {
|
||||||
|
execute: makeDup(13),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(13, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP14: {
|
||||||
|
execute: makeDup(14),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(14, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP15: {
|
||||||
|
execute: makeDup(15),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(15, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
DUP16: {
|
||||||
|
execute: makeDup(16),
|
||||||
|
gasCost: gasDup,
|
||||||
|
validateStack: makeStackFunc(16, 1),
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
jumpTable[ADD] = jumpPtr{opAdd, true}
|
|
||||||
jumpTable[SUB] = jumpPtr{opSub, true}
|
|
||||||
jumpTable[MUL] = jumpPtr{opMul, true}
|
|
||||||
jumpTable[DIV] = jumpPtr{opDiv, true}
|
|
||||||
jumpTable[SDIV] = jumpPtr{opSdiv, true}
|
|
||||||
jumpTable[MOD] = jumpPtr{opMod, true}
|
|
||||||
jumpTable[SMOD] = jumpPtr{opSmod, true}
|
|
||||||
jumpTable[EXP] = jumpPtr{opExp, true}
|
|
||||||
jumpTable[SIGNEXTEND] = jumpPtr{opSignExtend, true}
|
|
||||||
jumpTable[NOT] = jumpPtr{opNot, true}
|
|
||||||
jumpTable[LT] = jumpPtr{opLt, true}
|
|
||||||
jumpTable[GT] = jumpPtr{opGt, true}
|
|
||||||
jumpTable[SLT] = jumpPtr{opSlt, true}
|
|
||||||
jumpTable[SGT] = jumpPtr{opSgt, true}
|
|
||||||
jumpTable[EQ] = jumpPtr{opEq, true}
|
|
||||||
jumpTable[ISZERO] = jumpPtr{opIszero, true}
|
|
||||||
jumpTable[AND] = jumpPtr{opAnd, true}
|
|
||||||
jumpTable[OR] = jumpPtr{opOr, true}
|
|
||||||
jumpTable[XOR] = jumpPtr{opXor, true}
|
|
||||||
jumpTable[BYTE] = jumpPtr{opByte, true}
|
|
||||||
jumpTable[ADDMOD] = jumpPtr{opAddmod, true}
|
|
||||||
jumpTable[MULMOD] = jumpPtr{opMulmod, true}
|
|
||||||
jumpTable[SHA3] = jumpPtr{opSha3, true}
|
|
||||||
jumpTable[ADDRESS] = jumpPtr{opAddress, true}
|
|
||||||
jumpTable[BALANCE] = jumpPtr{opBalance, true}
|
|
||||||
jumpTable[ORIGIN] = jumpPtr{opOrigin, true}
|
|
||||||
jumpTable[CALLER] = jumpPtr{opCaller, true}
|
|
||||||
jumpTable[CALLVALUE] = jumpPtr{opCallValue, true}
|
|
||||||
jumpTable[CALLDATALOAD] = jumpPtr{opCalldataLoad, true}
|
|
||||||
jumpTable[CALLDATASIZE] = jumpPtr{opCalldataSize, true}
|
|
||||||
jumpTable[CALLDATACOPY] = jumpPtr{opCalldataCopy, true}
|
|
||||||
jumpTable[CODESIZE] = jumpPtr{opCodeSize, true}
|
|
||||||
jumpTable[EXTCODESIZE] = jumpPtr{opExtCodeSize, true}
|
|
||||||
jumpTable[CODECOPY] = jumpPtr{opCodeCopy, true}
|
|
||||||
jumpTable[EXTCODECOPY] = jumpPtr{opExtCodeCopy, true}
|
|
||||||
jumpTable[GASPRICE] = jumpPtr{opGasprice, true}
|
|
||||||
jumpTable[BLOCKHASH] = jumpPtr{opBlockhash, true}
|
|
||||||
jumpTable[COINBASE] = jumpPtr{opCoinbase, true}
|
|
||||||
jumpTable[TIMESTAMP] = jumpPtr{opTimestamp, true}
|
|
||||||
jumpTable[NUMBER] = jumpPtr{opNumber, true}
|
|
||||||
jumpTable[DIFFICULTY] = jumpPtr{opDifficulty, true}
|
|
||||||
jumpTable[GASLIMIT] = jumpPtr{opGasLimit, true}
|
|
||||||
jumpTable[POP] = jumpPtr{opPop, true}
|
|
||||||
jumpTable[MLOAD] = jumpPtr{opMload, true}
|
|
||||||
jumpTable[MSTORE] = jumpPtr{opMstore, true}
|
|
||||||
jumpTable[MSTORE8] = jumpPtr{opMstore8, true}
|
|
||||||
jumpTable[SLOAD] = jumpPtr{opSload, true}
|
|
||||||
jumpTable[SSTORE] = jumpPtr{opSstore, true}
|
|
||||||
jumpTable[JUMPDEST] = jumpPtr{opJumpdest, true}
|
|
||||||
jumpTable[PC] = jumpPtr{nil, true}
|
|
||||||
jumpTable[MSIZE] = jumpPtr{opMsize, true}
|
|
||||||
jumpTable[GAS] = jumpPtr{opGas, true}
|
|
||||||
jumpTable[CREATE] = jumpPtr{opCreate, true}
|
|
||||||
jumpTable[CALL] = jumpPtr{opCall, true}
|
|
||||||
jumpTable[CALLCODE] = jumpPtr{opCallCode, true}
|
|
||||||
jumpTable[LOG0] = jumpPtr{makeLog(0), true}
|
|
||||||
jumpTable[LOG1] = jumpPtr{makeLog(1), true}
|
|
||||||
jumpTable[LOG2] = jumpPtr{makeLog(2), true}
|
|
||||||
jumpTable[LOG3] = jumpPtr{makeLog(3), true}
|
|
||||||
jumpTable[LOG4] = jumpPtr{makeLog(4), true}
|
|
||||||
jumpTable[SWAP1] = jumpPtr{makeSwap(1), true}
|
|
||||||
jumpTable[SWAP2] = jumpPtr{makeSwap(2), true}
|
|
||||||
jumpTable[SWAP3] = jumpPtr{makeSwap(3), true}
|
|
||||||
jumpTable[SWAP4] = jumpPtr{makeSwap(4), true}
|
|
||||||
jumpTable[SWAP5] = jumpPtr{makeSwap(5), true}
|
|
||||||
jumpTable[SWAP6] = jumpPtr{makeSwap(6), true}
|
|
||||||
jumpTable[SWAP7] = jumpPtr{makeSwap(7), true}
|
|
||||||
jumpTable[SWAP8] = jumpPtr{makeSwap(8), true}
|
|
||||||
jumpTable[SWAP9] = jumpPtr{makeSwap(9), true}
|
|
||||||
jumpTable[SWAP10] = jumpPtr{makeSwap(10), true}
|
|
||||||
jumpTable[SWAP11] = jumpPtr{makeSwap(11), true}
|
|
||||||
jumpTable[SWAP12] = jumpPtr{makeSwap(12), true}
|
|
||||||
jumpTable[SWAP13] = jumpPtr{makeSwap(13), true}
|
|
||||||
jumpTable[SWAP14] = jumpPtr{makeSwap(14), true}
|
|
||||||
jumpTable[SWAP15] = jumpPtr{makeSwap(15), true}
|
|
||||||
jumpTable[SWAP16] = jumpPtr{makeSwap(16), true}
|
|
||||||
jumpTable[PUSH1] = jumpPtr{makePush(1, big.NewInt(1)), true}
|
|
||||||
jumpTable[PUSH2] = jumpPtr{makePush(2, big.NewInt(2)), true}
|
|
||||||
jumpTable[PUSH3] = jumpPtr{makePush(3, big.NewInt(3)), true}
|
|
||||||
jumpTable[PUSH4] = jumpPtr{makePush(4, big.NewInt(4)), true}
|
|
||||||
jumpTable[PUSH5] = jumpPtr{makePush(5, big.NewInt(5)), true}
|
|
||||||
jumpTable[PUSH6] = jumpPtr{makePush(6, big.NewInt(6)), true}
|
|
||||||
jumpTable[PUSH7] = jumpPtr{makePush(7, big.NewInt(7)), true}
|
|
||||||
jumpTable[PUSH8] = jumpPtr{makePush(8, big.NewInt(8)), true}
|
|
||||||
jumpTable[PUSH9] = jumpPtr{makePush(9, big.NewInt(9)), true}
|
|
||||||
jumpTable[PUSH10] = jumpPtr{makePush(10, big.NewInt(10)), true}
|
|
||||||
jumpTable[PUSH11] = jumpPtr{makePush(11, big.NewInt(11)), true}
|
|
||||||
jumpTable[PUSH12] = jumpPtr{makePush(12, big.NewInt(12)), true}
|
|
||||||
jumpTable[PUSH13] = jumpPtr{makePush(13, big.NewInt(13)), true}
|
|
||||||
jumpTable[PUSH14] = jumpPtr{makePush(14, big.NewInt(14)), true}
|
|
||||||
jumpTable[PUSH15] = jumpPtr{makePush(15, big.NewInt(15)), true}
|
|
||||||
jumpTable[PUSH16] = jumpPtr{makePush(16, big.NewInt(16)), true}
|
|
||||||
jumpTable[PUSH17] = jumpPtr{makePush(17, big.NewInt(17)), true}
|
|
||||||
jumpTable[PUSH18] = jumpPtr{makePush(18, big.NewInt(18)), true}
|
|
||||||
jumpTable[PUSH19] = jumpPtr{makePush(19, big.NewInt(19)), true}
|
|
||||||
jumpTable[PUSH20] = jumpPtr{makePush(20, big.NewInt(20)), true}
|
|
||||||
jumpTable[PUSH21] = jumpPtr{makePush(21, big.NewInt(21)), true}
|
|
||||||
jumpTable[PUSH22] = jumpPtr{makePush(22, big.NewInt(22)), true}
|
|
||||||
jumpTable[PUSH23] = jumpPtr{makePush(23, big.NewInt(23)), true}
|
|
||||||
jumpTable[PUSH24] = jumpPtr{makePush(24, big.NewInt(24)), true}
|
|
||||||
jumpTable[PUSH25] = jumpPtr{makePush(25, big.NewInt(25)), true}
|
|
||||||
jumpTable[PUSH26] = jumpPtr{makePush(26, big.NewInt(26)), true}
|
|
||||||
jumpTable[PUSH27] = jumpPtr{makePush(27, big.NewInt(27)), true}
|
|
||||||
jumpTable[PUSH28] = jumpPtr{makePush(28, big.NewInt(28)), true}
|
|
||||||
jumpTable[PUSH29] = jumpPtr{makePush(29, big.NewInt(29)), true}
|
|
||||||
jumpTable[PUSH30] = jumpPtr{makePush(30, big.NewInt(30)), true}
|
|
||||||
jumpTable[PUSH31] = jumpPtr{makePush(31, big.NewInt(31)), true}
|
|
||||||
jumpTable[PUSH32] = jumpPtr{makePush(32, big.NewInt(32)), true}
|
|
||||||
jumpTable[DUP1] = jumpPtr{makeDup(1), true}
|
|
||||||
jumpTable[DUP2] = jumpPtr{makeDup(2), true}
|
|
||||||
jumpTable[DUP3] = jumpPtr{makeDup(3), true}
|
|
||||||
jumpTable[DUP4] = jumpPtr{makeDup(4), true}
|
|
||||||
jumpTable[DUP5] = jumpPtr{makeDup(5), true}
|
|
||||||
jumpTable[DUP6] = jumpPtr{makeDup(6), true}
|
|
||||||
jumpTable[DUP7] = jumpPtr{makeDup(7), true}
|
|
||||||
jumpTable[DUP8] = jumpPtr{makeDup(8), true}
|
|
||||||
jumpTable[DUP9] = jumpPtr{makeDup(9), true}
|
|
||||||
jumpTable[DUP10] = jumpPtr{makeDup(10), true}
|
|
||||||
jumpTable[DUP11] = jumpPtr{makeDup(11), true}
|
|
||||||
jumpTable[DUP12] = jumpPtr{makeDup(12), true}
|
|
||||||
jumpTable[DUP13] = jumpPtr{makeDup(13), true}
|
|
||||||
jumpTable[DUP14] = jumpPtr{makeDup(14), true}
|
|
||||||
jumpTable[DUP15] = jumpPtr{makeDup(15), true}
|
|
||||||
jumpTable[DUP16] = jumpPtr{makeDup(16), true}
|
|
||||||
|
|
||||||
jumpTable[RETURN] = jumpPtr{nil, true}
|
|
||||||
jumpTable[SUICIDE] = jumpPtr{nil, true}
|
|
||||||
jumpTable[JUMP] = jumpPtr{nil, true}
|
|
||||||
jumpTable[JUMPI] = jumpPtr{nil, true}
|
|
||||||
jumpTable[STOP] = jumpPtr{nil, true}
|
|
||||||
|
|
||||||
return jumpTable
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
// Copyright 2016 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package vm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
|
||||||
jumpTable := newJumpTable(¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(0))
|
|
||||||
if jumpTable[DELEGATECALL].valid {
|
|
||||||
t.Error("Expected DELEGATECALL not to be present")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, n := range []int64{1, 2, 100} {
|
|
||||||
jumpTable := newJumpTable(¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(n))
|
|
||||||
if !jumpTable[DELEGATECALL].valid {
|
|
||||||
t.Error("Expected DELEGATECALL to be present for block", n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -45,7 +45,7 @@ type LogConfig struct {
|
||||||
Limit int // maximum length of output, but zero means unlimited
|
Limit int // maximum length of output, but zero means unlimited
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLog is emitted to the Environment each cycle and lists information about the current internal state
|
// StructLog is emitted to the EVM each cycle and lists information about the current internal state
|
||||||
// prior to the execution of the statement.
|
// prior to the execution of the statement.
|
||||||
type StructLog struct {
|
type StructLog struct {
|
||||||
Pc uint64
|
Pc uint64
|
||||||
|
|
@ -65,7 +65,7 @@ type StructLog struct {
|
||||||
// Note that reference types are actual VM data structures; make copies
|
// Note that reference types are actual VM data structures; make copies
|
||||||
// if you need to retain them beyond the current call.
|
// if you need to retain them beyond the current call.
|
||||||
type Tracer interface {
|
type Tracer interface {
|
||||||
CaptureState(env *Environment, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
|
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogger is an EVM state logger and implements Tracer.
|
// StructLogger is an EVM state logger and implements Tracer.
|
||||||
|
|
@ -94,10 +94,10 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
|
||||||
// captureState logs a new structured log message and pushes it out to the environment
|
// captureState logs a new structured log message and pushes it out to the environment
|
||||||
//
|
//
|
||||||
// captureState also tracks SSTORE ops to track dirty values.
|
// captureState also tracks SSTORE ops to track dirty values.
|
||||||
func (l *StructLogger) CaptureState(env *Environment, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
|
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
|
||||||
// check if already accumulated the specified number of logs
|
// check if already accumulated the specified number of logs
|
||||||
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
|
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
|
||||||
return TraceLimitReachedError
|
return ErrTraceLimitReached
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialise new changed values storage container for this contract
|
// initialise new changed values storage container for this contract
|
||||||
|
|
@ -155,7 +155,7 @@ func (l *StructLogger) CaptureState(env *Environment, pc uint64, op OpCode, gas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create a new snaptshot of the EVM.
|
// create a new snaptshot of the EVM.
|
||||||
log := StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, env.Depth, err}
|
log := StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, env.depth, err}
|
||||||
|
|
||||||
l.logs = append(l.logs, log)
|
l.logs = append(l.logs, log)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func (d dummyStateDB) GetAccount(common.Address) Account {
|
||||||
|
|
||||||
func TestStoreCapture(t *testing.T) {
|
func TestStoreCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEnvironment(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
|
|
@ -79,7 +79,7 @@ func TestStorageCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
ref = &dummyContractRef{}
|
ref = &dummyContractRef{}
|
||||||
contract = NewContract(ref, ref, new(big.Int), new(big.Int))
|
contract = NewContract(ref, ref, new(big.Int), new(big.Int))
|
||||||
env = NewEnvironment(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
env = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue