mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
341132925f
533 changed files with 31381 additions and 11594 deletions
10
.travis.yml
10
.travis.yml
|
|
@ -13,15 +13,15 @@ matrix:
|
||||||
go: 1.6.2
|
go: 1.6.2
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
go: 1.7
|
go: 1.7.4
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.7
|
go: 1.7.4
|
||||||
|
|
||||||
# This builder does the Ubuntu PPA and Linux Azure uploads
|
# This builder does the Ubuntu PPA and Linux Azure uploads
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.7
|
go: 1.7.4
|
||||||
env:
|
env:
|
||||||
- ubuntu-ppa
|
- ubuntu-ppa
|
||||||
- azure-linux
|
- azure-linux
|
||||||
|
|
@ -55,7 +55,7 @@ matrix:
|
||||||
|
|
||||||
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
|
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.7
|
go: 1.7.4
|
||||||
env:
|
env:
|
||||||
- azure-osx
|
- azure-osx
|
||||||
- mobile
|
- mobile
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,7 @@ The go-ubiq project comes with several wrappers/executables found in the `cmd` d
|
||||||
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
|
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
|
||||||
| `gubiqrpctest` | Developer utility tool to support our [ubiq/rpc-test](https://github.com/ubiq/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ubiq/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ubiq/rpc-tests/blob/master/README.md) for details. |
|
| `gubiqrpctest` | Developer utility tool to support our [ubiq/rpc-test](https://github.com/ubiq/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ubiq/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ubiq/rpc-tests/blob/master/README.md) for details. |
|
||||||
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ubiq/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
|
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ubiq/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
|
||||||
| `bzzd` | swarm daemon. This is the entrypoint for the swarm network. `bzzd --help` for command line options. See https://swarm-guide.readthedocs.io for swarm documentation. |
|
| `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. |
|
||||||
| `bzzup` | swarm command line file uploader. `bzzup --help` for command line options |
|
|
||||||
| `bzzhash` | command to calculate the swarm hash of a file or directory. `bzzhash --help` for command line options |
|
|
||||||
|
|
||||||
## Running gubiq
|
## Running gubiq
|
||||||
|
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.5.5
|
1.5.7
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -345,12 +387,13 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) error {
|
||||||
|
|
||||||
func (abi *ABI) UnmarshalJSON(data []byte) error {
|
func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||||
var fields []struct {
|
var fields []struct {
|
||||||
Type string
|
Type string
|
||||||
Name string
|
Name string
|
||||||
Constant bool
|
Constant bool
|
||||||
Indexed bool
|
Indexed bool
|
||||||
Inputs []Argument
|
Anonymous bool
|
||||||
Outputs []Argument
|
Inputs []Argument
|
||||||
|
Outputs []Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &fields); err != nil {
|
if err := json.Unmarshal(data, &fields); err != nil {
|
||||||
|
|
@ -375,8 +418,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
case "event":
|
case "event":
|
||||||
abi.Events[field.Name] = Event{
|
abi.Events[field.Name] = Event{
|
||||||
Name: field.Name,
|
Name: field.Name,
|
||||||
Inputs: field.Inputs,
|
Anonymous: field.Anonymous,
|
||||||
|
Inputs: field.Inputs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -752,23 +789,58 @@ func TestDefaultFunctionParsing(t *testing.T) {
|
||||||
func TestBareEvents(t *testing.T) {
|
func TestBareEvents(t *testing.T) {
|
||||||
const definition = `[
|
const definition = `[
|
||||||
{ "type" : "event", "name" : "balance" },
|
{ "type" : "event", "name" : "balance" },
|
||||||
{ "type" : "event", "name" : "name" }]`
|
{ "type" : "event", "name" : "anon", "anonymous" : true},
|
||||||
|
{ "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] }
|
||||||
|
]`
|
||||||
|
|
||||||
|
arg0, _ := NewType("uint256")
|
||||||
|
arg1, _ := NewType("address")
|
||||||
|
|
||||||
|
expectedEvents := map[string]struct {
|
||||||
|
Anonymous bool
|
||||||
|
Args []Argument
|
||||||
|
}{
|
||||||
|
"balance": {false, nil},
|
||||||
|
"anon": {true, nil},
|
||||||
|
"args": {false, []Argument{
|
||||||
|
{Name: "arg0", Type: arg0, Indexed: false},
|
||||||
|
{Name: "arg1", Type: arg1, Indexed: true},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(abi.Events) != 2 {
|
if len(abi.Events) != len(expectedEvents) {
|
||||||
t.Error("expected 2 events")
|
t.Fatalf("invalid number of events after parsing, want %d, got %d", len(expectedEvents), len(abi.Events))
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := abi.Events["balance"]; !ok {
|
for name, exp := range expectedEvents {
|
||||||
t.Error("expected 'balance' event to be present")
|
got, ok := abi.Events[name]
|
||||||
}
|
if !ok {
|
||||||
|
t.Errorf("could not found event %s", name)
|
||||||
if _, ok := abi.Events["name"]; !ok {
|
continue
|
||||||
t.Error("expected 'name' event to be present")
|
}
|
||||||
|
if got.Anonymous != exp.Anonymous {
|
||||||
|
t.Errorf("invalid anonymous indication for event %s, want %v, got %v", name, exp.Anonymous, got.Anonymous)
|
||||||
|
}
|
||||||
|
if len(got.Inputs) != len(exp.Args) {
|
||||||
|
t.Errorf("invalid number of args, want %d, got %d", len(exp.Args), len(got.Inputs))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i, arg := range exp.Args {
|
||||||
|
if arg.Name != got.Inputs[i].Name {
|
||||||
|
t.Errorf("events[%s].Input[%d] has an invalid name, want %s, got %s", name, i, arg.Name, got.Inputs[i].Name)
|
||||||
|
}
|
||||||
|
if arg.Indexed != got.Inputs[i].Indexed {
|
||||||
|
t.Errorf("events[%s].Input[%d] has an invalid indexed indication, want %v, got %v", name, i, arg.Indexed, got.Inputs[i].Indexed)
|
||||||
|
}
|
||||||
|
if arg.Type.T != got.Inputs[i].Type.T {
|
||||||
|
t.Errorf("events[%s].Input[%d] has an invalid type, want %x, got %x", name, i, arg.Type.T, got.Inputs[i].Type.T)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ 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
|
||||||
}
|
}
|
||||||
err := json.Unmarshal(data, &extarg)
|
err := json.Unmarshal(data, &extarg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -44,6 +45,7 @@ func (a *Argument) UnmarshalJSON(data []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.Name = extarg.Name
|
a.Name = extarg.Name
|
||||||
|
a.Indexed = extarg.Indexed
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,11 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
// Execute the call.
|
// Execute the call.
|
||||||
msg := callmsg{call}
|
msg := callmsg{call}
|
||||||
vmenv := core.NewEnv(statedb, chainConfig, b.blockchain, msg, block.Header(), vm.Config{})
|
|
||||||
|
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
|
||||||
|
// Create a new environment which holds all relevant information
|
||||||
|
// about the transaction and calling mechanisms.
|
||||||
|
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 (
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event is an event potentially triggered by the EVM's LOG mechanism. The Event
|
// Event is an event potentially triggered by the EVM's LOG mechanism. The Event
|
||||||
// holds type information (inputs) about the yielded output
|
// holds type information (inputs) about the yielded output. Anonymous events
|
||||||
|
// don't get the signature canonical representation as the first LOG topic.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Name string
|
Name string
|
||||||
Inputs []Argument
|
Anonymous bool
|
||||||
|
Inputs []Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id returns the canonical representation of the event's signature used by the
|
// Id returns the canonical representation of the event's signature used by the
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ const (
|
||||||
FixedBytesTy
|
FixedBytesTy
|
||||||
BytesTy
|
BytesTy
|
||||||
HashTy
|
HashTy
|
||||||
RealTy
|
FixedpointTy
|
||||||
|
FunctionTy
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type is the reflection of the supported argument type
|
// Type is the reflection of the supported argument type
|
||||||
|
|
@ -57,16 +58,16 @@ var (
|
||||||
// Types can be in the format of:
|
// Types can be in the format of:
|
||||||
//
|
//
|
||||||
// Input = Type [ "[" [ Number ] "]" ] Name .
|
// Input = Type [ "[" [ Number ] "]" ] Name .
|
||||||
// Type = [ "u" ] "int" [ Number ] .
|
// Type = [ "u" ] "int" [ Number ] [ x ] [ Number ].
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
// string int uint real
|
// string int uint fixed
|
||||||
// string32 int8 uint8 uint[]
|
// string32 int8 uint8 uint[]
|
||||||
// address int256 uint256 real[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]*)?")
|
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewType creates a new reflection type of abi type given in t.
|
// NewType creates a new reflection type of abi type given in t.
|
||||||
|
|
@ -90,14 +91,19 @@ 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.
|
||||||
parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
|
parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
|
||||||
// varSize is the size of the variable
|
// varSize is the size of the variable
|
||||||
var varSize int
|
var varSize int
|
||||||
if len(parsedType[2]) > 0 {
|
if len(parsedType[3]) > 0 {
|
||||||
var err error
|
var err error
|
||||||
varSize, err = strconv.Atoi(parsedType[2])
|
varSize, err = strconv.Atoi(parsedType[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -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++ {
|
||||||
|
|
|
||||||
78
accounts/abi/type_test.go
Normal file
78
accounts/abi/type_test.go
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
// 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 abi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// typeWithoutStringer is a alias for the Type type which simply doesn't implement
|
||||||
|
// the stringer interface to allow printing type details in the tests below.
|
||||||
|
type typeWithoutStringer Type
|
||||||
|
|
||||||
|
// Tests that all allowed types get recognized by the type parser.
|
||||||
|
func TestTypeRegexp(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
blob string
|
||||||
|
kind Type
|
||||||
|
}{
|
||||||
|
{"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"}},
|
||||||
|
{"int256", Type{Kind: reflect.Ptr, Type: big_t, Size: 256, T: IntTy, 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, 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, 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, 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"}},
|
||||||
|
{"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"}},
|
||||||
|
{"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, 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, 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, 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"}},
|
||||||
|
{"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[2]", Type{IsArray: true, SliceSize: 2, 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[2]"}},
|
||||||
|
{"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]"}},
|
||||||
|
{"string", Type{Kind: reflect.String, Size: -1, T: StringTy, 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, 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{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,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
|
||||||
|
// {"fixed", Type{}},
|
||||||
|
// {"fixed128x128", Type{}},
|
||||||
|
// {"fixed[]", Type{}},
|
||||||
|
// {"fixed[2]", Type{}},
|
||||||
|
// {"fixed128x128[]", Type{}},
|
||||||
|
// {"fixed128x128[2]", Type{}},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
typ, err := NewType(tt.blob)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("type %d: failed to parse type string: %v", i, err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(typ, tt.kind) {
|
||||||
|
t.Errorf("type %d: parsed type mismatch:\n have %+v\n want %+v", i, typeWithoutStringer(typ), typeWithoutStringer(tt.kind))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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/ubiq/go-ubiq/crypto"
|
"github.com/ubiq/go-ubiq/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:]
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ environment:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- rmdir C:\go /s /q
|
- rmdir C:\go /s /q
|
||||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.3.windows-%GETH_ARCH%.zip
|
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.4.windows-%GETH_ARCH%.zip
|
||||||
- 7z x go1.7.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
- 7z x go1.7.4.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||||
- go version
|
- go version
|
||||||
- gcc --version
|
- gcc --version
|
||||||
|
|
||||||
|
|
|
||||||
67
build/ci.go
67
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
|
||||||
|
|
@ -72,9 +72,7 @@ var (
|
||||||
executablePath("abigen"),
|
executablePath("abigen"),
|
||||||
executablePath("evm"),
|
executablePath("evm"),
|
||||||
executablePath("gubiq"),
|
executablePath("gubiq"),
|
||||||
executablePath("bzzd"),
|
executablePath("swarm"),
|
||||||
executablePath("bzzhash"),
|
|
||||||
executablePath("bzzup"),
|
|
||||||
executablePath("rlpdump"),
|
executablePath("rlpdump"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,16 +91,8 @@ var (
|
||||||
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
|
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "bzzd",
|
Name: "swarm",
|
||||||
Description: "Ethereum Swarm daemon",
|
Description: "Ethereum Swarm daemon and tools",
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "bzzup",
|
|
||||||
Description: "Ethereum Swarm command line file/directory uploader",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "bzzhash",
|
|
||||||
Description: "Ethereum Swarm file/directory hash calculator",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "abigen",
|
Name: "abigen",
|
||||||
|
|
@ -112,7 +102,8 @@ var (
|
||||||
|
|
||||||
// Distros for which packages are created.
|
// Distros for which packages are created.
|
||||||
// Note: vivid is unsupported because there is no golang-1.6 package for it.
|
// Note: vivid is unsupported because there is no golang-1.6 package for it.
|
||||||
debDistros = []string{"trusty", "wily", "xenial", "yakkety"}
|
// Note: wily is unsupported because it was officially deprecated on lanchpad.
|
||||||
|
debDistros = []string{"trusty", "xenial", "yakkety"}
|
||||||
)
|
)
|
||||||
|
|
||||||
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
|
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
|
||||||
|
|
@ -204,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")
|
||||||
|
|
@ -271,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)
|
||||||
|
|
@ -296,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
|
||||||
|
|
@ -309,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) {
|
||||||
|
|
@ -332,7 +354,7 @@ func doArchive(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
env = build.Env()
|
env = build.Env()
|
||||||
base = archiveBasename(*arch, env)
|
base = archiveBasename(*arch, env)
|
||||||
gubiq = "gubiq-" + base + ext
|
gubiq = "gubiq-" + base + ext
|
||||||
alltools = "gubiq-alltools-" + base + ext
|
alltools = "gubiq-alltools-" + base + ext
|
||||||
)
|
)
|
||||||
maybeSkipArchive(env)
|
maybeSkipArchive(env)
|
||||||
|
|
@ -612,8 +634,8 @@ func doWindowsInstaller(cmdline []string) {
|
||||||
|
|
||||||
// Aggregate binaries that are included in the installer
|
// Aggregate binaries that are included in the installer
|
||||||
var (
|
var (
|
||||||
devTools []string
|
devTools []string
|
||||||
allTools []string
|
allTools []string
|
||||||
gubiqTool string
|
gubiqTool string
|
||||||
)
|
)
|
||||||
for _, file := range allToolsArchiveFiles {
|
for _, file := range allToolsArchiveFiles {
|
||||||
|
|
@ -632,12 +654,13 @@ func doWindowsInstaller(cmdline []string) {
|
||||||
// first section contains the gubiq binary, second section holds the dev tools.
|
// first section contains the gubiq binary, second section holds the dev tools.
|
||||||
templateData := map[string]interface{}{
|
templateData := map[string]interface{}{
|
||||||
"License": "COPYING",
|
"License": "COPYING",
|
||||||
"Gubiq": gubiqTool,
|
"Gubiq": gubiqTool,
|
||||||
"DevTools": devTools,
|
"DevTools": devTools,
|
||||||
}
|
}
|
||||||
build.Render("build/nsis.gubiq.nsi", filepath.Join(*workdir, "gubiq.nsi"), 0644, nil)
|
build.Render("build/nsis.gubiq.nsi", filepath.Join(*workdir, "gubiq.nsi"), 0644, nil)
|
||||||
build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData)
|
build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData)
|
||||||
build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools)
|
build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools)
|
||||||
|
build.Render("build/nsis.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.nsh"), 0644, nil)
|
||||||
build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil)
|
build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil)
|
||||||
build.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll", 0755)
|
build.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll", 0755)
|
||||||
build.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING", 0755)
|
build.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING", 0755)
|
||||||
|
|
@ -800,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", "GE", "-v", "github.com/ubiq/go-ubiq/mobile")
|
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ubiq/go-ubiq/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
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,12 @@
|
||||||
#
|
#
|
||||||
# Requirements:
|
# Requirements:
|
||||||
# - NSIS, http://nsis.sourceforge.net/Main_Page
|
# - NSIS, http://nsis.sourceforge.net/Main_Page
|
||||||
|
# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds
|
||||||
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
|
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
|
||||||
#
|
#
|
||||||
|
# After intalling NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the
|
||||||
|
# files found in Stub.
|
||||||
|
#
|
||||||
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller
|
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller
|
||||||
#
|
#
|
||||||
# TODO:
|
# TODO:
|
||||||
|
|
@ -37,6 +41,7 @@ RequestExecutionLevel admin
|
||||||
SetCompressor /SOLID lzma
|
SetCompressor /SOLID lzma
|
||||||
|
|
||||||
!include LogicLib.nsh
|
!include LogicLib.nsh
|
||||||
|
!include PathUpdate.nsh
|
||||||
!include EnvVarUpdate.nsh
|
!include EnvVarUpdate.nsh
|
||||||
|
|
||||||
!macro VerifyUserIsAdmin
|
!macro VerifyUserIsAdmin
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,9 @@ Section "Gubiq" GETH_IDX
|
||||||
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc"
|
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc"
|
||||||
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\gubiq.ipc"
|
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\gubiq.ipc"
|
||||||
|
|
||||||
# Add gubiq to PATH
|
# Add instdir to PATH
|
||||||
${EnvVarUpdate} $0 "PATH" "A" "HKLM" $INSTDIR
|
Push "$INSTDIR"
|
||||||
|
Call AddToPath
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
# Install optional develop tools.
|
# Install optional develop tools.
|
||||||
|
|
|
||||||
153
build/nsis.pathupdate.nsh
Normal file
153
build/nsis.pathupdate.nsh
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
!include "WinMessages.nsh"
|
||||||
|
|
||||||
|
; see https://support.microsoft.com/en-us/kb/104011
|
||||||
|
!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||||
|
; HKEY_LOCAL_MACHINE = 0x80000002
|
||||||
|
|
||||||
|
; AddToPath - Appends dir to PATH
|
||||||
|
; (does not work on Win9x/ME)
|
||||||
|
;
|
||||||
|
; Usage:
|
||||||
|
; Push "dir"
|
||||||
|
; Call AddToPath
|
||||||
|
Function AddToPath
|
||||||
|
Exch $0
|
||||||
|
Push $1
|
||||||
|
Push $2
|
||||||
|
Push $3
|
||||||
|
Push $4
|
||||||
|
|
||||||
|
; NSIS ReadRegStr returns empty string on string overflow
|
||||||
|
; Native calls are used here to check actual length of PATH
|
||||||
|
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3)
|
||||||
|
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
|
||||||
|
IntCmp $4 0 0 done done
|
||||||
|
|
||||||
|
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2))
|
||||||
|
; RegCloseKey($3)
|
||||||
|
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
|
||||||
|
System::Call "advapi32::RegCloseKey(i $3)"
|
||||||
|
|
||||||
|
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
|
||||||
|
DetailPrint "AddToPath: original length $2 > ${NSIS_MAX_STRLEN}"
|
||||||
|
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}"
|
||||||
|
Goto done
|
||||||
|
|
||||||
|
IntCmp $4 0 +5 ; $4 != NO_ERROR
|
||||||
|
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
|
||||||
|
DetailPrint "AddToPath: unexpected error code $4"
|
||||||
|
Goto done
|
||||||
|
StrCpy $1 ""
|
||||||
|
|
||||||
|
; Check if already in PATH
|
||||||
|
Push "$1;"
|
||||||
|
Push "$0;"
|
||||||
|
Call StrStr
|
||||||
|
Pop $2
|
||||||
|
StrCmp $2 "" 0 done
|
||||||
|
Push "$1;"
|
||||||
|
Push "$0\;"
|
||||||
|
Call StrStr
|
||||||
|
Pop $2
|
||||||
|
StrCmp $2 "" 0 done
|
||||||
|
|
||||||
|
; Prevent NSIS string overflow
|
||||||
|
StrLen $2 $0
|
||||||
|
StrLen $3 $1
|
||||||
|
IntOp $2 $2 + $3
|
||||||
|
IntOp $2 $2 + 2 ; $2 = strlen(dir) + strlen(PATH) + sizeof(";")
|
||||||
|
IntCmp $2 ${NSIS_MAX_STRLEN} +4 +4 0
|
||||||
|
DetailPrint "AddToPath: new length $2 > ${NSIS_MAX_STRLEN}"
|
||||||
|
MessageBox MB_OK "PATH not updated, new length $2 > ${NSIS_MAX_STRLEN}."
|
||||||
|
Goto done
|
||||||
|
|
||||||
|
; Append dir to PATH
|
||||||
|
DetailPrint "Add to PATH: $0"
|
||||||
|
StrCpy $2 $1 1 -1
|
||||||
|
StrCmp $2 ";" 0 +2
|
||||||
|
StrCpy $1 $1 -1 ; remove trailing ';'
|
||||||
|
StrCmp $1 "" +2 ; no leading ';'
|
||||||
|
StrCpy $0 "$1;$0"
|
||||||
|
|
||||||
|
WriteRegExpandStr ${Environ} "PATH" $0
|
||||||
|
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||||
|
|
||||||
|
done:
|
||||||
|
Pop $4
|
||||||
|
Pop $3
|
||||||
|
Pop $2
|
||||||
|
Pop $1
|
||||||
|
Pop $0
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
|
||||||
|
; RemoveFromPath - Removes dir from PATH
|
||||||
|
;
|
||||||
|
; Usage:
|
||||||
|
; Push "dir"
|
||||||
|
; Call RemoveFromPath
|
||||||
|
Function un.RemoveFromPath
|
||||||
|
Exch $0
|
||||||
|
Push $1
|
||||||
|
Push $2
|
||||||
|
Push $3
|
||||||
|
Push $4
|
||||||
|
Push $5
|
||||||
|
Push $6
|
||||||
|
|
||||||
|
; NSIS ReadRegStr returns empty string on string overflow
|
||||||
|
; Native calls are used here to check actual length of PATH
|
||||||
|
; $4 = RegOpenKey(HKEY_LOCAL_MACHINE, "SYSTEM\CurrentControlSet\Control\Session Manager\Environment", &$3)
|
||||||
|
System::Call "advapi32::RegOpenKey(i 0x80000002, t'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', *i.r3) i.r4"
|
||||||
|
IntCmp $4 0 0 done done
|
||||||
|
|
||||||
|
; $4 = RegQueryValueEx($3, "PATH", (DWORD*)0, (DWORD*)0, &$1, ($2=NSIS_MAX_STRLEN, &$2))
|
||||||
|
; RegCloseKey($3)
|
||||||
|
System::Call "advapi32::RegQueryValueEx(i $3, t'PATH', i 0, i 0, t.r1, *i ${NSIS_MAX_STRLEN} r2) i.r4"
|
||||||
|
System::Call "advapi32::RegCloseKey(i $3)"
|
||||||
|
|
||||||
|
IntCmp $4 234 0 +4 +4 ; $4 == ERROR_MORE_DATA
|
||||||
|
DetailPrint "RemoveFromPath: original length $2 > ${NSIS_MAX_STRLEN}"
|
||||||
|
MessageBox MB_OK "PATH not updated, original length $2 > ${NSIS_MAX_STRLEN}"
|
||||||
|
Goto done
|
||||||
|
|
||||||
|
IntCmp $4 0 +5 ; $4 != NO_ERROR
|
||||||
|
IntCmp $4 2 +3 ; $4 != ERROR_FILE_NOT_FOUND
|
||||||
|
DetailPrint "RemoveFromPath: unexpected error code $4"
|
||||||
|
Goto done
|
||||||
|
StrCpy $1 ""
|
||||||
|
|
||||||
|
; length < ${NSIS_MAX_STRLEN} -> ReadRegStr can be used
|
||||||
|
ReadRegStr $1 ${Environ} "PATH"
|
||||||
|
StrCpy $5 $1 1 -1
|
||||||
|
StrCmp $5 ";" +2
|
||||||
|
StrCpy $1 "$1;" ; ensure trailing ';'
|
||||||
|
Push $1
|
||||||
|
Push "$0;"
|
||||||
|
Call un.StrStr
|
||||||
|
Pop $2 ; pos of our dir
|
||||||
|
StrCmp $2 "" done
|
||||||
|
|
||||||
|
DetailPrint "Remove from PATH: $0"
|
||||||
|
StrLen $3 "$0;"
|
||||||
|
StrLen $4 $2
|
||||||
|
StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove
|
||||||
|
StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove
|
||||||
|
StrCpy $3 "$5$6"
|
||||||
|
StrCpy $5 $3 1 -1
|
||||||
|
StrCmp $5 ";" 0 +2
|
||||||
|
StrCpy $3 $3 -1 ; remove trailing ';'
|
||||||
|
WriteRegExpandStr ${Environ} "PATH" $3
|
||||||
|
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||||
|
|
||||||
|
done:
|
||||||
|
Pop $6
|
||||||
|
Pop $5
|
||||||
|
Pop $4
|
||||||
|
Pop $3
|
||||||
|
Pop $2
|
||||||
|
Pop $1
|
||||||
|
Pop $0
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -25,7 +25,8 @@ Section "Uninstall"
|
||||||
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc"
|
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc"
|
||||||
|
|
||||||
# Remove install directory from PATH
|
# Remove install directory from PATH
|
||||||
${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" $INSTDIR
|
Push "$INSTDIR"
|
||||||
|
Call un.RemoveFromPath
|
||||||
|
|
||||||
# Cleanup registry (deletes all sub keys)
|
# Cleanup registry (deletes all sub keys)
|
||||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}"
|
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
// Copyright 2016 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Command bzzup uploads files to the swarm HTTP API.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var (
|
|
||||||
bzzapiFlag = flag.String("bzzapi", "http://127.0.0.1:8500", "Swarm HTTP endpoint")
|
|
||||||
recursiveFlag = flag.Bool("recursive", false, "Upload directories recursively")
|
|
||||||
manifestFlag = flag.Bool("manifest", true, "Skip automatic manifest upload")
|
|
||||||
)
|
|
||||||
log.SetOutput(os.Stderr)
|
|
||||||
log.SetFlags(0)
|
|
||||||
flag.Parse()
|
|
||||||
if flag.NArg() != 1 {
|
|
||||||
log.Fatal("need filename as the first and only argument")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file = flag.Arg(0)
|
|
||||||
client = &client{api: *bzzapiFlag}
|
|
||||||
mroot manifest
|
|
||||||
)
|
|
||||||
fi, err := os.Stat(file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if fi.IsDir() {
|
|
||||||
if !*recursiveFlag {
|
|
||||||
log.Fatal("argument is a directory and recursive upload is disabled")
|
|
||||||
}
|
|
||||||
mroot, err = client.uploadDirectory(file)
|
|
||||||
} else {
|
|
||||||
mroot, err = client.uploadFile(file, fi)
|
|
||||||
if *manifestFlag {
|
|
||||||
// Wrap the raw file entry in a proper manifest so both hashes get printed.
|
|
||||||
mroot = manifest{Entries: []manifest{mroot}}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("upload failed:", err)
|
|
||||||
}
|
|
||||||
if *manifestFlag {
|
|
||||||
hash, err := client.uploadManifest(mroot)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("manifest upload failed:", err)
|
|
||||||
}
|
|
||||||
mroot.Hash = hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the manifest. This is the only output to stdout.
|
|
||||||
mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
|
|
||||||
fmt.Println(string(mrootJSON))
|
|
||||||
}
|
|
||||||
|
|
||||||
// client wraps interaction with the swarm HTTP gateway.
|
|
||||||
type client struct {
|
|
||||||
api string
|
|
||||||
}
|
|
||||||
|
|
||||||
// manifest is the JSON representation of a swarm manifest.
|
|
||||||
type manifest struct {
|
|
||||||
Hash string `json:"hash,omitempty"`
|
|
||||||
ContentType string `json:"contentType,omitempty"`
|
|
||||||
Path string `json:"path,omitempty"`
|
|
||||||
Entries []manifest `json:"entries,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) uploadFile(file string, fi os.FileInfo) (manifest, error) {
|
|
||||||
hash, err := c.uploadFileContent(file, fi)
|
|
||||||
m := manifest{
|
|
||||||
Hash: hash,
|
|
||||||
ContentType: mime.TypeByExtension(filepath.Ext(fi.Name())),
|
|
||||||
}
|
|
||||||
return m, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) uploadDirectory(dir string) (manifest, error) {
|
|
||||||
dirm := manifest{}
|
|
||||||
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) {
|
|
||||||
fd, err := os.Open(file)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer fd.Close()
|
|
||||||
log.Printf("uploading file %s (%d bytes)", file, fi.Size())
|
|
||||||
return c.postRaw("application/octet-stream", fi.Size(), fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) uploadManifest(m manifest) (string, error) {
|
|
||||||
jsm, err := json.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
log.Println("uploading manifest")
|
|
||||||
return c.postRaw("application/json", int64(len(jsm)), ioutil.NopCloser(bytes.NewReader(jsm)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) postRaw(mimetype string, size int64, body io.ReadCloser) (string, error) {
|
|
||||||
req, err := http.NewRequest("POST", c.api+"/bzzr:/", body)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
req.Header.Set("content-type", mimetype)
|
|
||||||
req.ContentLength = 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
|
|
||||||
}
|
|
||||||
|
|
@ -18,11 +18,12 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/common"
|
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
"github.com/ubiq/go-ubiq/core/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -32,20 +33,28 @@ func main() {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
code = common.Hex2Bytes(string(code[:len(code)-1]))
|
code, err = hex.DecodeString(strings.TrimSpace(string(code[:])))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
fmt.Printf("%x\n", code)
|
fmt.Printf("%x\n", code)
|
||||||
|
|
||||||
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) {
|
||||||
|
|
|
||||||
156
cmd/evm/main.go
156
cmd/evm/main.go
|
|
@ -20,21 +20,18 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
goruntime "runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/cmd/utils"
|
"github.com/ubiq/go-ubiq/cmd/utils"
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core"
|
|
||||||
"github.com/ubiq/go-ubiq/core/state"
|
"github.com/ubiq/go-ubiq/core/state"
|
||||||
"github.com/ubiq/go-ubiq/core/types"
|
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
"github.com/ubiq/go-ubiq/core/vm"
|
||||||
|
"github.com/ubiq/go-ubiq/core/vm/runtime"
|
||||||
"github.com/ubiq/go-ubiq/crypto"
|
"github.com/ubiq/go-ubiq/crypto"
|
||||||
"github.com/ubiq/go-ubiq/ethdb"
|
"github.com/ubiq/go-ubiq/ethdb"
|
||||||
"github.com/ubiq/go-ubiq/logger/glog"
|
"github.com/ubiq/go-ubiq/logger/glog"
|
||||||
"github.com/ubiq/go-ubiq/params"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -47,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",
|
||||||
|
|
@ -98,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() {
|
||||||
|
|
@ -105,8 +98,6 @@ func init() {
|
||||||
CreateFlag,
|
CreateFlag,
|
||||||
DebugFlag,
|
DebugFlag,
|
||||||
VerbosityFlag,
|
VerbosityFlag,
|
||||||
ForceJitFlag,
|
|
||||||
DisableJitFlag,
|
|
||||||
SysStatFlag,
|
SysStatFlag,
|
||||||
CodeFlag,
|
CodeFlag,
|
||||||
CodeFileFlag,
|
CodeFileFlag,
|
||||||
|
|
@ -115,6 +106,7 @@ func init() {
|
||||||
ValueFlag,
|
ValueFlag,
|
||||||
DumpFlag,
|
DumpFlag,
|
||||||
InputFlag,
|
InputFlag,
|
||||||
|
DisableGasMeteringFlag,
|
||||||
}
|
}
|
||||||
app.Action = run
|
app.Action = run
|
||||||
}
|
}
|
||||||
|
|
@ -129,13 +121,6 @@ func run(ctx *cli.Context) error {
|
||||||
|
|
||||||
logger := vm.NewStructLogger(nil)
|
logger := vm.NewStructLogger(nil)
|
||||||
|
|
||||||
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name)), vm.Config{
|
|
||||||
Debug: ctx.GlobalBool(DebugFlag.Name),
|
|
||||||
ForceJit: ctx.GlobalBool(ForceJitFlag.Name),
|
|
||||||
EnableJit: !ctx.GlobalBool(DisableJitFlag.Name),
|
|
||||||
Tracer: logger,
|
|
||||||
})
|
|
||||||
|
|
||||||
tstart := time.Now()
|
tstart := time.Now()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -168,25 +153,32 @@ func run(ctx *cli.Context) error {
|
||||||
|
|
||||||
if ctx.GlobalBool(CreateFlag.Name) {
|
if ctx.GlobalBool(CreateFlag.Name) {
|
||||||
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
|
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
|
||||||
ret, _, err = vmenv.Create(
|
ret, _, err = runtime.Create(input, &runtime.Config{
|
||||||
sender,
|
Origin: sender.Address(),
|
||||||
input,
|
State: statedb,
|
||||||
common.Big(ctx.GlobalString(GasFlag.Name)),
|
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
|
||||||
common.Big(ctx.GlobalString(PriceFlag.Name)),
|
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||||
common.Big(ctx.GlobalString(ValueFlag.Name)),
|
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||||
)
|
EVMConfig: vm.Config{
|
||||||
|
Tracer: logger,
|
||||||
|
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||||
|
},
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
|
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
|
||||||
|
|
||||||
receiver.SetCode(crypto.Keccak256Hash(code), code)
|
receiver.SetCode(crypto.Keccak256Hash(code), code)
|
||||||
ret, err = vmenv.Call(
|
|
||||||
sender,
|
ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
|
||||||
receiver.Address(),
|
Origin: sender.Address(),
|
||||||
common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)),
|
State: statedb,
|
||||||
common.Big(ctx.GlobalString(GasFlag.Name)),
|
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
|
||||||
common.Big(ctx.GlobalString(PriceFlag.Name)),
|
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||||
common.Big(ctx.GlobalString(ValueFlag.Name)),
|
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||||
)
|
EVMConfig: vm.Config{
|
||||||
|
Tracer: logger,
|
||||||
|
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
vmdone := time.Since(tstart)
|
vmdone := time.Since(tstart)
|
||||||
|
|
||||||
|
|
@ -197,8 +189,8 @@ func run(ctx *cli.Context) error {
|
||||||
vm.StdErrFormat(logger.StructLogs())
|
vm.StdErrFormat(logger.StructLogs())
|
||||||
|
|
||||||
if ctx.GlobalBool(SysStatFlag.Name) {
|
if ctx.GlobalBool(SysStatFlag.Name) {
|
||||||
var mem runtime.MemStats
|
var mem goruntime.MemStats
|
||||||
runtime.ReadMemStats(&mem)
|
goruntime.ReadMemStats(&mem)
|
||||||
fmt.Printf("vm took %v\n", vmdone)
|
fmt.Printf("vm took %v\n", vmdone)
|
||||||
fmt.Printf(`alloc: %d
|
fmt.Printf(`alloc: %d
|
||||||
tot alloc: %d
|
tot alloc: %d
|
||||||
|
|
@ -223,87 +215,3 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type VMEnv struct {
|
|
||||||
state *state.StateDB
|
|
||||||
block *types.Block
|
|
||||||
|
|
||||||
transactor *common.Address
|
|
||||||
value *big.Int
|
|
||||||
|
|
||||||
depth int
|
|
||||||
Gas *big.Int
|
|
||||||
time *big.Int
|
|
||||||
logs []vm.StructLog
|
|
||||||
|
|
||||||
evm *vm.EVM
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int, cfg vm.Config) *VMEnv {
|
|
||||||
env := &VMEnv{
|
|
||||||
state: state,
|
|
||||||
transactor: &transactor,
|
|
||||||
value: value,
|
|
||||||
time: big.NewInt(time.Now().Unix()),
|
|
||||||
}
|
|
||||||
|
|
||||||
env.evm = vm.New(env, cfg)
|
|
||||||
return env
|
|
||||||
}
|
|
||||||
|
|
||||||
// ruleSet implements vm.ChainConfig and will always default to the homestead rule set.
|
|
||||||
type ruleSet struct{}
|
|
||||||
|
|
||||||
func (ruleSet) IsHomestead(*big.Int) bool { return true }
|
|
||||||
func (ruleSet) GasTable(*big.Int) params.GasTable {
|
|
||||||
return params.GasTableHomesteadGasRepriceFork
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *VMEnv) ChainConfig() *params.ChainConfig { return params.TestChainConfig }
|
|
||||||
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
|
||||||
func (self *VMEnv) Db() vm.Database { return self.state }
|
|
||||||
func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() }
|
|
||||||
func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) }
|
|
||||||
func (self *VMEnv) Origin() common.Address { return *self.transactor }
|
|
||||||
func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 }
|
|
||||||
func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
|
|
||||||
func (self *VMEnv) Time() *big.Int { return self.time }
|
|
||||||
func (self *VMEnv) Difficulty() *big.Int { return common.Big1 }
|
|
||||||
func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) }
|
|
||||||
func (self *VMEnv) Value() *big.Int { return self.value }
|
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
|
|
||||||
func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy }
|
|
||||||
func (self *VMEnv) Depth() int { return 0 }
|
|
||||||
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
|
||||||
func (self *VMEnv) GetHash(n uint64) common.Hash {
|
|
||||||
if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
|
|
||||||
return self.block.Hash()
|
|
||||||
}
|
|
||||||
return common.Hash{}
|
|
||||||
}
|
|
||||||
func (self *VMEnv) AddLog(log *vm.Log) {
|
|
||||||
self.state.AddLog(log)
|
|
||||||
}
|
|
||||||
func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool {
|
|
||||||
return self.state.GetBalance(from).Cmp(balance) >= 0
|
|
||||||
}
|
|
||||||
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) {
|
|
||||||
core.Transfer(from, to, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *VMEnv) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
|
||||||
self.Gas = gas
|
|
||||||
return core.Call(self, caller, addr, data, gas, price, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *VMEnv) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
|
||||||
return core.CallCode(self, caller, addr, data, gas, price, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *VMEnv) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
|
|
||||||
return core.DelegateCall(self, caller, addr, data, gas, price)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
|
|
||||||
return core.Create(self, caller, data, gas, price, value)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ Passphrase: {{.InputLine "foobar"}}
|
||||||
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
||||||
}
|
}
|
||||||
for _, m := range wantMessages {
|
for _, m := range wantMessages {
|
||||||
if strings.Index(gubiq.stderrText(), m) == -1 {
|
if !strings.Contains(gubiq.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(gubiq.stderrText(), m) == -1 {
|
if !strings.Contains(gubiq.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(gubiq.stderrText(), m) == -1 {
|
if !strings.Contains(gubiq.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(gubiq.stderrText(), m) == -1 {
|
if !strings.Contains(gubiq.stderrText(), m) {
|
||||||
t.Errorf("stderr text does not contain %q", m)
|
t.Errorf("stderr text does not contain %q", m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Simple wrapper to translate the API exposed methods and types to inthernal
|
|
||||||
// Go versions of the same types.
|
|
||||||
|
|
||||||
#include "_cgo_export.h"
|
|
||||||
|
|
||||||
int run(const char* args) {
|
|
||||||
return doRun((char*)args);
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Contains a simple library definition to allow creating a Gubiq instance from
|
|
||||||
// straight C code.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
// #ifdef __cplusplus
|
|
||||||
// extern "C" {
|
|
||||||
// #endif
|
|
||||||
//
|
|
||||||
// extern int run(const char*);
|
|
||||||
//
|
|
||||||
// #ifdef __cplusplus
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
//export doRun
|
|
||||||
func doRun(args *C.char) C.int {
|
|
||||||
// This is equivalent to gubiq.main, just modified to handle the function arg passing
|
|
||||||
if err := app.Run(strings.Split("gubiq "+C.GoString(args), " ")); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Contains specialized code for running Gubiq on Android.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
// #include <android/log.h>
|
|
||||||
// #cgo LDFLAGS: -llog
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Redirect the standard output and error to logcat
|
|
||||||
oldStdout, oldStderr := os.Stdout, os.Stderr
|
|
||||||
|
|
||||||
outRead, outWrite, _ := os.Pipe()
|
|
||||||
errRead, errWrite, _ := os.Pipe()
|
|
||||||
|
|
||||||
os.Stdout = outWrite
|
|
||||||
os.Stderr = errWrite
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
scanner := bufio.NewScanner(outRead)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stdout"), C.CString(line))
|
|
||||||
oldStdout.WriteString(line + "\n")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
scanner := bufio.NewScanner(errRead)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stderr"), C.CString(line))
|
|
||||||
oldStderr.WriteString(line + "\n")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -19,22 +19,21 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/swarm/storage"
|
"github.com/ubiq/go-ubiq/swarm/storage"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func hash(ctx *cli.Context) {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
args := ctx.Args()
|
||||||
|
if len(args) < 1 {
|
||||||
if len(os.Args) < 2 {
|
log.Fatal("Usage: swarm hash <file name>")
|
||||||
fmt.Println("Usage: bzzhash <file name>")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
f, err := os.Open(os.Args[1])
|
f, err := os.Open(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error opening file " + os.Args[1])
|
fmt.Println("Error opening file " + args[1])
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +41,7 @@ func main() {
|
||||||
chunker := storage.NewTreeChunker(storage.NewChunkerParams())
|
chunker := storage.NewTreeChunker(storage.NewChunkerParams())
|
||||||
key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
|
key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
log.Fatalf("%v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%v\n", key)
|
fmt.Printf("%v\n", key)
|
||||||
}
|
}
|
||||||
|
|
@ -43,11 +43,15 @@ import (
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const clientIdentifier = "bzzd"
|
const (
|
||||||
|
clientIdentifier = "swarm"
|
||||||
|
versionString = "0.2"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
|
gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
|
||||||
app = utils.NewApp(gitCommit, "Ubiq Swarm server daemon")
|
app = utils.NewApp(gitCommit, "Ubiq Swarm")
|
||||||
|
testbetBootNodes = []string{}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -65,30 +69,49 @@ var (
|
||||||
}
|
}
|
||||||
SwarmNetworkIdFlag = cli.IntFlag{
|
SwarmNetworkIdFlag = cli.IntFlag{
|
||||||
Name: "bzznetworkid",
|
Name: "bzznetworkid",
|
||||||
Usage: "Network identifier (integer, default 322=swarm testnet)",
|
Usage: "Network identifier (integer, default 3=swarm testnet)",
|
||||||
Value: network.NetworkId,
|
Value: network.NetworkId,
|
||||||
}
|
}
|
||||||
SwarmConfigPathFlag = cli.StringFlag{
|
SwarmConfigPathFlag = cli.StringFlag{
|
||||||
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("gubiq"),
|
Value: node.DefaultIPCEndpoint("gubiq"),
|
||||||
}
|
}
|
||||||
|
SwarmApiFlag = cli.StringFlag{
|
||||||
|
Name: "bzzapi",
|
||||||
|
Usage: "Swarm HTTP endpoint",
|
||||||
|
Value: "http://127.0.0.1:8500",
|
||||||
|
}
|
||||||
|
SwarmRecursiveUploadFlag = cli.BoolFlag{
|
||||||
|
Name: "recursive",
|
||||||
|
Usage: "Upload directories recursively",
|
||||||
|
}
|
||||||
|
SwarmWantManifestFlag = cli.BoolTFlag{
|
||||||
|
Name: "manifest",
|
||||||
|
Usage: "Automatic manifest upload",
|
||||||
|
}
|
||||||
|
SwarmUploadDefaultPath = cli.StringFlag{
|
||||||
|
Name: "defaultpath",
|
||||||
|
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 ',')",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultBootnodes = []string{}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Override flag defaults so bzzd can run alongside gubiq.
|
// Override flag defaults so bzzd can run alongside gubiq.
|
||||||
utils.ListenPortFlag.Value = 30399
|
utils.ListenPortFlag.Value = 30399
|
||||||
|
|
@ -96,8 +119,39 @@ func init() {
|
||||||
utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3"
|
utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3"
|
||||||
|
|
||||||
// Set up the cli app.
|
// Set up the cli app.
|
||||||
app.Commands = nil
|
|
||||||
app.Action = bzzd
|
app.Action = bzzd
|
||||||
|
app.HideVersion = true // we have a command to print the version
|
||||||
|
app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Action: version,
|
||||||
|
Name: "version",
|
||||||
|
Usage: "Print version numbers",
|
||||||
|
ArgsUsage: " ",
|
||||||
|
Description: `
|
||||||
|
The output of this command is supposed to be machine-readable.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: upload,
|
||||||
|
Name: "up",
|
||||||
|
Usage: "upload a file or directory to swarm using the HTTP API",
|
||||||
|
ArgsUsage: " <file>",
|
||||||
|
Description: `
|
||||||
|
"upload a file or directory to swarm using the HTTP API and prints the root hash",
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Action: hash,
|
||||||
|
Name: "hash",
|
||||||
|
Usage: "print the swarm hash of a file or directory",
|
||||||
|
ArgsUsage: " <file>",
|
||||||
|
Description: `
|
||||||
|
Prints the swarm hash of file or directory.
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
utils.IdentityFlag,
|
utils.IdentityFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
|
|
@ -115,14 +169,20 @@ func init() {
|
||||||
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,
|
||||||
ChequebookAddrFlag,
|
ChequebookAddrFlag,
|
||||||
|
// upload flags
|
||||||
|
SwarmApiFlag,
|
||||||
|
SwarmRecursiveUploadFlag,
|
||||||
|
SwarmWantManifestFlag,
|
||||||
|
SwarmUploadDefaultPath,
|
||||||
}
|
}
|
||||||
app.Flags = append(app.Flags, debug.Flags...)
|
app.Flags = append(app.Flags, debug.Flags...)
|
||||||
app.Before = func(ctx *cli.Context) error {
|
app.Before = func(ctx *cli.Context) error {
|
||||||
|
|
@ -142,17 +202,33 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func version(ctx *cli.Context) error {
|
||||||
|
fmt.Println(strings.Title(clientIdentifier))
|
||||||
|
fmt.Println("Version:", versionString)
|
||||||
|
if gitCommit != "" {
|
||||||
|
fmt.Println("Git Commit:", gitCommit)
|
||||||
|
}
|
||||||
|
fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name))
|
||||||
|
fmt.Println("Go Version:", runtime.Version())
|
||||||
|
fmt.Println("OS:", runtime.GOOS)
|
||||||
|
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
||||||
|
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func bzzd(ctx *cli.Context) error {
|
func bzzd(ctx *cli.Context) error {
|
||||||
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
|
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
|
||||||
registerBzzService(ctx, stack)
|
registerBzzService(ctx, stack)
|
||||||
utils.StartNode(stack)
|
utils.StartNode(stack)
|
||||||
|
networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name)
|
||||||
// Add bootnodes as initial peers.
|
// Add bootnodes as initial peers.
|
||||||
if ctx.GlobalIsSet(utils.BootnodesFlag.Name) {
|
if ctx.GlobalIsSet(utils.BootnodesFlag.Name) {
|
||||||
bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",")
|
bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",")
|
||||||
injectBootnodes(stack.Server(), bootnodes)
|
injectBootnodes(stack.Server(), bootnodes)
|
||||||
} else {
|
} else {
|
||||||
injectBootnodes(stack.Server(), defaultBootnodes)
|
if networkId == 3 {
|
||||||
|
injectBootnodes(stack.Server(), testbetBootNodes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.Wait()
|
stack.Wait()
|
||||||
|
|
@ -175,22 +251,21 @@ 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
|
||||||
if ethapi == "" {
|
if len(ethapi) > 0 {
|
||||||
err = fmt.Errorf("use ethapi flag to connect to a an eth client and talk to the blockchain")
|
|
||||||
} else {
|
|
||||||
client, err = ethclient.Dial(ethapi)
|
client, err = ethclient.Dial(ethapi)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Can't connect: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled, cors)
|
||||||
utils.Fatalf("Can't connect: %v", err)
|
|
||||||
}
|
|
||||||
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled)
|
|
||||||
}
|
}
|
||||||
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)
|
||||||
231
cmd/swarm/upload.go
Normal file
231
cmd/swarm/upload.go
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Command bzzup uploads files to the swarm HTTP API.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func upload(ctx *cli.Context) {
|
||||||
|
args := ctx.Args()
|
||||||
|
var (
|
||||||
|
bzzapi = strings.TrimRight(ctx.GlobalString(SwarmApiFlag.Name), "/")
|
||||||
|
recursive = ctx.GlobalBool(SwarmRecursiveUploadFlag.Name)
|
||||||
|
wantManifest = ctx.GlobalBoolT(SwarmWantManifestFlag.Name)
|
||||||
|
defaultPath = ctx.GlobalString(SwarmUploadDefaultPath.Name)
|
||||||
|
)
|
||||||
|
if len(args) != 1 {
|
||||||
|
log.Fatal("need filename as the first and only argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file = args[0]
|
||||||
|
client = &client{api: bzzapi}
|
||||||
|
)
|
||||||
|
fi, err := os.Stat(expandPath(file))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if fi.IsDir() {
|
||||||
|
if !recursive {
|
||||||
|
log.Fatal("argument is a directory and recursive upload is disabled")
|
||||||
|
}
|
||||||
|
if !wantManifest {
|
||||||
|
log.Fatal("manifest is required for directory uploads")
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
log.Fatalln("upload failed:", err)
|
||||||
|
}
|
||||||
|
mroot := manifest{[]manifestEntry{entry}}
|
||||||
|
if !wantManifest {
|
||||||
|
// Print the manifest. This is the only output to stdout.
|
||||||
|
mrootJSON, _ := json.MarshalIndent(mroot, "", " ")
|
||||||
|
fmt.Println(string(mrootJSON))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hash, err := client.uploadManifest(mroot)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("manifest upload failed:", err)
|
||||||
|
}
|
||||||
|
fmt.Println(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expands a file path
|
||||||
|
// 1. replace tilde with users home dir
|
||||||
|
// 2. expands embedded environment variables
|
||||||
|
// 3. cleans the path, e.g. /a/b/../c -> /a/c
|
||||||
|
// Note, it has limitations, e.g. ~someuser/tmp will not be expanded
|
||||||
|
func expandPath(p string) string {
|
||||||
|
if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
|
||||||
|
if home := homeDir(); home != "" {
|
||||||
|
p = home + p[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path.Clean(os.ExpandEnv(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
func homeDir() string {
|
||||||
|
if home := os.Getenv("HOME"); home != "" {
|
||||||
|
return home
|
||||||
|
}
|
||||||
|
if usr, err := user.Current(); err == nil {
|
||||||
|
return usr.HomeDir
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// client wraps interaction with the swarm HTTP gateway.
|
||||||
|
type client struct {
|
||||||
|
api string
|
||||||
|
}
|
||||||
|
|
||||||
|
// manifest is the JSON representation of a swarm manifest.
|
||||||
|
type manifestEntry struct {
|
||||||
|
Hash string `json:"hash,omitempty"`
|
||||||
|
ContentType string `json:"contentType,omitempty"`
|
||||||
|
Path string `json:"path,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// manifest is the JSON representation of a swarm manifest.
|
||||||
|
type manifest struct {
|
||||||
|
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) {
|
||||||
|
hash, err := c.uploadFileContent(file, fi)
|
||||||
|
m := manifestEntry{
|
||||||
|
Hash: hash,
|
||||||
|
ContentType: mime.TypeByExtension(filepath.Ext(fi.Name())),
|
||||||
|
}
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) uploadFileContent(file string, fi os.FileInfo) (string, error) {
|
||||||
|
fd, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
log.Printf("uploading file %s (%d bytes)", file, fi.Size())
|
||||||
|
return c.postRaw("application/octet-stream", fi.Size(), fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) uploadManifest(m manifest) (string, error) {
|
||||||
|
jsm, err := json.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
log.Println("uploading manifest")
|
||||||
|
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) {
|
||||||
|
req, err := http.NewRequest("POST", c.api+"/bzzr:/", body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("content-type", mimetype)
|
||||||
|
req.ContentLength = 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
|
||||||
|
}
|
||||||
|
|
@ -18,12 +18,14 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core"
|
"github.com/ubiq/go-ubiq/core"
|
||||||
|
|
@ -65,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,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...)
|
||||||
|
|
@ -133,7 +134,15 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
stream := rlp.NewStream(fh, 0)
|
|
||||||
|
var reader io.Reader = fh
|
||||||
|
if strings.HasSuffix(fn, ".gz") {
|
||||||
|
if reader, err = gzip.NewReader(reader); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream := rlp.NewStream(reader, 0)
|
||||||
|
|
||||||
// Run actual the import.
|
// Run actual the import.
|
||||||
blocks := make(types.Blocks, importBatchSize)
|
blocks := make(types.Blocks, importBatchSize)
|
||||||
|
|
@ -195,10 +204,18 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
if err := blockchain.Export(fh); err != nil {
|
|
||||||
|
var writer io.Writer = fh
|
||||||
|
if strings.HasSuffix(fn, ".gz") {
|
||||||
|
writer = gzip.NewWriter(writer)
|
||||||
|
defer writer.(*gzip.Writer).Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := blockchain.Export(writer); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
glog.Infoln("Exported blockchain to ", fn)
|
glog.Infoln("Exported blockchain to ", fn)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +227,14 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
if err := blockchain.ExportN(fh, first, last); err != nil {
|
|
||||||
|
var writer io.Writer = fh
|
||||||
|
if strings.HasSuffix(fn, ".gz") {
|
||||||
|
writer = gzip.NewWriter(writer)
|
||||||
|
defer writer.(*gzip.Writer).Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := blockchain.ExportN(writer, first, last); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
glog.Infoln("Exported blockchain to ", fn)
|
glog.Infoln("Exported blockchain to ", fn)
|
||||||
|
|
|
||||||
|
|
@ -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. ~/.ubiq -> /home/username/.ubiq
|
// e.g. ~/.ubiq -> /home/username/.ubiq
|
||||||
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 = 88
|
|
||||||
}
|
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -920,12 +896,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("", "gubiq-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.
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,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 +255,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/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core/state"
|
"github.com/ubiq/go-ubiq/core/state"
|
||||||
"github.com/ubiq/go-ubiq/core/types"
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
|
||||||
"github.com/ubiq/go-ubiq/ethdb"
|
"github.com/ubiq/go-ubiq/ethdb"
|
||||||
"github.com/ubiq/go-ubiq/event"
|
"github.com/ubiq/go-ubiq/event"
|
||||||
"github.com/ubiq/go-ubiq/params"
|
"github.com/ubiq/go-ubiq/params"
|
||||||
"github.com/ubiq/go-ubiq/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,7 +29,9 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/golang-lru"
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
|
"github.com/ubiq/go-ubiq/common/mclock"
|
||||||
"github.com/ubiq/go-ubiq/core/state"
|
"github.com/ubiq/go-ubiq/core/state"
|
||||||
"github.com/ubiq/go-ubiq/core/types"
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
"github.com/ubiq/go-ubiq/core/vm"
|
||||||
|
|
@ -43,13 +45,9 @@ import (
|
||||||
"github.com/ubiq/go-ubiq/pow"
|
"github.com/ubiq/go-ubiq/pow"
|
||||||
"github.com/ubiq/go-ubiq/rlp"
|
"github.com/ubiq/go-ubiq/rlp"
|
||||||
"github.com/ubiq/go-ubiq/trie"
|
"github.com/ubiq/go-ubiq/trie"
|
||||||
"github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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")
|
||||||
|
|
@ -152,7 +150,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())
|
||||||
|
|
@ -404,10 +402,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.
|
||||||
|
|
@ -634,7 +629,11 @@ func (self *BlockChain) procFutureBlocks() {
|
||||||
}
|
}
|
||||||
if len(blocks) > 0 {
|
if len(blocks) > 0 {
|
||||||
types.BlockBy(types.Number).Sort(blocks)
|
types.BlockBy(types.Number).Sort(blocks)
|
||||||
self.InsertChain(blocks)
|
|
||||||
|
// Insert one by one as chain insertion needs contiguous ancestry between blocks
|
||||||
|
for i := range blocks {
|
||||||
|
self.InsertChain(blocks[i : i+1])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -708,6 +707,18 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty
|
||||||
// transaction and receipt data.
|
// transaction and receipt data.
|
||||||
// XXX should this be moved to the test?
|
// XXX should this be moved to the test?
|
||||||
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
|
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
|
||||||
|
// Do a sanity check that the provided chain is actually ordered and linked
|
||||||
|
for i := 1; i < len(blockChain); i++ {
|
||||||
|
if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() {
|
||||||
|
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||||
|
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, blockChain[i-1].NumberU64(),
|
||||||
|
blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4])
|
||||||
|
|
||||||
|
glog.V(logger.Error).Info(failure.Error())
|
||||||
|
return 0, failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Pre-checks passed, start the block body and receipt imports
|
||||||
self.wg.Add(1)
|
self.wg.Add(1)
|
||||||
defer self.wg.Done()
|
defer self.wg.Done()
|
||||||
|
|
||||||
|
|
@ -822,7 +833,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
|
||||||
}
|
}
|
||||||
|
|
@ -876,6 +887,18 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
|
||||||
// InsertChain will attempt to insert the given chain in to the canonical chain or, otherwise, create a fork. It an error is returned
|
// InsertChain will attempt to insert the given chain in to the canonical chain or, otherwise, create a fork. It an error is returned
|
||||||
// it will return the index number of the failing block as well an error describing what went wrong (for possible errors see core/errors.go).
|
// it will return the index number of the failing block as well an error describing what went wrong (for possible errors see core/errors.go).
|
||||||
func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
|
// Do a sanity check that the provided chain is actually ordered and linked
|
||||||
|
for i := 1; i < len(chain); i++ {
|
||||||
|
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {
|
||||||
|
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||||
|
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])",
|
||||||
|
i-1, chain[i-1].NumberU64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4])
|
||||||
|
|
||||||
|
glog.V(logger.Error).Info(failure.Error())
|
||||||
|
return 0, failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Pre-checks passed, start the full block imports
|
||||||
self.wg.Add(1)
|
self.wg.Add(1)
|
||||||
defer self.wg.Done()
|
defer self.wg.Done()
|
||||||
|
|
||||||
|
|
@ -886,9 +909,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))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -949,10 +972,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.reportBlock(block, nil, err)
|
self.reportBlock(block, nil, err)
|
||||||
|
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new statedb using the parent block and report an
|
// Create a new statedb using the parent block and report an
|
||||||
// error if it fails.
|
// error if it fails.
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -1021,7 +1042,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
glog.Infof("inserted forked block #%d [%x…] (TD=%v) in %9v: %3d txs %d uncles.", block.Number(), block.Hash().Bytes()[0:4], block.Difficulty(), common.PrettyDuration(time.Since(bstart)), len(block.Transactions()), len(block.Uncles()))
|
glog.Infof("inserted forked block #%d [%x…] (TD=%v) in %9v: %3d txs %d uncles.", block.Number(), block.Hash().Bytes()[0:4], block.Difficulty(), common.PrettyDuration(time.Since(bstart)), len(block.Transactions()), len(block.Uncles()))
|
||||||
}
|
}
|
||||||
blockInsertTimer.UpdateSince(bstart)
|
blockInsertTimer.UpdateSince(bstart)
|
||||||
events = append(events, ChainSideEvent{block, logs})
|
events = append(events, ChainSideEvent{block})
|
||||||
|
|
||||||
case SplitStatTy:
|
case SplitStatTy:
|
||||||
events = append(events, ChainSplitEvent{block, logs})
|
events = append(events, ChainSplitEvent{block, logs})
|
||||||
|
|
@ -1044,7 +1065,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
|
||||||
|
|
@ -1056,28 +1077,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}
|
||||||
}
|
}
|
||||||
|
|
@ -1095,24 +1112,25 @@ func countTransactions(chain []*types.Block) (c int) {
|
||||||
// event about them
|
// event about them
|
||||||
func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||||
var (
|
var (
|
||||||
newChain types.Blocks
|
newChain types.Blocks
|
||||||
oldChain types.Blocks
|
oldChain types.Blocks
|
||||||
commonBlock *types.Block
|
commonBlock *types.Block
|
||||||
oldStart = oldBlock
|
oldStart = oldBlock
|
||||||
newStart = newBlock
|
newStart = newBlock
|
||||||
deletedTxs types.Transactions
|
deletedTxs types.Transactions
|
||||||
deletedLogs vm.Logs
|
deletedLogs []*types.Log
|
||||||
deletedLogsByHash = make(map[common.Hash]vm.Logs)
|
|
||||||
// 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.
|
||||||
collectLogs = func(h common.Hash) {
|
collectLogs = func(h common.Hash) {
|
||||||
// Coalesce logs
|
// Coalesce logs and set 'Removed'.
|
||||||
receipts := GetBlockReceipts(self.chainDb, h, self.hc.GetBlockNumber(h))
|
receipts := GetBlockReceipts(self.chainDb, h, self.hc.GetBlockNumber(h))
|
||||||
for _, receipt := range receipts {
|
for _, receipt := range receipts {
|
||||||
deletedLogs = append(deletedLogs, receipt.Logs...)
|
for _, log := range receipt.Logs {
|
||||||
|
del := *log
|
||||||
deletedLogsByHash[h] = receipt.Logs
|
del.Removed = true
|
||||||
|
deletedLogs = append(deletedLogs, &del)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -1206,7 +1224,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||||
if len(oldChain) > 0 {
|
if len(oldChain) > 0 {
|
||||||
go func() {
|
go func() {
|
||||||
for _, block := range oldChain {
|
for _, block := range oldChain {
|
||||||
self.eventMux.Post(ChainSideEvent{Block: block, Logs: deletedLogsByHash[block.Hash()]})
|
self.eventMux.Post(ChainSideEvent{Block: block})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
@ -1216,7 +1234,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)
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,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:
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core/types"
|
"github.com/ubiq/go-ubiq/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/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core/types"
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
|
||||||
"github.com/ubiq/go-ubiq/crypto"
|
"github.com/ubiq/go-ubiq/crypto"
|
||||||
"github.com/ubiq/go-ubiq/crypto/sha3"
|
"github.com/ubiq/go-ubiq/crypto/sha3"
|
||||||
"github.com/ubiq/go-ubiq/ethdb"
|
"github.com/ubiq/go-ubiq/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}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,9 @@ package core
|
||||||
// genesis block.
|
// genesis block.
|
||||||
const defaultGenesisBlock = "H4sIACZxSlgAA61Sy24bMQy8+ysMn3OgKJKiegvQQw/9CerBZgE/gngLuAjy75XjGEiRtnAX5UHAUuTMzoyeV+tRm/1hX/vm03oDJ3hfqrq5u4zM064fZ9s9XsZY6T4Bpev1oz31/fzFjg+/gVlQV9x+mp/ss832Bnvtf7Pj12k3zZe2/rrUJvepft/OPy7X/hdEssTSBMcZpaRITLy5O09exnfT6eG/q6qHaV/s+GZ5vLGu27bdHupYfX79fG0NHUm8xZ65t2ih556EsqbiHjFCGVEyeKN23ltvim3tLfLw579dv9y9p0ACtCJSA9YaqAg7YE2eWonmWaBCZaT4gYJvJOhiA7drYiIs7JkVWs0NzopsHA3RM5TFBOCdJRQ0RHMD6hW4uFZXwVZjGQ4lz+GjSbcScNco4iODTBULuVPSyooKgcgNBUIQDosJQiXmDmZlOM4t5NKFyZR7IfQhpKfQe11uUQSLKedm7EKgXc4UQTlWSnVwaonKQfNyBRIpAvL5RZbhR1JOBo4gjUNHHXJi0bjcIiQE1/HisWGuGag0hhiGLizqaNWrFMnLQ3Zz6S7ckqJpD1IoSBUzAiEeIacgiv9G8Ir/snpZ/QSJtNFBkgUAAA=="
|
const defaultGenesisBlock = "H4sIACZxSlgAA61Sy24bMQy8+ysMn3OgKJKiegvQQw/9CerBZgE/gngLuAjy75XjGEiRtnAX5UHAUuTMzoyeV+tRm/1hX/vm03oDJ3hfqrq5u4zM064fZ9s9XsZY6T4Bpev1oz31/fzFjg+/gVlQV9x+mp/ss832Bnvtf7Pj12k3zZe2/rrUJvepft/OPy7X/hdEssTSBMcZpaRITLy5O09exnfT6eG/q6qHaV/s+GZ5vLGu27bdHupYfX79fG0NHUm8xZ65t2ih556EsqbiHjFCGVEyeKN23ltvim3tLfLw579dv9y9p0ACtCJSA9YaqAg7YE2eWonmWaBCZaT4gYJvJOhiA7drYiIs7JkVWs0NzopsHA3RM5TFBOCdJRQ0RHMD6hW4uFZXwVZjGQ4lz+GjSbcScNco4iODTBULuVPSyooKgcgNBUIQDosJQiXmDmZlOM4t5NKFyZR7IfQhpKfQe11uUQSLKedm7EKgXc4UQTlWSnVwaonKQfNyBRIpAvL5RZbhR1JOBo4gjUNHHXJi0bjcIiQE1/HisWGuGag0hhiGLizqaNWrFMnLQ3Zz6S7ckqJpD1IoSBUzAiEeIacgiv9G8Ir/snpZ/QSJtNFBkgUAAA=="
|
||||||
|
|
||||||
|
// defaultTestnetGenesisBlock is a gzip compressed dump of the official default Ethereum
|
||||||
|
// test network genesis block (currently Ropsten).
|
||||||
const defaultTestnetGenesisBlock = "QlpoOTFBWSZTWezl5v8AGI59gHRQABBcBH/0FGQ/795qUAN+PcGHAoQMVIwm0zCSp+ihiAANB6gqp+mmp6eMmqo0AADRpoABgAGjTQBk0BoMgNAbSqNAyDQyaBoNAyAGBUkhNNNA0JGmgD0g0AekxJtVIgTtRupd52vqSSSVfG2ALQBhhdbCIgmAgUiIJnEQTviQF8kkN1IOKiRVVFVSVXHT1cHLHdiSQBlAAG2JtCtNgCS5IEB6dNtP782Z729Tbt3Z6+uFr7u3w79widyYSMAhtlL5XeGZWdwEBNdFm+Hh5gVRBoslgksAMkUKmYlSJRTxBsQAAKKlnd3WjPWrNd66NR7WAu6AQL40vqlny1We+p3l1QThy4gRd2lSVjEKISLDFrVJ1UtjPEPctVSZGjBTJWRzpdgRmCCprJWGe3DK9wvz4eGvdv1ZZcMvxGgdakeMAVEeFywVQWLWCrUWg60Y9ZLoAuZ0uSJJUELb8N2e7j05d3Tlz7vRwgk+LisedJALLVUgFjLGzfv5SEGPLlhhjpx2aaO8T87whcYDmgPLVDBI3RF1TLnzvymWtN732u93GiAGiBdm5s1q9Haru7+yCLJAk3wBDTtrGeMVh3iJmXHo+OBAsqoDOZwjKM3d3mZmcHdBJiSVouSKVkDg+L4vSzNRqs7u6NEaIiUKoYxERGfTWIhoiHwQFESGzta21qu1qtZ3cAXQshVAUybTLbWttWh3iHLoDJEgkACRVCzbeX774Z6558+mfDTdz058efTpDbXai+tddbQBbn/YA9fwxy8/Pq3HFW7deL8W447duuyI2RGqIAAA9SOqHeXzbRtGiXeHiYBMggAAIyQh/f5vW96Xvvu7b7777yMURRHFE6EkEnxRIiOlY2ijs7RV4gYIB0R4LmgB49xg0Oz0bVr2a95u4AZE6rTjl2w58Cntu1ZV6e3Lw3ne2RegHw7R58NdbtVlJEkuqRV2WKa/hpbPIx3bIyX43aNWmezrCBry2ePzkA8reSwB/xdyRThQkOzl5v8="
|
const defaultTestnetGenesisBlock = "QlpoOTFBWSZTWezl5v8AGI59gHRQABBcBH/0FGQ/795qUAN+PcGHAoQMVIwm0zCSp+ihiAANB6gqp+mmp6eMmqo0AADRpoABgAGjTQBk0BoMgNAbSqNAyDQyaBoNAyAGBUkhNNNA0JGmgD0g0AekxJtVIgTtRupd52vqSSSVfG2ALQBhhdbCIgmAgUiIJnEQTviQF8kkN1IOKiRVVFVSVXHT1cHLHdiSQBlAAG2JtCtNgCS5IEB6dNtP782Z729Tbt3Z6+uFr7u3w79widyYSMAhtlL5XeGZWdwEBNdFm+Hh5gVRBoslgksAMkUKmYlSJRTxBsQAAKKlnd3WjPWrNd66NR7WAu6AQL40vqlny1We+p3l1QThy4gRd2lSVjEKISLDFrVJ1UtjPEPctVSZGjBTJWRzpdgRmCCprJWGe3DK9wvz4eGvdv1ZZcMvxGgdakeMAVEeFywVQWLWCrUWg60Y9ZLoAuZ0uSJJUELb8N2e7j05d3Tlz7vRwgk+LisedJALLVUgFjLGzfv5SEGPLlhhjpx2aaO8T87whcYDmgPLVDBI3RF1TLnzvymWtN732u93GiAGiBdm5s1q9Haru7+yCLJAk3wBDTtrGeMVh3iJmXHo+OBAsqoDOZwjKM3d3mZmcHdBJiSVouSKVkDg+L4vSzNRqs7u6NEaIiUKoYxERGfTWIhoiHwQFESGzta21qu1qtZ3cAXQshVAUybTLbWttWh3iHLoDJEgkACRVCzbeX774Z6558+mfDTdz058efTpDbXai+tddbQBbn/YA9fwxy8/Pq3HFW7deL8W447duuyI2RGqIAAA9SOqHeXzbRtGiXeHiYBMggAAIyQh/f5vW96Xvvu7b7777yMURRHFE6EkEnxRIiOlY2ijs7RV4gYIB0R4LmgB49xg0Oz0bVr2a95u4AZE6rTjl2w58Cntu1ZV6e3Lw3ne2RegHw7R58NdbtVlJEkuqRV2WKa/hpbPIx3bIyX43aNWmezrCBry2ePzkA8reSwB/xdyRThQkOzl5v8="
|
||||||
|
|
||||||
|
// defaultDevnetGenesisBlockis a gzip compressed dump of a dev Ethereum network genesis block.
|
||||||
|
const defaultDevnetGenesisBlock = "QlpoOTFBWSZTWb66siUAAmldgEERWAR/8AAEP6eOakACGu6ULVwyRNGKeBCbUaAGIJUDJpT2lP1BQAAANqp6jTUxMIxGmAJgFVTAp4mjSaoAxAB4cLqQ6aBgTRPcAECErBIZ9PyZJw5IYvQPWlcXDXnhaC9buNtJaAFApAgwkUIRBmBY6EhTY8/6ZXse6lLD1Eh3sfas7VHnxse2LZeXpME9fADujvYB4Wr9cgQA+Wq0gRnrfVmgVwIiIrgfON+c4EhrApvQT2LjUh6y3x41XXOxriA89W52MDId9R7vasE3pfWWATQF7nAEAWRb861EU6M9SmBTET1UUGuBmgxzewhmUe4Rj4jSvgRFRTYgI8WzzcQn3nNr6x3GW94Yp1xG4kOoC/MxDhbF8uMahuMTmKyEep0SwLaxquoT3F9X0NxmouMWhxTAlxHQoN872vbYJS/Wrls2LuptmbKr4R6BJ/oJfPNpq+H362F5ZyhNQBxXep4ZOr94ylFM6UfOeUq37kFeGzXOle3LKItkvJ70OKqEqzujic72rnpZHym6b3xSONoWjYzRzIUbOKSUgdVtEhtvUg24asA2cy1zFzsfnj8CXe0Bdi7kinChIX11ZEo="
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core/types"
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
"github.com/ubiq/go-ubiq/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,28 +44,27 @@ 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 {
|
||||||
Block *types.Block
|
Block *types.Block
|
||||||
Logs vm.Logs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PendingBlockEvent struct {
|
type PendingBlockEvent struct {
|
||||||
Block *types.Block
|
Block *types.Block
|
||||||
Logs vm.Logs
|
Logs []*types.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainUncleEvent struct {
|
type ChainUncleEvent struct {
|
||||||
|
|
|
||||||
73
core/evm.go
Normal file
73
core/evm.go
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright 2014 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/ubiq/go-ubiq/common"
|
||||||
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
|
"github.com/ubiq/go-ubiq/core/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BlockFetcher retrieves headers by their hash
|
||||||
|
type HeaderFetcher interface {
|
||||||
|
// GetHeader returns the hash corresponding to their hash
|
||||||
|
GetHeader(common.Hash, uint64) *types.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEVMContext creates a new context for use in the EVM.
|
||||||
|
func NewEVMContext(msg Message, header *types.Header, chain HeaderFetcher) vm.Context {
|
||||||
|
return vm.Context{
|
||||||
|
CanTransfer: CanTransfer,
|
||||||
|
Transfer: Transfer,
|
||||||
|
GetHash: GetHashFn(header, chain),
|
||||||
|
|
||||||
|
Origin: msg.From(),
|
||||||
|
Coinbase: header.Coinbase,
|
||||||
|
BlockNumber: new(big.Int).Set(header.Number),
|
||||||
|
Time: new(big.Int).Set(header.Time),
|
||||||
|
Difficulty: new(big.Int).Set(header.Difficulty),
|
||||||
|
GasLimit: new(big.Int).Set(header.GasLimit),
|
||||||
|
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
|
||||||
|
func GetHashFn(ref *types.Header, chain HeaderFetcher) func(n uint64) common.Hash {
|
||||||
|
return func(n uint64) common.Hash {
|
||||||
|
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
|
||||||
|
if header.Number.Uint64() == n {
|
||||||
|
return header.Hash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanTransfer checks wether there are enough funds in the address' account to make a transfer.
|
||||||
|
// This does not take the necessary gas in to account to make the transfer valid.
|
||||||
|
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
|
||||||
|
return db.GetBalance(addr).Cmp(amount) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
|
||||||
|
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
|
||||||
|
db.SubBalance(sender, amount)
|
||||||
|
db.AddBalance(recipient, amount)
|
||||||
|
}
|
||||||
|
|
@ -1,217 +0,0 @@
|
||||||
// Copyright 2014 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/ubiq/go-ubiq/common"
|
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
|
||||||
"github.com/ubiq/go-ubiq/crypto"
|
|
||||||
"github.com/ubiq/go-ubiq/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Call executes within the given contract
|
|
||||||
func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
|
||||||
// limit.
|
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
|
|
||||||
return nil, vm.DepthError
|
|
||||||
}
|
|
||||||
if !env.CanTransfer(caller.Address(), value) {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
|
|
||||||
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
|
||||||
}
|
|
||||||
|
|
||||||
snapshotPreTransfer := env.SnapshotDatabase()
|
|
||||||
var (
|
|
||||||
from = env.Db().GetAccount(caller.Address())
|
|
||||||
to vm.Account
|
|
||||||
)
|
|
||||||
if !env.Db().Exist(addr) {
|
|
||||||
if vm.Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber()) && value.BitLen() == 0 {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
to = env.Db().CreateAccount(addr)
|
|
||||||
} else {
|
|
||||||
to = env.Db().GetAccount(addr)
|
|
||||||
}
|
|
||||||
env.Transfer(from, to, value)
|
|
||||||
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
|
||||||
// EVM. The contract is a scoped environment for this execution context
|
|
||||||
// only.
|
|
||||||
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
|
||||||
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
|
|
||||||
defer contract.Finalise()
|
|
||||||
|
|
||||||
ret, err = env.Vm().Run(contract, input)
|
|
||||||
// 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
|
|
||||||
// when we're in homestead this also counts for code storage gas errors.
|
|
||||||
if err != nil {
|
|
||||||
contract.UseGas(contract.Gas)
|
|
||||||
|
|
||||||
env.RevertToSnapshot(snapshotPreTransfer)
|
|
||||||
}
|
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallCode executes the given address' code as the given contract address
|
|
||||||
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
|
||||||
// limit.
|
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
|
|
||||||
return nil, vm.DepthError
|
|
||||||
}
|
|
||||||
if !env.CanTransfer(caller.Address(), value) {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
|
|
||||||
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
snapshotPreTransfer = env.SnapshotDatabase()
|
|
||||||
to = env.Db().GetAccount(caller.Address())
|
|
||||||
)
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
|
||||||
// EVM. The contract is a scoped environment for this execution context
|
|
||||||
// only.
|
|
||||||
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
|
||||||
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
|
|
||||||
defer contract.Finalise()
|
|
||||||
|
|
||||||
ret, err = env.Vm().Run(contract, input)
|
|
||||||
if err != nil {
|
|
||||||
contract.UseGas(contract.Gas)
|
|
||||||
|
|
||||||
env.RevertToSnapshot(snapshotPreTransfer)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates a new contract with the given code
|
|
||||||
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
|
||||||
// limit.
|
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
|
|
||||||
return nil, common.Address{}, vm.DepthError
|
|
||||||
}
|
|
||||||
if !env.CanTransfer(caller.Address(), value) {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
|
|
||||||
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new account on the state
|
|
||||||
nonce := env.Db().GetNonce(caller.Address())
|
|
||||||
env.Db().SetNonce(caller.Address(), nonce+1)
|
|
||||||
|
|
||||||
snapshotPreTransfer := env.SnapshotDatabase()
|
|
||||||
var (
|
|
||||||
addr = crypto.CreateAddress(caller.Address(), nonce)
|
|
||||||
from = env.Db().GetAccount(caller.Address())
|
|
||||||
to = env.Db().CreateAccount(addr)
|
|
||||||
)
|
|
||||||
if env.ChainConfig().IsEIP158(env.BlockNumber()) {
|
|
||||||
env.Db().SetNonce(addr, 1)
|
|
||||||
}
|
|
||||||
env.Transfer(from, to, value)
|
|
||||||
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
|
||||||
// EVM. The contract is a scoped environment for this execution context
|
|
||||||
// only.
|
|
||||||
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
|
||||||
contract.SetCallCode(&addr, crypto.Keccak256Hash(code), code)
|
|
||||||
defer contract.Finalise()
|
|
||||||
|
|
||||||
ret, err = env.Vm().Run(contract, nil)
|
|
||||||
// check whether the max code size has been exceeded
|
|
||||||
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
|
|
||||||
// if the contract creation ran successfully and no errors were returned
|
|
||||||
// calculate the gas required to store the code. If the code could not
|
|
||||||
// be stored due to not enough gas set an error and let it be handled
|
|
||||||
// by the error checking condition below.
|
|
||||||
if err == nil && !maxCodeSizeExceeded {
|
|
||||||
dataGas := big.NewInt(int64(len(ret)))
|
|
||||||
dataGas.Mul(dataGas, params.CreateDataGas)
|
|
||||||
if contract.UseGas(dataGas) {
|
|
||||||
env.Db().SetCode(addr, ret)
|
|
||||||
} else {
|
|
||||||
err = vm.CodeStoreOutOfGasError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// when we're in homestead this also counts for code storage gas errors.
|
|
||||||
if maxCodeSizeExceeded ||
|
|
||||||
(err != nil && (env.ChainConfig().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError)) {
|
|
||||||
contract.UseGas(contract.Gas)
|
|
||||||
env.RevertToSnapshot(snapshotPreTransfer)
|
|
||||||
|
|
||||||
// Nothing should be returned when an error is thrown.
|
|
||||||
return nil, addr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, addr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
|
|
||||||
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
|
||||||
// limit.
|
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
|
||||||
caller.ReturnGas(gas, gasPrice)
|
|
||||||
return nil, vm.DepthError
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
snapshot = env.SnapshotDatabase()
|
|
||||||
to = env.Db().GetAccount(caller.Address())
|
|
||||||
)
|
|
||||||
|
|
||||||
// Iinitialise a new contract and make initialise the delegate values
|
|
||||||
contract := vm.NewContract(caller, to, caller.Value(), gas, gasPrice).AsDelegate()
|
|
||||||
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
|
|
||||||
defer contract.Finalise()
|
|
||||||
|
|
||||||
ret, err = env.Vm().Run(contract, input)
|
|
||||||
if err != nil {
|
|
||||||
contract.UseGas(contract.Gas)
|
|
||||||
|
|
||||||
env.RevertToSnapshot(snapshot)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// generic transfer method
|
|
||||||
func Transfer(from, to vm.Account, amount *big.Int) {
|
|
||||||
from.SubBalance(amount)
|
|
||||||
to.AddBalance(amount)
|
|
||||||
}
|
|
||||||
|
|
@ -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())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,17 @@ type WhCallback func(*types.Header) error
|
||||||
// of the header retrieval mechanisms already need to verfy nonces, as well as
|
// of the header retrieval mechanisms already need to verfy nonces, as well as
|
||||||
// because nonces can be verified sparsely, not needing to check each.
|
// because nonces can be verified sparsely, not needing to check each.
|
||||||
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, writeHeader WhCallback) (int, error) {
|
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, writeHeader WhCallback) (int, error) {
|
||||||
|
// Do a sanity check that the provided chain is actually ordered and linked
|
||||||
|
for i := 1; i < len(chain); i++ {
|
||||||
|
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
|
||||||
|
// Chain broke ancestry, log a messge (programming error) and skip insertion
|
||||||
|
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])",
|
||||||
|
i-1, chain[i-1].Number.Uint64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].Number.Uint64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash.Bytes()[:4])
|
||||||
|
|
||||||
|
glog.V(logger.Error).Info(failure.Error())
|
||||||
|
return 0, failure
|
||||||
|
}
|
||||||
|
}
|
||||||
// Collect some import statistics to report on
|
// Collect some import statistics to report on
|
||||||
stats := struct{ processed, ignored int }{}
|
stats := struct{ processed, ignored int }{}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
@ -329,7 +340,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ func (self *StateObject) setBalance(amount *big.Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||||
func (c *StateObject) ReturnGas(gas, price *big.Int) {}
|
func (c *StateObject) ReturnGas(gas *big.Int) {}
|
||||||
|
|
||||||
func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject {
|
func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject {
|
||||||
stateObject := newObject(db, self.address, self.data, onDirty)
|
stateObject := newObject(db, self.address, self.data, onDirty)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
"github.com/ubiq/go-ubiq/core/vm"
|
||||||
"github.com/ubiq/go-ubiq/crypto"
|
"github.com/ubiq/go-ubiq/crypto"
|
||||||
"github.com/ubiq/go-ubiq/ethdb"
|
"github.com/ubiq/go-ubiq/ethdb"
|
||||||
|
|
@ -31,7 +33,6 @@ import (
|
||||||
"github.com/ubiq/go-ubiq/logger/glog"
|
"github.com/ubiq/go-ubiq/logger/glog"
|
||||||
"github.com/ubiq/go-ubiq/rlp"
|
"github.com/ubiq/go-ubiq/rlp"
|
||||||
"github.com/ubiq/go-ubiq/trie"
|
"github.com/ubiq/go-ubiq/trie"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Trie cache generation limit after which to evic trie nodes from memory.
|
// Trie cache generation limit after which to evic trie nodes from memory.
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -293,6 +294,7 @@ func (self *StateDB) HasSuicided(addr common.Address) bool {
|
||||||
* SETTERS
|
* SETTERS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// AddBalance adds amount to the account associated with addr
|
||||||
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
@ -300,6 +302,14 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubBalance subtracts amount from the account associated with addr
|
||||||
|
func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
||||||
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
|
if stateObject != nil {
|
||||||
|
stateObject.SubBalance(amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) {
|
func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
@ -465,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
|
||||||
|
|
@ -520,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)
|
||||||
|
|
@ -543,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/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
"github.com/ubiq/go-ubiq/core/types"
|
||||||
"github.com/ubiq/go-ubiq/ethdb"
|
"github.com/ubiq/go-ubiq/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/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/ethdb"
|
|
||||||
"github.com/ubiq/go-ubiq/rlp"
|
"github.com/ubiq/go-ubiq/rlp"
|
||||||
"github.com/ubiq/go-ubiq/trie"
|
"github.com/ubiq/go-ubiq/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,25 +57,25 @@ 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())
|
||||||
)
|
)
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
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())
|
||||||
|
|
||||||
|
|
@ -83,37 +83,44 @@ 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
|
||||||
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, msg, header, cfg), msg, gp)
|
context := NewEVMContext(msg, header, bc)
|
||||||
|
// Create a new environment which holds all relevant information
|
||||||
|
// about the transaction and calling mechanisms.
|
||||||
|
vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
|
||||||
|
// Apply the transaction to the current state (included in the env)
|
||||||
|
_, 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
|
||||||
usedGas.Add(usedGas, gas)
|
usedGas.Add(usedGas, gas)
|
||||||
|
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
|
||||||
|
// based on the eip phase, we're passing wether the root touch-delete accounts.
|
||||||
receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas)
|
receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas)
|
||||||
receipt.TxHash = tx.Hash()
|
receipt.TxHash = tx.Hash()
|
||||||
receipt.GasUsed = new(big.Int).Set(gas)
|
receipt.GasUsed = new(big.Int).Set(gas)
|
||||||
if MessageCreatesContract(msg) {
|
// if the transaction created a contract, store the creation address in the receipt.
|
||||||
receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce())
|
if msg.To() == nil {
|
||||||
|
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
logs := statedb.GetLogs(tx.Hash())
|
// Set the receipt logs and create a bloom for filtering
|
||||||
receipt.Logs = logs
|
receipt.Logs = statedb.GetLogs(tx.Hash())
|
||||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
|
|
||||||
glog.V(logger.Debug).Infoln(receipt)
|
glog.V(logger.Debug).Infoln(receipt)
|
||||||
|
|
||||||
return 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
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,9 @@ type StateTransition struct {
|
||||||
initialGas *big.Int
|
initialGas *big.Int
|
||||||
value *big.Int
|
value *big.Int
|
||||||
data []byte
|
data []byte
|
||||||
state vm.Database
|
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,
|
||||||
|
|
@ -116,7 +116,7 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran
|
||||||
initialGas: new(big.Int),
|
initialGas: new(big.Int),
|
||||||
value: msg.Value(),
|
value: msg.Value(),
|
||||||
data: msg.Data(),
|
data: msg.Data(),
|
||||||
state: env.Db(),
|
state: env.StateDB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,7 +127,7 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran
|
||||||
// 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)
|
||||||
|
|
||||||
|
|
@ -217,47 +217,44 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||||
msg := self.msg
|
msg := self.msg
|
||||||
sender := self.from() // err checked in preCheck
|
sender := self.from() // err checked in preCheck
|
||||||
|
|
||||||
homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber())
|
homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber)
|
||||||
contractCreation := MessageCreatesContract(msg)
|
contractCreation := MessageCreatesContract(msg)
|
||||||
// Pay intrinsic gas
|
// Pay intrinsic gas
|
||||||
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
|
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
|
||||||
return nil, nil, nil, InvalidTxError(err)
|
return nil, nil, nil, InvalidTxError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vmenv := self.env
|
var (
|
||||||
//var addr common.Address
|
vmenv = self.env
|
||||||
|
// vm errors do not effect consensus and are therefor
|
||||||
|
// not assigned to err, except for insufficient balance
|
||||||
|
// error.
|
||||||
|
vmerr error
|
||||||
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, 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
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ret = nil
|
|
||||||
glog.V(logger.Core).Infoln("VM create err:", err)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1)
|
self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1)
|
||||||
ret, err = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.gasPrice, self.value)
|
ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.value)
|
||||||
if err != nil {
|
}
|
||||||
glog.V(logger.Core).Infoln("VM call err:", err)
|
if vmerr != nil {
|
||||||
|
glog.V(logger.Core).Infoln("vm returned with error:", err)
|
||||||
|
// The only possible consensus-error would be if there wasn't
|
||||||
|
// sufficient balance to make the transfer happen. The first
|
||||||
|
// balance transfer may never fail.
|
||||||
|
if vmerr == vm.ErrInsufficientBalance {
|
||||||
|
return nil, nil, nil, InvalidTxError(vmerr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && IsValueTransferErr(err) {
|
|
||||||
return nil, nil, nil, InvalidTxError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We aren't interested in errors here. Errors returned by the VM are non-consensus errors and therefor shouldn't bubble up
|
|
||||||
if err != nil {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
requiredGas = new(big.Int).Set(self.gasUsed())
|
requiredGas = new(big.Int).Set(self.gasUsed())
|
||||||
|
|
||||||
self.refundGas()
|
self.refundGas()
|
||||||
self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice))
|
self.state.AddBalance(self.env.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
|
||||||
|
|
||||||
return ret, requiredGas, self.gasUsed(), err
|
return ret, requiredGas, self.gasUsed(), err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -37,15 +37,14 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Transaction Pool Errors
|
// Transaction Pool Errors
|
||||||
ErrInvalidSender = errors.New("Invalid sender")
|
ErrInvalidSender = errors.New("Invalid sender")
|
||||||
ErrNonce = errors.New("Nonce too low")
|
ErrNonce = errors.New("Nonce too low")
|
||||||
ErrCheap = errors.New("Gas price too low for acceptance")
|
ErrCheap = errors.New("Gas price too low for acceptance")
|
||||||
ErrBalance = errors.New("Insufficient balance")
|
ErrBalance = errors.New("Insufficient balance")
|
||||||
ErrNonExistentAccount = errors.New("Account does not exist or account balance too low")
|
ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value")
|
||||||
ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value")
|
ErrIntrinsicGas = errors.New("Intrinsic gas too low")
|
||||||
ErrIntrinsicGas = errors.New("Intrinsic gas too low")
|
ErrGasLimit = errors.New("Exceeds block gas limit")
|
||||||
ErrGasLimit = errors.New("Exceeds block gas limit")
|
ErrNegativeValue = errors.New("Negative value")
|
||||||
ErrNegativeValue = errors.New("Negative value")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -124,6 +123,8 @@ func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentState
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool.resetState()
|
||||||
|
|
||||||
pool.wg.Add(2)
|
pool.wg.Add(2)
|
||||||
go pool.eventLoop()
|
go pool.eventLoop()
|
||||||
go pool.expirationLoop()
|
go pool.expirationLoop()
|
||||||
|
|
@ -176,7 +177,7 @@ func (pool *TxPool) resetState() {
|
||||||
// any transactions that have been included in the block or
|
// any transactions that have been included in the block or
|
||||||
// have been invalidated because of another transaction (e.g.
|
// have been invalidated because of another transaction (e.g.
|
||||||
// higher gas price)
|
// higher gas price)
|
||||||
pool.demoteUnexecutables()
|
pool.demoteUnexecutables(currentState)
|
||||||
|
|
||||||
// Update all accounts to the latest known pending nonce
|
// Update all accounts to the latest known pending nonce
|
||||||
for addr, list := range pool.pending {
|
for addr, list := range pool.pending {
|
||||||
|
|
@ -185,7 +186,7 @@ func (pool *TxPool) resetState() {
|
||||||
}
|
}
|
||||||
// Check the queue and move transactions over to the pending if possible
|
// Check the queue and move transactions over to the pending if possible
|
||||||
// or remove those that have become invalid
|
// or remove those that have become invalid
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables(currentState)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *TxPool) Stop() {
|
func (pool *TxPool) Stop() {
|
||||||
|
|
@ -237,21 +238,26 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common
|
||||||
// Pending retrieves all currently processable transactions, groupped by origin
|
// Pending retrieves all currently processable transactions, groupped by origin
|
||||||
// account and sorted by nonce. The returned transaction set is a copy and can be
|
// account and sorted by nonce. The returned transaction set is a copy and can be
|
||||||
// freely modified by calling code.
|
// freely modified by calling code.
|
||||||
func (pool *TxPool) Pending() map[common.Address]types.Transactions {
|
func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) {
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
defer pool.mu.Unlock()
|
defer pool.mu.Unlock()
|
||||||
|
|
||||||
|
state, err := pool.currentState()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// check queue first
|
// check queue first
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables(state)
|
||||||
|
|
||||||
// invalidate any txs
|
// invalidate any txs
|
||||||
pool.demoteUnexecutables()
|
pool.demoteUnexecutables(state)
|
||||||
|
|
||||||
pending := make(map[common.Address]types.Transactions)
|
pending := make(map[common.Address]types.Transactions)
|
||||||
for addr, list := range pool.pending {
|
for addr, list := range pool.pending {
|
||||||
pending[addr] = list.Flatten()
|
pending[addr] = list.Flatten()
|
||||||
}
|
}
|
||||||
return pending
|
return pending, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLocal marks a transaction as local, skipping gas price
|
// SetLocal marks a transaction as local, skipping gas price
|
||||||
|
|
@ -280,13 +286,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrInvalidSender
|
return ErrInvalidSender
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the account exist. Non existent accounts
|
|
||||||
// haven't got funds and well therefor never pass.
|
|
||||||
if !currentState.Exist(from) {
|
|
||||||
return ErrNonExistentAccount
|
|
||||||
}
|
|
||||||
|
|
||||||
// Last but not least check for nonce errors
|
// Last but not least check for nonce errors
|
||||||
if currentState.GetNonce(from) > tx.Nonce() {
|
if currentState.GetNonce(from) > tx.Nonce() {
|
||||||
return ErrNonce
|
return ErrNonce
|
||||||
|
|
@ -322,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])
|
||||||
|
|
@ -372,10 +371,6 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
|
||||||
//
|
//
|
||||||
// Note, this method assumes the pool lock is held!
|
// Note, this method assumes the pool lock is held!
|
||||||
func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) {
|
func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) {
|
||||||
// Init delayed since tx pool could have been started before any state sync
|
|
||||||
if pool.pendingState == nil {
|
|
||||||
pool.resetState()
|
|
||||||
}
|
|
||||||
// Try to insert the transaction into the pending queue
|
// Try to insert the transaction into the pending queue
|
||||||
if pool.pending[addr] == nil {
|
if pool.pending[addr] == nil {
|
||||||
pool.pending[addr] = newTxList(true)
|
pool.pending[addr] = newTxList(true)
|
||||||
|
|
@ -410,13 +405,19 @@ func (pool *TxPool) Add(tx *types.Transaction) error {
|
||||||
if err := pool.add(tx); err != nil {
|
if err := pool.add(tx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pool.promoteExecutables()
|
|
||||||
|
state, err := pool.currentState()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.promoteExecutables(state)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddBatch attempts to queue a batch of transactions.
|
// AddBatch attempts to queue a batch of transactions.
|
||||||
func (pool *TxPool) AddBatch(txs []*types.Transaction) {
|
func (pool *TxPool) AddBatch(txs []*types.Transaction) error {
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
defer pool.mu.Unlock()
|
defer pool.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -425,7 +426,15 @@ func (pool *TxPool) AddBatch(txs []*types.Transaction) {
|
||||||
glog.V(logger.Debug).Infoln("tx error:", err)
|
glog.V(logger.Debug).Infoln("tx error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pool.promoteExecutables()
|
|
||||||
|
state, err := pool.currentState()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.promoteExecutables(state)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns a transaction if it is contained in the pool
|
// Get returns a transaction if it is contained in the pool
|
||||||
|
|
@ -499,17 +508,7 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
||||||
// promoteExecutables moves transactions that have become processable from the
|
// promoteExecutables moves transactions that have become processable from the
|
||||||
// future queue to the set of pending transactions. During this process, all
|
// future queue to the set of pending transactions. During this process, all
|
||||||
// invalidated transactions (low nonce, low balance) are deleted.
|
// invalidated transactions (low nonce, low balance) are deleted.
|
||||||
func (pool *TxPool) promoteExecutables() {
|
func (pool *TxPool) promoteExecutables(state *state.StateDB) {
|
||||||
// Init delayed since tx pool could have been started before any state sync
|
|
||||||
if pool.pendingState == nil {
|
|
||||||
pool.resetState()
|
|
||||||
}
|
|
||||||
// Retrieve the current state to allow nonce and balance checking
|
|
||||||
state, err := pool.currentState()
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorf("Could not get current state: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Iterate over all accounts and promote any executable transactions
|
// Iterate over all accounts and promote any executable transactions
|
||||||
queued := uint64(0)
|
queued := uint64(0)
|
||||||
for addr, list := range pool.queue {
|
for addr, list := range pool.queue {
|
||||||
|
|
@ -610,7 +609,7 @@ func (pool *TxPool) promoteExecutables() {
|
||||||
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)
|
||||||
|
|
@ -645,13 +644,7 @@ func (pool *TxPool) promoteExecutables() {
|
||||||
// demoteUnexecutables removes invalid and processed transactions from the pools
|
// demoteUnexecutables removes invalid and processed transactions from the pools
|
||||||
// executable/pending queue and any subsequent transactions that become unexecutable
|
// executable/pending queue and any subsequent transactions that become unexecutable
|
||||||
// are moved back into the future queue.
|
// are moved back into the future queue.
|
||||||
func (pool *TxPool) demoteUnexecutables() {
|
func (pool *TxPool) demoteUnexecutables(state *state.StateDB) {
|
||||||
// Retrieve the current state to allow nonce and balance checking
|
|
||||||
state, err := pool.currentState()
|
|
||||||
if err != nil {
|
|
||||||
glog.V(logger.Info).Infoln("failed to get current state: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Iterate over all accounts and demote any non-executable transactions
|
// Iterate over all accounts and demote any non-executable transactions
|
||||||
for addr, list := range pool.pending {
|
for addr, list := range pool.pending {
|
||||||
nonce := state.GetNonce(addr)
|
nonce := state.GetNonce(addr)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,14 +51,84 @@ func deriveSender(tx *types.Transaction) (common.Address, error) {
|
||||||
return types.Sender(types.HomesteadSigner{}, tx)
|
return types.Sender(types.HomesteadSigner{}, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test simulates a scenario where a new block is imported during a
|
||||||
|
// state reset and tests whether the pending state is in sync with the
|
||||||
|
// block head event that initiated the resetState().
|
||||||
|
func TestStateChangeDuringPoolReset(t *testing.T) {
|
||||||
|
var (
|
||||||
|
db, _ = ethdb.NewMemDatabase()
|
||||||
|
key, _ = crypto.GenerateKey()
|
||||||
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
mux = new(event.TypeMux)
|
||||||
|
statedb, _ = state.New(common.Hash{}, db)
|
||||||
|
trigger = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// setup pool with 2 transaction in it
|
||||||
|
statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether))
|
||||||
|
|
||||||
|
tx0 := transaction(0, big.NewInt(100000), key)
|
||||||
|
tx1 := transaction(1, big.NewInt(100000), key)
|
||||||
|
|
||||||
|
// stateFunc is used multiple times to reset the pending state.
|
||||||
|
// when simulate is true it will create a state that indicates
|
||||||
|
// that tx0 and tx1 are included in the chain.
|
||||||
|
stateFunc := func() (*state.StateDB, error) {
|
||||||
|
// delay "state change" by one. The tx pool fetches the
|
||||||
|
// state multiple times and by delaying it a bit we simulate
|
||||||
|
// a state change between those fetches.
|
||||||
|
stdb := statedb
|
||||||
|
if trigger {
|
||||||
|
statedb, _ = state.New(common.Hash{}, db)
|
||||||
|
// simulate that the new head block included tx0 and tx1
|
||||||
|
statedb.SetNonce(address, 2)
|
||||||
|
statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether))
|
||||||
|
trigger = false
|
||||||
|
}
|
||||||
|
return stdb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
|
||||||
|
|
||||||
|
txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc)
|
||||||
|
txpool.resetState()
|
||||||
|
|
||||||
|
nonce := txpool.State().GetNonce(address)
|
||||||
|
if nonce != 0 {
|
||||||
|
t.Fatalf("Invalid nonce, want 0, got %d", nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
txpool.AddBatch(types.Transactions{tx0, tx1})
|
||||||
|
|
||||||
|
nonce = txpool.State().GetNonce(address)
|
||||||
|
if nonce != 2 {
|
||||||
|
t.Fatalf("Invalid nonce, want 2, got %d", nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
// trigger state change in the background
|
||||||
|
trigger = true
|
||||||
|
|
||||||
|
txpool.resetState()
|
||||||
|
|
||||||
|
pendingTx, err := txpool.Pending()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not fetch pending transactions: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for addr, txs := range pendingTx {
|
||||||
|
t.Logf("%0x: %d\n", addr, len(txs))
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce = txpool.State().GetNonce(address)
|
||||||
|
if nonce != 2 {
|
||||||
|
t.Fatalf("Invalid nonce, want 2, got %d", nonce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestInvalidTransactions(t *testing.T) {
|
func TestInvalidTransactions(t *testing.T) {
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
|
|
||||||
tx := transaction(0, big.NewInt(100), key)
|
tx := transaction(0, big.NewInt(100), key)
|
||||||
if err := pool.Add(tx); err != ErrNonExistentAccount {
|
|
||||||
t.Error("expected", ErrNonExistentAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
from, _ := deriveSender(tx)
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1))
|
currentState.AddBalance(from, big.NewInt(1))
|
||||||
|
|
@ -97,9 +167,10 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
from, _ := deriveSender(tx)
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1000))
|
currentState.AddBalance(from, big.NewInt(1000))
|
||||||
|
pool.resetState()
|
||||||
pool.enqueueTx(tx.Hash(), tx)
|
pool.enqueueTx(tx.Hash(), tx)
|
||||||
|
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables(currentState)
|
||||||
if len(pool.pending) != 1 {
|
if len(pool.pending) != 1 {
|
||||||
t.Error("expected valid txs to be 1 is", len(pool.pending))
|
t.Error("expected valid txs to be 1 is", len(pool.pending))
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +179,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
from, _ = deriveSender(tx)
|
from, _ = deriveSender(tx)
|
||||||
currentState.SetNonce(from, 2)
|
currentState.SetNonce(from, 2)
|
||||||
pool.enqueueTx(tx.Hash(), tx)
|
pool.enqueueTx(tx.Hash(), tx)
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables(currentState)
|
||||||
if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok {
|
if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok {
|
||||||
t.Error("expected transaction to be in tx pool")
|
t.Error("expected transaction to be in tx pool")
|
||||||
}
|
}
|
||||||
|
|
@ -124,11 +195,13 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
from, _ = deriveSender(tx1)
|
from, _ = deriveSender(tx1)
|
||||||
currentState, _ = pool.currentState()
|
currentState, _ = pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1000))
|
currentState.AddBalance(from, big.NewInt(1000))
|
||||||
|
pool.resetState()
|
||||||
|
|
||||||
pool.enqueueTx(tx1.Hash(), tx1)
|
pool.enqueueTx(tx1.Hash(), tx1)
|
||||||
pool.enqueueTx(tx2.Hash(), tx2)
|
pool.enqueueTx(tx2.Hash(), tx2)
|
||||||
pool.enqueueTx(tx3.Hash(), tx3)
|
pool.enqueueTx(tx3.Hash(), tx3)
|
||||||
|
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables(currentState)
|
||||||
|
|
||||||
if len(pool.pending) != 1 {
|
if len(pool.pending) != 1 {
|
||||||
t.Error("expected tx pool to be 1, got", len(pool.pending))
|
t.Error("expected tx pool to be 1, got", len(pool.pending))
|
||||||
|
|
@ -165,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))
|
||||||
|
|
@ -214,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 {
|
||||||
|
|
@ -225,7 +298,8 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
if err := pool.add(tx2); err != nil {
|
if err := pool.add(tx2); err != nil {
|
||||||
t.Error("didn't expect error", err)
|
t.Error("didn't expect error", err)
|
||||||
}
|
}
|
||||||
pool.promoteExecutables()
|
state, _ := pool.currentState()
|
||||||
|
pool.promoteExecutables(state)
|
||||||
if pool.pending[addr].Len() != 1 {
|
if pool.pending[addr].Len() != 1 {
|
||||||
t.Error("expected 1 pending transactions, got", pool.pending[addr].Len())
|
t.Error("expected 1 pending transactions, got", pool.pending[addr].Len())
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +310,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
if err := pool.add(tx3); err != nil {
|
if err := pool.add(tx3); err != nil {
|
||||||
t.Error("didn't expect error", err)
|
t.Error("didn't expect error", err)
|
||||||
}
|
}
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables(state)
|
||||||
if pool.pending[addr].Len() != 1 {
|
if pool.pending[addr].Len() != 1 {
|
||||||
t.Error("expected 1 pending transactions, got", pool.pending[addr].Len())
|
t.Error("expected 1 pending transactions, got", pool.pending[addr].Len())
|
||||||
}
|
}
|
||||||
|
|
@ -295,6 +369,7 @@ func TestRemovedTxEvent(t *testing.T) {
|
||||||
from, _ := deriveSender(tx)
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1000000000000))
|
currentState.AddBalance(from, big.NewInt(1000000000000))
|
||||||
|
pool.resetState()
|
||||||
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
|
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
|
||||||
pool.eventMux.Post(ChainHeadEvent{nil})
|
pool.eventMux.Post(ChainHeadEvent{nil})
|
||||||
if pool.pending[from].Len() != 1 {
|
if pool.pending[from].Len() != 1 {
|
||||||
|
|
@ -452,6 +527,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
|
||||||
|
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
pool.resetState()
|
||||||
|
|
||||||
// Keep queuing up transactions and make sure all above a limit are dropped
|
// Keep queuing up transactions and make sure all above a limit are dropped
|
||||||
for i := uint64(1); i <= maxQueuedPerAccount+5; i++ {
|
for i := uint64(1); i <= maxQueuedPerAccount+5; i++ {
|
||||||
|
|
@ -564,6 +640,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
|
||||||
|
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
pool.resetState()
|
||||||
|
|
||||||
// Keep queuing up transactions and make sure all above a limit are dropped
|
// Keep queuing up transactions and make sure all above a limit are dropped
|
||||||
for i := uint64(0); i < maxQueuedPerAccount+5; i++ {
|
for i := uint64(0); i < maxQueuedPerAccount+5; i++ {
|
||||||
|
|
@ -733,7 +810,7 @@ func benchmarkPendingDemotion(b *testing.B, size int) {
|
||||||
// Benchmark the speed of pool validation
|
// Benchmark the speed of pool validation
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
pool.demoteUnexecutables()
|
pool.demoteUnexecutables(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -757,7 +834,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
|
||||||
// Benchmark the speed of pool validation
|
// Benchmark the speed of pool validation
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/common/hexutil"
|
"github.com/ubiq/go-ubiq/common/hexutil"
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
|
||||||
"github.com/ubiq/go-ubiq/crypto"
|
"github.com/ubiq/go-ubiq/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[:]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
184
core/types/log.go
Normal file
184
core/types/log.go
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Copyright 2014 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ubiq/go-ubiq/common"
|
||||||
|
"github.com/ubiq/go-ubiq/common/hexutil"
|
||||||
|
"github.com/ubiq/go-ubiq/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errMissingLogFields = errors.New("missing required JSON log fields")
|
||||||
|
|
||||||
|
// Log represents a contract log event. These events are generated by the LOG opcode and
|
||||||
|
// stored/indexed by the node.
|
||||||
|
type Log struct {
|
||||||
|
// Consensus fields.
|
||||||
|
Address common.Address // address of the contract that generated the event
|
||||||
|
Topics []common.Hash // list of topics provided by the contract.
|
||||||
|
Data []byte // supplied by the contract, usually ABI-encoded
|
||||||
|
|
||||||
|
// Derived fields. These fields are filled in by the node
|
||||||
|
// but not secured by consensus.
|
||||||
|
BlockNumber uint64 // block in which the transaction was included
|
||||||
|
TxHash common.Hash // hash of the transaction
|
||||||
|
TxIndex uint // index of the transaction in the block
|
||||||
|
BlockHash common.Hash // hash of the block in which the transaction was included
|
||||||
|
Index uint // index of the log in the receipt
|
||||||
|
|
||||||
|
// The Removed field is true if this log was reverted due to a chain reorganisation.
|
||||||
|
// You must pay attention to this field if you receive logs through a filter query.
|
||||||
|
Removed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type rlpLog struct {
|
||||||
|
Address common.Address
|
||||||
|
Topics []common.Hash
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type rlpStorageLog struct {
|
||||||
|
Address common.Address
|
||||||
|
Topics []common.Hash
|
||||||
|
Data []byte
|
||||||
|
BlockNumber uint64
|
||||||
|
TxHash common.Hash
|
||||||
|
TxIndex uint
|
||||||
|
BlockHash common.Hash
|
||||||
|
Index uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonLog struct {
|
||||||
|
Address *common.Address `json:"address"`
|
||||||
|
Topics *[]common.Hash `json:"topics"`
|
||||||
|
Data *hexutil.Bytes `json:"data"`
|
||||||
|
BlockNumber *hexutil.Uint64 `json:"blockNumber"`
|
||||||
|
TxIndex *hexutil.Uint `json:"transactionIndex"`
|
||||||
|
TxHash *common.Hash `json:"transactionHash"`
|
||||||
|
BlockHash *common.Hash `json:"blockHash"`
|
||||||
|
Index *hexutil.Uint `json:"logIndex"`
|
||||||
|
Removed bool `json:"removed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeRLP implements rlp.Encoder.
|
||||||
|
func (l *Log) EncodeRLP(w io.Writer) error {
|
||||||
|
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeRLP implements rlp.Decoder.
|
||||||
|
func (l *Log) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
var dec rlpLog
|
||||||
|
err := s.Decode(&dec)
|
||||||
|
if err == nil {
|
||||||
|
l.Address, l.Topics, l.Data = dec.Address, dec.Topics, dec.Data
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Log) String() string {
|
||||||
|
return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (l *Log) MarshalJSON() ([]byte, error) {
|
||||||
|
jslog := &jsonLog{
|
||||||
|
Address: &l.Address,
|
||||||
|
Topics: &l.Topics,
|
||||||
|
Data: (*hexutil.Bytes)(&l.Data),
|
||||||
|
TxIndex: (*hexutil.Uint)(&l.TxIndex),
|
||||||
|
TxHash: &l.TxHash,
|
||||||
|
Index: (*hexutil.Uint)(&l.Index),
|
||||||
|
Removed: l.Removed,
|
||||||
|
}
|
||||||
|
// Set block information for mined logs.
|
||||||
|
if (l.BlockHash != common.Hash{}) {
|
||||||
|
jslog.BlockHash = &l.BlockHash
|
||||||
|
jslog.BlockNumber = (*hexutil.Uint64)(&l.BlockNumber)
|
||||||
|
}
|
||||||
|
return json.Marshal(jslog)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Umarshaler.
|
||||||
|
func (l *Log) UnmarshalJSON(input []byte) error {
|
||||||
|
var dec jsonLog
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dec.Address == nil || dec.Topics == nil || dec.Data == nil ||
|
||||||
|
dec.TxIndex == nil || dec.TxHash == nil || dec.Index == nil {
|
||||||
|
return errMissingLogFields
|
||||||
|
}
|
||||||
|
declog := Log{
|
||||||
|
Address: *dec.Address,
|
||||||
|
Topics: *dec.Topics,
|
||||||
|
Data: *dec.Data,
|
||||||
|
TxHash: *dec.TxHash,
|
||||||
|
TxIndex: uint(*dec.TxIndex),
|
||||||
|
Index: uint(*dec.Index),
|
||||||
|
Removed: dec.Removed,
|
||||||
|
}
|
||||||
|
// Block information may be missing if the log is received through
|
||||||
|
// the pending log filter, so it's handled specially here.
|
||||||
|
if dec.BlockHash != nil && dec.BlockNumber != nil {
|
||||||
|
declog.BlockHash = *dec.BlockHash
|
||||||
|
declog.BlockNumber = uint64(*dec.BlockNumber)
|
||||||
|
}
|
||||||
|
*l = declog
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
|
||||||
|
// a log including non-consensus fields.
|
||||||
|
type LogForStorage Log
|
||||||
|
|
||||||
|
// EncodeRLP implements rlp.Encoder.
|
||||||
|
func (l *LogForStorage) EncodeRLP(w io.Writer) error {
|
||||||
|
return rlp.Encode(w, rlpStorageLog{
|
||||||
|
Address: l.Address,
|
||||||
|
Topics: l.Topics,
|
||||||
|
Data: l.Data,
|
||||||
|
BlockNumber: l.BlockNumber,
|
||||||
|
TxHash: l.TxHash,
|
||||||
|
TxIndex: l.TxIndex,
|
||||||
|
BlockHash: l.BlockHash,
|
||||||
|
Index: l.Index,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeRLP implements rlp.Decoder.
|
||||||
|
func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
var dec rlpStorageLog
|
||||||
|
err := s.Decode(&dec)
|
||||||
|
if err == nil {
|
||||||
|
*l = LogForStorage{
|
||||||
|
Address: dec.Address,
|
||||||
|
Topics: dec.Topics,
|
||||||
|
Data: dec.Data,
|
||||||
|
BlockNumber: dec.BlockNumber,
|
||||||
|
TxHash: dec.TxHash,
|
||||||
|
TxIndex: dec.TxIndex,
|
||||||
|
BlockHash: dec.BlockHash,
|
||||||
|
Index: dec.Index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
131
core/types/log_test.go
Normal file
131
core/types/log_test.go
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
// 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/ubiq/go-ubiq/common"
|
||||||
|
"github.com/ubiq/go-ubiq/common/hexutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var unmarshalLogTests = map[string]struct {
|
||||||
|
input string
|
||||||
|
want *Log
|
||||||
|
wantError error
|
||||||
|
}{
|
||||||
|
"ok": {
|
||||||
|
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
|
||||||
|
want: &Log{
|
||||||
|
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
|
||||||
|
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
|
||||||
|
BlockNumber: 2019236,
|
||||||
|
Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000001a055690d9db80000"),
|
||||||
|
Index: 2,
|
||||||
|
TxIndex: 3,
|
||||||
|
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
|
||||||
|
Topics: []common.Hash{
|
||||||
|
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
|
||||||
|
common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"empty data": {
|
||||||
|
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
|
||||||
|
want: &Log{
|
||||||
|
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
|
||||||
|
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
|
||||||
|
BlockNumber: 2019236,
|
||||||
|
Data: []byte{},
|
||||||
|
Index: 2,
|
||||||
|
TxIndex: 3,
|
||||||
|
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
|
||||||
|
Topics: []common.Hash{
|
||||||
|
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
|
||||||
|
common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"missing block fields (pending logs)": {
|
||||||
|
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","data":"0x","logIndex":"0x0","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
|
||||||
|
want: &Log{
|
||||||
|
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
|
||||||
|
BlockHash: common.Hash{},
|
||||||
|
BlockNumber: 0,
|
||||||
|
Data: []byte{},
|
||||||
|
Index: 0,
|
||||||
|
TxIndex: 3,
|
||||||
|
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
|
||||||
|
Topics: []common.Hash{
|
||||||
|
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Removed: true": {
|
||||||
|
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3","removed":true}`,
|
||||||
|
want: &Log{
|
||||||
|
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
|
||||||
|
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
|
||||||
|
BlockNumber: 2019236,
|
||||||
|
Data: []byte{},
|
||||||
|
Index: 2,
|
||||||
|
TxIndex: 3,
|
||||||
|
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
|
||||||
|
Topics: []common.Hash{
|
||||||
|
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
|
||||||
|
},
|
||||||
|
Removed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"missing data": {
|
||||||
|
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
|
||||||
|
wantError: errMissingLogFields,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalLog(t *testing.T) {
|
||||||
|
dumper := spew.ConfigState{DisableMethods: true, Indent: " "}
|
||||||
|
for name, test := range unmarshalLogTests {
|
||||||
|
var log *Log
|
||||||
|
err := json.Unmarshal([]byte(test.input), &log)
|
||||||
|
checkError(t, name, err, test.wantError)
|
||||||
|
if test.wantError == nil && err == nil {
|
||||||
|
if !reflect.DeepEqual(log, test.want) {
|
||||||
|
t.Errorf("test %q:\nGOT %sWANT %s", name, dumper.Sdump(log), dumper.Sdump(test.want))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkError(t *testing.T, testname string, got, want error) bool {
|
||||||
|
if got == nil {
|
||||||
|
if want != nil {
|
||||||
|
t.Errorf("test %q: got no error, want %q", testname, want)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if want == nil {
|
||||||
|
t.Errorf("test %q: unexpected error %q", testname, got)
|
||||||
|
} else if got.Error() != want.Error() {
|
||||||
|
t.Errorf("test %q: got error %q, want %q", testname, got, want)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
"github.com/ubiq/go-ubiq/common/hexutil"
|
"github.com/ubiq/go-ubiq/common/hexutil"
|
||||||
"github.com/ubiq/go-ubiq/core/vm"
|
|
||||||
"github.com/ubiq/go-ubiq/rlp"
|
"github.com/ubiq/go-ubiq/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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
|
|
||||||
// ContractRef is a reference to the contract's backing object
|
// ContractRef is a reference to the contract's backing object
|
||||||
type ContractRef interface {
|
type ContractRef interface {
|
||||||
ReturnGas(*big.Int, *big.Int)
|
ReturnGas(*big.Int)
|
||||||
Address() common.Address
|
Address() common.Address
|
||||||
Value() *big.Int
|
Value() *big.Int
|
||||||
SetCode(common.Hash, []byte)
|
SetCode(common.Hash, []byte)
|
||||||
|
|
@ -48,7 +48,7 @@ type Contract struct {
|
||||||
CodeAddr *common.Address
|
CodeAddr *common.Address
|
||||||
Input []byte
|
Input []byte
|
||||||
|
|
||||||
value, Gas, UsedGas, Price *big.Int
|
value, Gas, UsedGas *big.Int
|
||||||
|
|
||||||
Args []byte
|
Args []byte
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ type Contract struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContract returns a new contract environment for the execution of EVM.
|
// NewContract returns a new contract environment for the execution of EVM.
|
||||||
func NewContract(caller ContractRef, object ContractRef, value, gas, price *big.Int) *Contract {
|
func NewContract(caller ContractRef, object ContractRef, value, gas *big.Int) *Contract {
|
||||||
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
|
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
|
||||||
|
|
||||||
if parent, ok := caller.(*Contract); ok {
|
if parent, ok := caller.(*Contract); ok {
|
||||||
|
|
@ -70,9 +70,6 @@ func NewContract(caller ContractRef, object ContractRef, value, gas, price *big.
|
||||||
// This pointer will be off the state transition
|
// This pointer will be off the state transition
|
||||||
c.Gas = gas //new(big.Int).Set(gas)
|
c.Gas = gas //new(big.Int).Set(gas)
|
||||||
c.value = new(big.Int).Set(value)
|
c.value = new(big.Int).Set(value)
|
||||||
// In most cases price and value are pointers to transaction objects
|
|
||||||
// and we don't want the transaction's values to change.
|
|
||||||
c.Price = new(big.Int).Set(price)
|
|
||||||
c.UsedGas = new(big.Int)
|
c.UsedGas = new(big.Int)
|
||||||
|
|
||||||
return c
|
return c
|
||||||
|
|
@ -114,7 +111,7 @@ func (c *Contract) Caller() common.Address {
|
||||||
// caller.
|
// caller.
|
||||||
func (c *Contract) Finalise() {
|
func (c *Contract) Finalise() {
|
||||||
// Return the remaining gas to the caller
|
// Return the remaining gas to the caller
|
||||||
c.caller.ReturnGas(c.Gas, c.Price)
|
c.caller.ReturnGas(c.Gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseGas attempts the use gas and subtracts it and returns true on success
|
// UseGas attempts the use gas and subtracts it and returns true on success
|
||||||
|
|
@ -127,7 +124,7 @@ func (c *Contract) UseGas(gas *big.Int) (ok bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReturnGas adds the given gas back to itself.
|
// ReturnGas adds the given gas back to itself.
|
||||||
func (c *Contract) ReturnGas(gas, price *big.Int) {
|
func (c *Contract) ReturnGas(gas *big.Int) {
|
||||||
// Return the gas to the context
|
// Return the gas to the context
|
||||||
c.Gas.Add(c.Gas, gas)
|
c.Gas.Add(c.Gas, gas)
|
||||||
c.UsedGas.Sub(c.UsedGas, gas)
|
c.UsedGas.Sub(c.UsedGas, gas)
|
||||||
|
|
|
||||||
|
|
@ -26,84 +26,59 @@ import (
|
||||||
"github.com/ubiq/go-ubiq/params"
|
"github.com/ubiq/go-ubiq/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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,110 +17,312 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/ubiq/go-ubiq/common"
|
"github.com/ubiq/go-ubiq/common"
|
||||||
|
"github.com/ubiq/go-ubiq/crypto"
|
||||||
"github.com/ubiq/go-ubiq/params"
|
"github.com/ubiq/go-ubiq/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Environment is an EVM requirement and helper which allows access to outside
|
type (
|
||||||
// information such as states.
|
CanTransferFunc func(StateDB, common.Address, *big.Int) bool
|
||||||
type Environment interface {
|
TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
|
||||||
// The current ruleset
|
// GetHashFunc returns the nth block hash in the blockchain
|
||||||
ChainConfig() *params.ChainConfig
|
// and is used by the BLOCKHASH EVM op code.
|
||||||
// The state database
|
GetHashFunc func(uint64) common.Hash
|
||||||
Db() Database
|
)
|
||||||
// Creates a restorable snapshot
|
|
||||||
SnapshotDatabase() int
|
// Context provides the EVM with auxiliary information. Once provided it shouldn't be modified.
|
||||||
// Set database to previous snapshot
|
type Context struct {
|
||||||
RevertToSnapshot(int)
|
// CanTransfer returns whether the account contains
|
||||||
// Address of the original invoker (first occurrence of the VM invoker)
|
// sufficient ether to transfer the value
|
||||||
Origin() common.Address
|
CanTransfer CanTransferFunc
|
||||||
// The block number this VM is invoked on
|
// Transfer transfers ether from one account to the other
|
||||||
BlockNumber() *big.Int
|
Transfer TransferFunc
|
||||||
// The n'th hash ago from this block number
|
// GetHash returns the hash corresponding to n
|
||||||
GetHash(uint64) common.Hash
|
GetHash GetHashFunc
|
||||||
// The handler's address
|
|
||||||
Coinbase() common.Address
|
// Message information
|
||||||
// The current time (block time)
|
Origin common.Address // Provides information for ORIGIN
|
||||||
Time() *big.Int
|
GasPrice *big.Int // Provides information for GASPRICE
|
||||||
// Difficulty set on the current block
|
|
||||||
Difficulty() *big.Int
|
// Block information
|
||||||
// The gas limit of the block
|
Coinbase common.Address // Provides information for COINBASE
|
||||||
GasLimit() *big.Int
|
GasLimit *big.Int // Provides information for GASLIMIT
|
||||||
// Determines whether it's possible to transact
|
BlockNumber *big.Int // Provides information for NUMBER
|
||||||
CanTransfer(from common.Address, balance *big.Int) bool
|
Time *big.Int // Provides information for TIME
|
||||||
// Transfers amount from one account to the other
|
Difficulty *big.Int // Provides information for DIFFICULTY
|
||||||
Transfer(from, to Account, amount *big.Int)
|
|
||||||
// Adds a LOG to the state
|
|
||||||
AddLog(*Log)
|
|
||||||
// Type of the VM
|
|
||||||
Vm() Vm
|
|
||||||
// Get the curret calling depth
|
|
||||||
Depth() int
|
|
||||||
// Set the current calling depth
|
|
||||||
SetDepth(i int)
|
|
||||||
// Call another contract
|
|
||||||
Call(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
|
|
||||||
// Take another's contract code and execute within our own context
|
|
||||||
CallCode(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
|
|
||||||
// Same as CallCode except sender and value is propagated from parent to child scope
|
|
||||||
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
|
|
||||||
// Create a new contract
|
|
||||||
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vm is the basic interface for an implementation of the EVM.
|
// EVM provides information about external sources for the EVM
|
||||||
type Vm interface {
|
//
|
||||||
// Run should execute the given contract with the input given in in
|
// The EVM should never be reused and is not thread safe.
|
||||||
// and return the contract execution return bytes or an error if it
|
type EVM struct {
|
||||||
// failed.
|
// Context provides auxiliary blockchain related information
|
||||||
Run(c *Contract, in []byte) ([]byte, error)
|
Context
|
||||||
|
// StateDB gives access to the underlying state
|
||||||
|
StateDB StateDB
|
||||||
|
// Depth is the current call stack
|
||||||
|
depth int
|
||||||
|
|
||||||
|
// chainConfig contains information about the current chain
|
||||||
|
chainConfig *params.ChainConfig
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database is a EVM database for full state querying.
|
// NewEVM retutrns a new EVM evmironment.
|
||||||
type Database interface {
|
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
|
||||||
GetAccount(common.Address) Account
|
evm := &EVM{
|
||||||
CreateAccount(common.Address) Account
|
Context: ctx,
|
||||||
|
StateDB: statedb,
|
||||||
|
vmConfig: vmConfig,
|
||||||
|
chainConfig: chainConfig,
|
||||||
|
}
|
||||||
|
|
||||||
AddBalance(common.Address, *big.Int)
|
evm.interpreter = NewInterpreter(evm, vmConfig)
|
||||||
GetBalance(common.Address) *big.Int
|
return evm
|
||||||
|
|
||||||
GetNonce(common.Address) uint64
|
|
||||||
SetNonce(common.Address, uint64)
|
|
||||||
|
|
||||||
GetCodeHash(common.Address) common.Hash
|
|
||||||
GetCodeSize(common.Address) int
|
|
||||||
GetCode(common.Address) []byte
|
|
||||||
SetCode(common.Address, []byte)
|
|
||||||
|
|
||||||
AddRefund(*big.Int)
|
|
||||||
GetRefund() *big.Int
|
|
||||||
|
|
||||||
GetState(common.Address, common.Hash) common.Hash
|
|
||||||
SetState(common.Address, common.Hash, common.Hash)
|
|
||||||
|
|
||||||
Suicide(common.Address) bool
|
|
||||||
HasSuicided(common.Address) bool
|
|
||||||
|
|
||||||
// Exist reports whether the given account exists in state.
|
|
||||||
// Notably this should also return true for suicided accounts.
|
|
||||||
Exist(common.Address) bool
|
|
||||||
// Empty returns whether the given account is empty. Empty
|
|
||||||
// is defined according to EIP161 (balance = nonce = code = 0).
|
|
||||||
Empty(common.Address) bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account represents a contract or basic ethereum account.
|
// Cancel cancels any running EVM operation. This may be called concurrently and it's safe to be
|
||||||
type Account interface {
|
// called multiple times.
|
||||||
SubBalance(amount *big.Int)
|
func (evm *EVM) Cancel() {
|
||||||
AddBalance(amount *big.Int)
|
atomic.StoreInt32(&evm.abort, 1)
|
||||||
SetBalance(*big.Int)
|
|
||||||
SetNonce(uint64)
|
|
||||||
Balance() *big.Int
|
|
||||||
Address() common.Address
|
|
||||||
ReturnGas(*big.Int, *big.Int)
|
|
||||||
SetCode(common.Hash, []byte)
|
|
||||||
ForEachStorage(cb func(key, value common.Hash) bool)
|
|
||||||
Value() *big.Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// case of an execution error or failed value transfer.
|
||||||
|
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
|
||||||
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
|
// limit.
|
||||||
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, ErrDepth
|
||||||
|
}
|
||||||
|
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, ErrInsufficientBalance
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
to Account
|
||||||
|
snapshot = evm.StateDB.Snapshot()
|
||||||
|
)
|
||||||
|
if !evm.StateDB.Exist(addr) {
|
||||||
|
if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.BitLen() == 0 {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
to = evm.StateDB.CreateAccount(addr)
|
||||||
|
} else {
|
||||||
|
to = evm.StateDB.GetAccount(addr)
|
||||||
|
}
|
||||||
|
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
||||||
|
|
||||||
|
// initialise a new contract and set the code that is to be used by the
|
||||||
|
// E The contract is a scoped evmironment for this execution context
|
||||||
|
// only.
|
||||||
|
contract := NewContract(caller, to, value, gas)
|
||||||
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
|
defer contract.Finalise()
|
||||||
|
|
||||||
|
ret, err = evm.interpreter.Run(contract, input)
|
||||||
|
// 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
|
||||||
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
|
if err != nil {
|
||||||
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// 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.
|
||||||
|
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
|
||||||
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
|
// limit.
|
||||||
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, ErrDepth
|
||||||
|
}
|
||||||
|
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", value, evm.StateDB.GetBalance(caller.Address()))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
snapshot = evm.StateDB.Snapshot()
|
||||||
|
to = evm.StateDB.GetAccount(caller.Address())
|
||||||
|
)
|
||||||
|
// initialise a new contract and set the code that is to be used by the
|
||||||
|
// E The contract is a scoped evmironment for this execution context
|
||||||
|
// only.
|
||||||
|
contract := NewContract(caller, to, value, gas)
|
||||||
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
|
defer contract.Finalise()
|
||||||
|
|
||||||
|
ret, err = evm.interpreter.Run(contract, input)
|
||||||
|
if err != nil {
|
||||||
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelegateCall executes the contract associated with the addr with the given input as parameters.
|
||||||
|
// 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
|
||||||
|
// and the caller is set to the caller of the caller.
|
||||||
|
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas *big.Int) (ret []byte, err error) {
|
||||||
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
|
// limit.
|
||||||
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
return nil, ErrDepth
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
snapshot = evm.StateDB.Snapshot()
|
||||||
|
to = evm.StateDB.GetAccount(caller.Address())
|
||||||
|
)
|
||||||
|
|
||||||
|
// Iinitialise a new contract and make initialise the delegate values
|
||||||
|
contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
|
||||||
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
|
defer contract.Finalise()
|
||||||
|
|
||||||
|
ret, err = evm.interpreter.Run(contract, input)
|
||||||
|
if err != nil {
|
||||||
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new contract using code as deployment code.
|
||||||
|
func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (ret []byte, contractAddr common.Address, err error) {
|
||||||
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, common.Address{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
|
// limit.
|
||||||
|
if evm.depth > int(params.CallCreateDepth.Int64()) {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, common.Address{}, ErrDepth
|
||||||
|
}
|
||||||
|
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
|
caller.ReturnGas(gas)
|
||||||
|
|
||||||
|
return nil, common.Address{}, ErrInsufficientBalance
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new account on the state
|
||||||
|
nonce := evm.StateDB.GetNonce(caller.Address())
|
||||||
|
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||||
|
|
||||||
|
snapshot := evm.StateDB.Snapshot()
|
||||||
|
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
|
||||||
|
to := evm.StateDB.CreateAccount(contractAddr)
|
||||||
|
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||||
|
evm.StateDB.SetNonce(contractAddr, 1)
|
||||||
|
}
|
||||||
|
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
||||||
|
|
||||||
|
// initialise a new contract and set the code that is to be used by the
|
||||||
|
// E The contract is a scoped evmironment for this execution context
|
||||||
|
// only.
|
||||||
|
contract := NewContract(caller, to, value, gas)
|
||||||
|
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
||||||
|
defer contract.Finalise()
|
||||||
|
|
||||||
|
ret, err = evm.interpreter.Run(contract, nil)
|
||||||
|
|
||||||
|
// check whether the max code size has been exceeded
|
||||||
|
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
|
||||||
|
// if the contract creation ran successfully and no errors were returned
|
||||||
|
// calculate the gas required to store the code. If the code could not
|
||||||
|
// be stored due to not enough gas set an error and let it be handled
|
||||||
|
// by the error checking condition below.
|
||||||
|
if err == nil && !maxCodeSizeExceeded {
|
||||||
|
dataGas := big.NewInt(int64(len(ret)))
|
||||||
|
dataGas.Mul(dataGas, params.CreateDataGas)
|
||||||
|
if contract.UseGas(dataGas) {
|
||||||
|
evm.StateDB.SetCode(contractAddr, ret)
|
||||||
|
} else {
|
||||||
|
err = ErrCodeStoreOutOfGas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
|
if maxCodeSizeExceeded ||
|
||||||
|
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
|
||||||
|
contract.UseGas(contract.Gas)
|
||||||
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
|
// Nothing should be returned when an error is thrown.
|
||||||
|
return nil, contractAddr, err
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
// tests, RPC calls, etc.
|
||||||
|
if err != nil {
|
||||||
|
ret = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, contractAddr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainConfig returns the evmironment's chain configuration
|
||||||
|
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||||
|
|
||||||
|
// Interpreter returns the EVM interpreter
|
||||||
|
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue