diff options
-rw-r--r-- | accounts/abi/abi.go | 79 | ||||
-rw-r--r-- | accounts/abi/abi_test.go | 205 | ||||
-rw-r--r-- | accounts/abi/numbers.go | 2 | ||||
-rw-r--r-- | accounts/abi/numbers_test.go | 4 | ||||
-rw-r--r-- | accounts/abi/type.go | 188 | ||||
-rw-r--r-- | cmd/geth/main.go | 7 | ||||
-rw-r--r-- | cmd/geth/usage.go | 2 | ||||
-rw-r--r-- | cmd/utils/flags.go | 41 | ||||
-rw-r--r-- | core/canary.go | 51 | ||||
-rw-r--r-- | eth/backend.go | 4 | ||||
-rw-r--r-- | miner/worker.go | 30 | ||||
-rw-r--r-- | p2p/rlpx.go | 10 |
12 files changed, 354 insertions, 269 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 91f9700d9..9ef7c0f0d 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" "io" + "math/big" "reflect" "strings" @@ -63,9 +64,8 @@ func (abi ABI) pack(method Method, args ...interface{}) ([]byte, error) { return nil, fmt.Errorf("`%s` %v", method.Name, err) } - // check for a string or bytes input type - switch input.Type.T { - case StringTy, BytesTy: + // check for a slice type (string, bytes, slice) + if input.Type.T == StringTy || input.Type.T == BytesTy || input.Type.IsSlice { // calculate the offset offset := len(method.Inputs)*32 + len(variableInput) // set the offset @@ -73,7 +73,7 @@ func (abi ABI) pack(method Method, args ...interface{}) ([]byte, error) { // Append the packed output to the variable input. The variable input // will be appended at the end of the input. variableInput = append(variableInput, packed...) - default: + } else { // append the packed value to the input ret = append(ret, packed...) } @@ -117,11 +117,80 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { return append(method.Id(), arguments...), nil } +// toGoSliceType prses the input and casts it to the proper slice defined by the ABI +// argument in T. +func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { + index := i * 32 + // The slice must, at very least be large enough for the index+32 which is exactly the size required + // for the [offset in output, size of offset]. + if index+32 > len(output) { + return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), index+32) + } + + // first we need to create a slice of the type + var refSlice reflect.Value + switch t.Type.T { + case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int. + refSlice = reflect.ValueOf([]*big.Int(nil)) + case AddressTy: // address must be of slice Address + refSlice = reflect.ValueOf([]common.Address(nil)) + case HashTy: // hash must be of slice hash + refSlice = reflect.ValueOf([]common.Hash(nil)) + default: // no other types are supported + return nil, fmt.Errorf("abi: unsupported slice type %v", t.Type.T) + } + // get the offset which determines the start of this array ... + offset := int(common.BytesToBig(output[index : index+32]).Uint64()) + if offset+32 > len(output) { + return nil, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32) + } + + slice := output[offset:] + // ... starting with the size of the array in elements ... + size := int(common.BytesToBig(slice[:32]).Uint64()) + slice = slice[32:] + // ... and make sure that we've at the very least the amount of bytes + // available in the buffer. + if size*32 > len(slice) { + return nil, fmt.Errorf("abi: cannot marshal in to go slice: insufficient size output %d require %d", len(output), offset+32+size*32) + } + + // reslice to match the required size + slice = slice[:(size * 32)] + for i := 0; i < size; i++ { + var ( + inter interface{} // interface type + returnOutput = slice[i*32 : i*32+32] // the return output + ) + + // set inter to the correct type (cast) + switch t.Type.T { + case IntTy, UintTy: + inter = common.BytesToBig(returnOutput) + case BoolTy: + inter = common.BytesToBig(returnOutput).Uint64() > 0 + case AddressTy: + inter = common.BytesToAddress(returnOutput) + case HashTy: + inter = common.BytesToHash(returnOutput) + } + // append the item to our reflect slice + refSlice = reflect.Append(refSlice, reflect.ValueOf(inter)) + } + + // return the interface + return refSlice.Interface(), nil +} + // toGoType parses the input and casts it to the proper type defined by the ABI // argument in T. func toGoType(i int, t Argument, output []byte) (interface{}, error) { - index := i * 32 + // we need to treat slices differently + if t.Type.IsSlice { + return toGoSlice(i, t, output) + } + index := i * 32 if index+32 > len(output) { return nil, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), index+32) } diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 66d2e1b39..a1b3e62d9 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -49,7 +49,9 @@ const jsondata2 = ` { "type" : "function", "name" : "foo", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] }, { "type" : "function", "name" : "bar", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] }, { "type" : "function", "name" : "slice", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] }, - { "type" : "function", "name" : "slice256", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] } + { "type" : "function", "name" : "slice256", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }, + { "type" : "function", "name" : "sliceAddress", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] }, + { "type" : "function", "name" : "sliceMultiAddress", "const" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] } ]` func TestType(t *testing.T) { @@ -57,7 +59,7 @@ func TestType(t *testing.T) { if err != nil { t.Error(err) } - if typ.Kind != reflect.Ptr { + if typ.Kind != reflect.Uint { t.Error("expected uint32 to have kind Ptr") } @@ -65,10 +67,10 @@ func TestType(t *testing.T) { if err != nil { t.Error(err) } - if typ.Kind != reflect.Slice { - t.Error("expected uint32[] to have type slice") + if !typ.IsSlice { + t.Error("expected uint32[] to be slice") } - if typ.Type != ubig_ts { + if typ.Type != ubig_t { t.Error("expcted uith32[] to have type uint64") } @@ -76,13 +78,13 @@ func TestType(t *testing.T) { if err != nil { t.Error(err) } - if typ.Kind != reflect.Slice { - t.Error("expected uint32[2] to have kind slice") + if !typ.IsSlice { + t.Error("expected uint32[2] to be slice") } - if typ.Type != ubig_ts { + if typ.Type != ubig_t { t.Error("expcted uith32[2] to have type uint64") } - if typ.Size != 2 { + if typ.SliceSize != 2 { t.Error("expected uint32[2] to have a size of 2") } } @@ -147,10 +149,6 @@ func TestTestNumbers(t *testing.T) { t.Errorf("expected send( ptr ) to throw, requires *big.Int instead of *int") } - if _, err := abi.Pack("send", 1000); err != nil { - t.Error("expected send(1000) to cast to big") - } - if _, err := abi.Pack("test", uint32(1000)); err != nil { t.Error(err) } @@ -202,17 +200,7 @@ func TestTestSlice(t *testing.T) { t.FailNow() } - addr := make([]byte, 20) - if _, err := abi.Pack("address", addr); err != nil { - t.Error(err) - } - - addr = make([]byte, 21) - if _, err := abi.Pack("address", addr); err == nil { - t.Error("expected address of 21 width to throw") - } - - slice := make([]byte, 2) + slice := make([]uint64, 2) if _, err := abi.Pack("uint64[2]", slice); err != nil { t.Error(err) } @@ -222,16 +210,18 @@ func TestTestSlice(t *testing.T) { } } -func TestTestAddress(t *testing.T) { +func TestImplicitTypeCasts(t *testing.T) { abi, err := JSON(strings.NewReader(jsondata2)) if err != nil { t.Error(err) t.FailNow() } - addr := make([]byte, 20) - if _, err := abi.Pack("address", addr); err != nil { - t.Error(err) + slice := make([]uint8, 2) + _, err = abi.Pack("uint64[2]", slice) + expStr := "`uint64[2]` abi: cannot use type uint8 as type uint64" + if err.Error() != expStr { + t.Errorf("expected %v, got %v", expStr, err) } } @@ -310,44 +300,69 @@ func TestPackSlice(t *testing.T) { } sig := crypto.Keccak256([]byte("slice(uint32[2])"))[:4] - sig = append(sig, make([]byte, 64)...) - sig[35] = 1 - sig[67] = 2 + sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) packed, err := abi.Pack("slice", []uint32{1, 2}) if err != nil { t.Error(err) - t.FailNow() } if !bytes.Equal(packed, sig) { t.Errorf("expected %x got %x", sig, packed) } -} -func TestPackSliceBig(t *testing.T) { - abi, err := JSON(strings.NewReader(jsondata2)) + var addrA, addrB = common.Address{1}, common.Address{2} + sig = abi.Methods["sliceAddress"].Id() + sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes(addrA[:], 32)...) + sig = append(sig, common.LeftPadBytes(addrB[:], 32)...) + + packed, err = abi.Pack("sliceAddress", []common.Address{addrA, addrB}) if err != nil { - t.Error(err) - t.FailNow() + t.Fatal(err) + } + if !bytes.Equal(packed, sig) { + t.Errorf("expected %x got %x", sig, packed) } - sig := crypto.Keccak256([]byte("slice256(uint256[2])"))[:4] - sig = append(sig, make([]byte, 64)...) - sig[35] = 1 - sig[67] = 2 + var addrC, addrD = common.Address{3}, common.Address{4} + sig = abi.Methods["sliceMultiAddress"].Id() + sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes(addrA[:], 32)...) + sig = append(sig, common.LeftPadBytes(addrB[:], 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes(addrC[:], 32)...) + sig = append(sig, common.LeftPadBytes(addrD[:], 32)...) - packed, err := abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)}) + packed, err = abi.Pack("sliceMultiAddress", []common.Address{addrA, addrB}, []common.Address{addrC, addrD}) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(packed, sig) { + t.Errorf("expected %x got %x", sig, packed) + } + + sig = crypto.Keccak256([]byte("slice256(uint256[2])"))[:4] + sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) + sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) + + packed, err = abi.Pack("slice256", []*big.Int{big.NewInt(1), big.NewInt(2)}) if err != nil { t.Error(err) - t.FailNow() } if !bytes.Equal(packed, sig) { t.Errorf("expected %x got %x", sig, packed) } } - func ExampleJSON() { const definition = `[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBar","outputs":[{"name":"","type":"bool"}],"type":"function"}]` @@ -370,7 +385,7 @@ func TestInputVariableInputLength(t *testing.T) { { "type" : "function", "name" : "strOne", "const" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] }, { "type" : "function", "name" : "bytesOne", "const" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] }, { "type" : "function", "name" : "strTwo", "const" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "str1", "type" : "string" } ] } -]` + ]` abi, err := JSON(strings.NewReader(definition)) if err != nil { @@ -493,35 +508,6 @@ func TestInputVariableInputLength(t *testing.T) { } } -func TestBytes(t *testing.T) { - const definition = `[ - { "type" : "function", "name" : "balance", "const" : true, "inputs" : [ { "name" : "address", "type" : "bytes20" } ] }, - { "type" : "function", "name" : "send", "const" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] } -]` - - abi, err := JSON(strings.NewReader(definition)) - if err != nil { - t.Fatal(err) - } - ok := make([]byte, 20) - _, err = abi.Pack("balance", ok) - if err != nil { - t.Error(err) - } - - toosmall := make([]byte, 19) - _, err = abi.Pack("balance", toosmall) - if err != nil { - t.Error(err) - } - - toobig := make([]byte, 21) - _, err = abi.Pack("balance", toobig) - if err == nil { - t.Error("expected error") - } -} - func TestDefaultFunctionParsing(t *testing.T) { const definition = `[{ "name" : "balance" }]` @@ -713,12 +699,15 @@ func TestUnmarshal(t *testing.T) { { "name" : "bytes", "const" : false, "outputs": [ { "type": "bytes" } ] }, { "name" : "fixed", "const" : false, "outputs": [ { "type": "bytes32" } ] }, { "name" : "multi", "const" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] }, + { "name" : "addressSliceSingle", "const" : false, "outputs": [ { "type": "address[]" } ] }, + { "name" : "addressSliceDouble", "const" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] }, { "name" : "mixedBytes", "const" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]` abi, err := JSON(strings.NewReader(definition)) if err != nil { t.Fatal(err) } + buff := new(bytes.Buffer) // marshal int var Int *big.Int @@ -743,7 +732,6 @@ func TestUnmarshal(t *testing.T) { } // marshal dynamic bytes max length 32 - buff := new(bytes.Buffer) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) bytesOut := common.RightPadBytes([]byte("hello"), 32) @@ -862,4 +850,71 @@ func TestUnmarshal(t *testing.T) { if !bytes.Equal(fixed, out[1].([]byte)) { t.Errorf("expected %x, got %x", fixed, out[1]) } + + // marshal address slice + buff.Reset() + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020")) // offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size + buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000")) + + var outAddr []common.Address + err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes()) + if err != nil { + t.Fatal("didn't expect error:", err) + } + + if len(outAddr) != 1 { + t.Fatal("expected 1 item, got", len(outAddr)) + } + + if outAddr[0] != (common.Address{1}) { + t.Errorf("expected %x, got %x", common.Address{1}, outAddr[0]) + } + + // marshal multiple address slice + buff.Reset() + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040")) // offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000080")) // offset + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")) // size + buff.Write(common.Hex2Bytes("0000000000000000000000000100000000000000000000000000000000000000")) + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002")) // size + buff.Write(common.Hex2Bytes("0000000000000000000000000200000000000000000000000000000000000000")) + buff.Write(common.Hex2Bytes("0000000000000000000000000300000000000000000000000000000000000000")) + + var outAddrStruct struct { + A []common.Address + B []common.Address + } + err = abi.Unpack(&outAddrStruct, "addressSliceDouble", buff.Bytes()) + if err != nil { + t.Fatal("didn't expect error:", err) + } + + if len(outAddrStruct.A) != 1 { + t.Fatal("expected 1 item, got", len(outAddrStruct.A)) + } + + if outAddrStruct.A[0] != (common.Address{1}) { + t.Errorf("expected %x, got %x", common.Address{1}, outAddrStruct.A[0]) + } + + if len(outAddrStruct.B) != 2 { + t.Fatal("expected 1 item, got", len(outAddrStruct.B)) + } + + if outAddrStruct.B[0] != (common.Address{2}) { + t.Errorf("expected %x, got %x", common.Address{2}, outAddrStruct.B[0]) + } + if outAddrStruct.B[1] != (common.Address{3}) { + t.Errorf("expected %x, got %x", common.Address{3}, outAddrStruct.B[1]) + } + + // marshal invalid address slice + buff.Reset() + buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000100")) + + err = abi.Unpack(&outAddr, "addressSliceSingle", buff.Bytes()) + if err == nil { + t.Fatal("expected error:", err) + } } diff --git a/accounts/abi/numbers.go b/accounts/abi/numbers.go index 02609d567..084701de5 100644 --- a/accounts/abi/numbers.go +++ b/accounts/abi/numbers.go @@ -117,8 +117,6 @@ func packNum(value reflect.Value, to byte) []byte { // checks whether the given reflect value is signed. This also works for slices with a number type func isSigned(v reflect.Value) bool { switch v.Type() { - case ubig_ts, big_ts, big_t, ubig_t: - return true case int_ts, int8_ts, int16_ts, int32_ts, int64_ts, int_t, int8_t, int16_t, int32_t, int64_t: return true } diff --git a/accounts/abi/numbers_test.go b/accounts/abi/numbers_test.go index 78dc57543..6590e41a6 100644 --- a/accounts/abi/numbers_test.go +++ b/accounts/abi/numbers_test.go @@ -81,8 +81,4 @@ func TestSigned(t *testing.T) { if !isSigned(reflect.ValueOf(int(10))) { t.Error() } - - if !isSigned(reflect.ValueOf(big.NewInt(10))) { - t.Error() - } } diff --git a/accounts/abi/type.go b/accounts/abi/type.go index c08b744f7..5a5a5ac49 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -40,6 +40,9 @@ const ( // Type is the reflection of the supported argument type type Type struct { + IsSlice bool + SliceSize int + Kind reflect.Kind Type reflect.Type Size int @@ -47,6 +50,11 @@ type Type struct { stringKind string // holds the unparsed string for deriving signatures } +var ( + fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?") + typeRegex = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?") +) + // NewType returns a fully parsed Type given by the input string or an error if it can't be parsed. // // Strings can be in the format of: @@ -61,98 +69,87 @@ type Type struct { // address int256 uint256 real[2] func NewType(t string) (typ Type, err error) { // 1. full string 2. type 3. (opt.) is slice 4. (opt.) size - freg, err := regexp.Compile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?") - if err != nil { - return Type{}, err - } - res := freg.FindAllStringSubmatch(t, -1)[0] - var ( - isslice bool - size int - ) + // parse the full representation of the abi-type definition; including: + // * full string + // * type + // * is slice + // * slice size + res := fullTypeRegex.FindAllStringSubmatch(t, -1)[0] + + // check if type is slice and parse type. switch { case res[3] != "": // err is ignored. Already checked for number through the regexp - size, _ = strconv.Atoi(res[3]) - isslice = true + typ.SliceSize, _ = strconv.Atoi(res[3]) + typ.IsSlice = true case res[2] != "": - isslice = true - size = -1 + typ.IsSlice, typ.SliceSize = true, -1 case res[0] == "": - return Type{}, fmt.Errorf("type parse error for `%s`", t) + return Type{}, fmt.Errorf("abi: type parse error: %s", t) } - treg, err := regexp.Compile("([a-zA-Z]+)([0-9]*)?") - if err != nil { - return Type{}, err + // parse the type and size of the abi-type. + parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0] + // varSize is the size of the variable + var varSize int + if len(parsedType[2]) > 0 { + var err error + varSize, err = strconv.Atoi(parsedType[2]) + if err != nil { + return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err) + } } - - parsedType := treg.FindAllStringSubmatch(res[1], -1)[0] - vsize, _ := strconv.Atoi(parsedType[2]) - vtype := parsedType[1] - // substitute canonical representation - if vsize == 0 && (vtype == "int" || vtype == "uint") { - vsize = 256 + // varType is the parsed abi type + varType := parsedType[1] + // substitute canonical integer + if varSize == 0 && (varType == "int" || varType == "uint") { + varSize = 256 t += "256" } - if isslice { - typ.Kind = reflect.Slice - typ.Size = size - switch vtype { - case "int": - typ.Type = big_ts - case "uint": - typ.Type = ubig_ts - default: - return Type{}, fmt.Errorf("unsupported arg slice type: %s", t) - } - } else { - switch vtype { - case "int": - typ.Kind = reflect.Ptr - typ.Type = big_t - typ.Size = 256 - typ.T = IntTy - case "uint": - typ.Kind = reflect.Ptr - typ.Type = ubig_t - typ.Size = 256 - typ.T = UintTy - case "bool": - typ.Kind = reflect.Bool - typ.T = BoolTy - case "real": // TODO - typ.Kind = reflect.Invalid - case "address": - typ.Kind = reflect.Slice - typ.Type = address_t - typ.Size = 20 - typ.T = AddressTy - case "string": - typ.Kind = reflect.String - typ.Size = -1 - typ.T = StringTy - if vsize > 0 { - typ.Size = 32 - } - case "hash": - typ.Kind = reflect.Slice + switch varType { + case "int": + typ.Kind = reflect.Int + typ.Type = big_t + typ.Size = varSize + typ.T = IntTy + case "uint": + typ.Kind = reflect.Uint + typ.Type = ubig_t + typ.Size = varSize + typ.T = UintTy + case "bool": + typ.Kind = reflect.Bool + typ.T = BoolTy + case "real": // TODO + typ.Kind = reflect.Invalid + case "address": + typ.Type = address_t + typ.Size = 20 + typ.T = AddressTy + case "string": + typ.Kind = reflect.String + typ.Size = -1 + typ.T = StringTy + if varSize > 0 { typ.Size = 32 - typ.Type = hash_t - typ.T = HashTy - case "bytes": - typ.Kind = reflect.Slice - typ.Type = byte_ts - typ.Size = vsize - if vsize == 0 { - typ.T = BytesTy - } else { - typ.T = FixedBytesTy - } - default: - return Type{}, fmt.Errorf("unsupported arg type: %s", t) } + case "hash": + typ.Kind = reflect.Array + typ.Size = 32 + typ.Type = hash_t + typ.T = HashTy + case "bytes": + typ.Kind = reflect.Array + typ.Type = byte_ts + typ.Size = varSize + if varSize == 0 { + typ.T = BytesTy + } else { + typ.T = FixedBytesTy + } + default: + return Type{}, fmt.Errorf("unsupported arg type: %s", t) } typ.stringKind = t @@ -180,14 +177,26 @@ func (t Type) pack(v interface{}) ([]byte, error) { value := reflect.ValueOf(v) switch kind := value.Kind(); kind { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + // check input is unsigned if t.Type != ubig_t { - return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v) + return nil, fmt.Errorf("abi: type mismatch: %s for %T", t.Type, v) + } + + // no implicit type casting + if int(value.Type().Size()*8) != t.Size { + return nil, fmt.Errorf("abi: cannot use type %T as type uint%d", v, t.Size) } + return packNum(value, t.T), nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if t.Type != ubig_t { return nil, fmt.Errorf("type mismatch: %s for %T", t.Type, v) } + + // no implicit type casting + if int(value.Type().Size()*8) != t.Size { + return nil, fmt.Errorf("abi: cannot use type %T as type uint%d", v, t.Size) + } return packNum(value, t.T), nil case reflect.Ptr: // If the value is a ptr do a assign check (only used by @@ -203,30 +212,29 @@ func (t Type) pack(v interface{}) ([]byte, error) { return packBytesSlice([]byte(value.String()), value.Len()), nil case reflect.Slice: - // if the param is a bytes type, pack the slice up as a string + // Byte slice is a special case, it gets treated as a single value if t.T == BytesTy { return packBytesSlice(value.Bytes(), value.Len()), nil } - if t.Size > -1 && value.Len() > t.Size { + if t.SliceSize > -1 && value.Len() > t.SliceSize { return nil, fmt.Errorf("%v out of bound. %d for %d", value.Kind(), value.Len(), t.Size) } - // Address is a special slice. The slice acts as one rather than a list of elements. - if t.T == AddressTy { - return common.LeftPadBytes(v.([]byte), 32), nil - } - // Signed / Unsigned check - if (t.T != IntTy && isSigned(value)) || (t.T == UintTy && isSigned(value)) { + if value.Type() == big_t && (t.T != IntTy && isSigned(value)) || (t.T == UintTy && isSigned(value)) { return nil, fmt.Errorf("slice of incompatible types.") } var packed []byte for i := 0; i < value.Len(); i++ { - packed = append(packed, packNum(value.Index(i), t.T)...) + val, err := t.pack(value.Index(i).Interface()) + if err != nil { + return nil, err + } + packed = append(packed, val...) } - return packed, nil + return packBytesSlice(packed, value.Len()), nil case reflect.Bool: if value.Bool() { return common.LeftPadBytes(common.Big1.Bytes(), 32), nil diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 5d5ab4559..645743c13 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -312,6 +312,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.MiningEnabledFlag, utils.MiningGPUFlag, utils.AutoDAGFlag, + utils.TargetGasLimitFlag, utils.NATFlag, utils.NatspecEnabledFlag, utils.NoDiscoverFlag, @@ -359,6 +360,12 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso go metrics.CollectProcessMetrics(3 * time.Second) utils.SetupNetwork(ctx) + + // Deprecation warning. + if ctx.GlobalIsSet(utils.GenesisFileFlag.Name) { + common.PrintDepricationWarning("--genesis is deprecated. Switch to use 'geth init /path/to/file'") + } + return nil } diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index a31532bea..e2adf7305 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -121,10 +121,10 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.MiningEnabledFlag, utils.MinerThreadsFlag, - utils.TargetGasLimitFlag, utils.MiningGPUFlag, utils.AutoDAGFlag, utils.EtherbaseFlag, + utils.TargetGasLimitFlag, utils.GasPriceFlag, utils.ExtraDataFlag, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3f54b40ca..2f10938e3 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -22,11 +22,13 @@ import ( "io/ioutil" "math" "math/big" + "math/rand" "os" "path/filepath" "runtime" "strconv" "strings" + "time" "github.com/codegangsta/cli" "github.com/ethereum/ethash" @@ -659,6 +661,16 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. // Configure the Ethereum service accman := MakeAccountManager(ctx) + // initialise new random number generator + rand := rand.New(rand.NewSource(time.Now().UnixNano())) + // get enabled jit flag + jitEnabled := ctx.GlobalBool(VMEnableJitFlag.Name) + // if the jit is not enabled enable it for 10 pct of the people + if !jitEnabled && rand.Float64() < 0.1 { + jitEnabled = true + glog.V(logger.Info).Infoln("You're one of the lucky few that will try out the JIT VM (random). If you get a consensus failure please be so kind to report this incident with the block hash that failed. You can switch to the regular VM by setting --jitvm=false") + } + ethConf := ð.Config{ ChainConfig: MustMakeChainConfig(ctx), Genesis: MakeGenesisBlock(ctx), @@ -673,7 +685,7 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. ExtraData: MakeMinerExtra(extra, ctx), NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name), DocRoot: ctx.GlobalString(DocRootFlag.Name), - EnableJit: ctx.GlobalBool(VMEnableJitFlag.Name), + EnableJit: jitEnabled, ForceJit: ctx.GlobalBool(VMForceJitFlag.Name), GasPrice: common.String2Big(ctx.GlobalString(GasPriceFlag.Name)), GpoMinGasPrice: common.String2Big(ctx.GlobalString(GpoMinGasPriceFlag.Name)), @@ -772,23 +784,22 @@ func MustMakeChainConfig(ctx *cli.Context) *core.ChainConfig { ) defer db.Close() - chainConfig, err := core.GetChainConfig(db, genesis.Hash()) - if err != nil { - if err != core.ChainConfigNotFoundErr { + if genesis != nil { + // Exsting genesis block, use stored config if available. + storedConfig, err := core.GetChainConfig(db, genesis.Hash()) + if err == nil { + return storedConfig + } else if err != core.ChainConfigNotFoundErr { Fatalf("Could not make chain configuration: %v", err) } - var homesteadBlockNo *big.Int - if ctx.GlobalBool(TestNetFlag.Name) { - homesteadBlockNo = params.TestNetHomesteadBlock - } else { - homesteadBlockNo = params.MainNetHomesteadBlock - } - - chainConfig = &core.ChainConfig{ - HomesteadBlock: homesteadBlockNo, - } } - return chainConfig + var homesteadBlockNo *big.Int + if ctx.GlobalBool(TestNetFlag.Name) { + homesteadBlockNo = params.TestNetHomesteadBlock + } else { + homesteadBlockNo = params.MainNetHomesteadBlock + } + return &core.ChainConfig{HomesteadBlock: homesteadBlockNo} } // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. diff --git a/core/canary.go b/core/canary.go deleted file mode 100644 index 69db18e58..000000000 --- a/core/canary.go +++ /dev/null @@ -1,51 +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 core - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/state" -) - -var ( - jeff = common.HexToAddress("959c33de5961820567930eccce51ea715c496f85") - vitalik = common.HexToAddress("c8158da0b567a8cc898991c2c2a073af67dc03a9") - christoph = common.HexToAddress("7a19a893f91d5b6e2cdf941b6acbba2cbcf431ee") - gav = common.HexToAddress("539dd9aaf45c3feb03f9c004f4098bd3268fef6b") -) - -// Canary will check the 0'd address of the 4 contracts above. -// If two or more are set to anything other than a 0 the canary -// dies a horrible death. -func Canary(statedb *state.StateDB) bool { - var r int - if (statedb.GetState(jeff, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) { - r++ - } - if (statedb.GetState(gav, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) { - r++ - } - if (statedb.GetState(christoph, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) { - r++ - } - if (statedb.GetState(vitalik, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) { - r++ - } - return r > 1 -} diff --git a/eth/backend.go b/eth/backend.go index d4f72515e..20f516610 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -169,10 +169,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Load up any custom genesis block if requested if len(config.Genesis) > 0 { - // Using println instead of glog to make sure it **always** displays regardless of - // verbosity settings. - common.PrintDepricationWarning("--genesis is deprecated. Switch to use 'geth init /path/to/file'") - block, err := core.WriteGenesisBlock(chainDb, strings.NewReader(config.Genesis)) if err != nil { return nil, err diff --git a/miner/worker.go b/miner/worker.go index c45945b87..c5fb82b45 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -351,19 +351,15 @@ func (self *worker) wait() { } } +// push sends a new work task to currently live miner agents. func (self *worker) push(work *Work) { - if atomic.LoadInt32(&self.mining) == 1 { - if core.Canary(work.state) { - glog.Infoln("Toxicity levels rising to deadly levels. Your canary has died. You can go back or continue down the mineshaft --more--") - glog.Infoln("You turn back and abort mining") - return - } - // push new work to agents - for agent := range self.agents { - atomic.AddInt32(&self.atWork, 1) - if agent.Work() != nil { - agent.Work() <- work - } + if atomic.LoadInt32(&self.mining) != 1 { + return + } + for agent := range self.agents { + atomic.AddInt32(&self.atWork, 1) + if ch := agent.Work(); ch != nil { + ch <- work } } } @@ -662,7 +658,15 @@ func (env *Work) commitTransactions(mux *event.TypeMux, transactions types.Trans func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) { snap := env.state.Copy() - receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, env.config.VmConfig) + + // this is a bit of a hack to force jit for the miners + config := env.config.VmConfig + if !(config.EnableJit && config.ForceJit) { + config.EnableJit = false + } + config.ForceJit = false // disable forcing jit + + receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config) if err != nil { env.state.Set(snap) return err, nil diff --git a/p2p/rlpx.go b/p2p/rlpx.go index ddfafe9a4..2a9bdc121 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -31,7 +31,6 @@ import ( "io" mrand "math/rand" "net" - "os" "sync" "time" @@ -262,8 +261,6 @@ func (h *encHandshake) staticSharedSecret(prv *ecdsa.PrivateKey) ([]byte, error) return ecies.ImportECDSA(prv).GenerateShared(h.remotePub, sskLen, sskLen) } -var configSendEIP = os.Getenv("RLPX_EIP8") != "" - // initiatorEncHandshake negotiates a session token on conn. // it should be called on the dialing side of the connection. // @@ -274,12 +271,7 @@ func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID d if err != nil { return s, err } - var authPacket []byte - if configSendEIP { - authPacket, err = sealEIP8(authMsg, h) - } else { - authPacket, err = authMsg.sealPlain(h) - } + authPacket, err := sealEIP8(authMsg, h) if err != nil { return s, err } |