mirror of
https://github.com/arnaucube/go-ethereum.git
synced 2026-03-03 15:44:52 +01:00
Compare commits
180 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da2a22c384 | ||
|
|
0fa9a8929c | ||
|
|
2a1a531ba3 | ||
|
|
51f6b6d33f | ||
|
|
b5a100b859 | ||
|
|
54fcab20e3 | ||
|
|
a2bc90d1d7 | ||
|
|
c01f8c3d3c | ||
|
|
e4181a7f1b | ||
|
|
01f6f2d741 | ||
|
|
c5df37c111 | ||
|
|
e0ceeab0d1 | ||
|
|
93077c98e4 | ||
|
|
3dab303826 | ||
|
|
3160fd24ba | ||
|
|
ce7822c130 | ||
|
|
745a3adebd | ||
|
|
218ec6c085 | ||
|
|
d30d7800e0 | ||
|
|
8820d97039 | ||
|
|
b52fde7cf7 | ||
|
|
2b4d0b6ff9 | ||
|
|
21f1370d2a | ||
|
|
d78f9b834a | ||
|
|
445deb7470 | ||
|
|
02b67558e8 | ||
|
|
91c8f87fb1 | ||
|
|
d056b7fa52 | ||
|
|
2a609af518 | ||
|
|
1d5d6616ae | ||
|
|
b9b3efb09f | ||
|
|
0f34d506b5 | ||
|
|
5eccc122e8 | ||
|
|
681b51aac4 | ||
|
|
4268cb8efe | ||
|
|
3f1a72908c | ||
|
|
2fed476ce1 | ||
|
|
6cb39dd3da | ||
|
|
88cc1ca55a | ||
|
|
1bd9769111 | ||
|
|
47372813ef | ||
|
|
fc213c873d | ||
|
|
972f0bd3db | ||
|
|
808310a569 | ||
|
|
0a5450fe04 | ||
|
|
9bab0b8a24 | ||
|
|
17182732f5 | ||
|
|
18c77744ff | ||
|
|
ac93a6ff6c | ||
|
|
13e3b2f433 | ||
|
|
f2da6581ba | ||
|
|
444fc892b0 | ||
|
|
b56aee3697 | ||
|
|
35a7dcb162 | ||
|
|
e0fde02290 | ||
|
|
59b8245bbc | ||
|
|
8f9daaa3ba | ||
|
|
d3b751e4d9 | ||
|
|
7731061903 | ||
|
|
b9683d3748 | ||
|
|
66979aa468 | ||
|
|
93f9c023cc | ||
|
|
e0ee0cc66a | ||
|
|
9b135a9c20 | ||
|
|
e171bf74f8 | ||
|
|
bb2e99dfc2 | ||
|
|
b37d175e59 | ||
|
|
f087633efd | ||
|
|
bbce726c8a | ||
|
|
bbc4ea4ae8 | ||
|
|
2126d81488 | ||
|
|
06b381d1c9 | ||
|
|
08eea0f0e4 | ||
|
|
a1798a8188 | ||
|
|
0fac8cba47 | ||
|
|
1ca74aba6f | ||
|
|
2ce30382d9 | ||
|
|
8bc545be2a | ||
|
|
891fcd8ce1 | ||
|
|
bd06091874 | ||
|
|
3e3edcc465 | ||
|
|
89a32267f7 | ||
|
|
021177ca9b | ||
|
|
115364b0a9 | ||
|
|
6d15d00ac4 | ||
|
|
bdaa43510b | ||
|
|
9a51f5c350 | ||
|
|
301c0a6303 | ||
|
|
65f486ff02 | ||
|
|
df096a7771 | ||
|
|
0e9a9f243f | ||
|
|
12c964b2b7 | ||
|
|
cf71f5cd60 | ||
|
|
adab2e16bd | ||
|
|
a3e3235d97 | ||
|
|
2be3c4b0e3 | ||
|
|
0ee796632a | ||
|
|
1fe67c125d | ||
|
|
ba996f5e27 | ||
|
|
64bf5bafe9 | ||
|
|
4d05bbf2a4 | ||
|
|
471990f771 | ||
|
|
7b623aab9d | ||
|
|
e871ae1270 | ||
|
|
c44830ebf3 | ||
|
|
3e4a04f34d | ||
|
|
38827dd9ca | ||
|
|
21fd9f037e | ||
|
|
033763eaf7 | ||
|
|
2573094df2 | ||
|
|
745026b7b4 | ||
|
|
a07d955eaa | ||
|
|
9d6f4e2e7f | ||
|
|
ff07d54843 | ||
|
|
e53879328c | ||
|
|
b792412d31 | ||
|
|
49c6f1053c | ||
|
|
4d960f6dc6 | ||
|
|
8941665896 | ||
|
|
9cc0f60666 | ||
|
|
fdb8edf5ea | ||
|
|
9ba9fe818d | ||
|
|
92224d27b1 | ||
|
|
157a4bd926 | ||
|
|
29d6881112 | ||
|
|
e2692921e1 | ||
|
|
b63138c3ec | ||
|
|
a59fcc33e6 | ||
|
|
07311f3157 | ||
|
|
17637ed1bb | ||
|
|
f15828e901 | ||
|
|
dadd689359 | ||
|
|
b750cab56a | ||
|
|
485748c416 | ||
|
|
080699f7df | ||
|
|
8e35f54931 | ||
|
|
d44f1a77ee | ||
|
|
4181046488 | ||
|
|
d7c398b638 | ||
|
|
5f5d0aa4ff | ||
|
|
9f1520b4c0 | ||
|
|
a98e8c0889 | ||
|
|
ee445a2ba4 | ||
|
|
b2c226cb7d | ||
|
|
13614f4e1c | ||
|
|
4f9ccdd70f | ||
|
|
4e36b1e3da | ||
|
|
f12f8a6c14 | ||
|
|
c57c54ce96 | ||
|
|
c8130df1d9 | ||
|
|
af8a742d00 | ||
|
|
e67500aa15 | ||
|
|
a6d3bf6fc3 | ||
|
|
3e617f3cd6 | ||
|
|
0fe35b907a | ||
|
|
3fc7c97827 | ||
|
|
7f79d249a6 | ||
|
|
f138374027 | ||
|
|
f52a1ae849 | ||
|
|
3bc0fe1ee3 | ||
|
|
fa0cc27400 | ||
|
|
4cb29bde2e | ||
|
|
2dcf75a722 | ||
|
|
671fd94e25 | ||
|
|
717d2f6f9e | ||
|
|
8cb95cb916 | ||
|
|
56b446190a | ||
|
|
86f9e836be | ||
|
|
a90a170361 | ||
|
|
889a5e0cf1 | ||
|
|
9f8bc00cf5 | ||
|
|
3363a1c227 | ||
|
|
fc9939c4e1 | ||
|
|
7267f796e6 | ||
|
|
7dfeceb8cc | ||
|
|
3807e520ec | ||
|
|
7625b1a4f4 | ||
|
|
1fc5cc1b59 | ||
|
|
61ccb43487 | ||
|
|
bf24b120d7 |
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
@@ -9,9 +9,7 @@ and help.
|
||||
|
||||
If you'd like to contribute to go-ethereum please fork, fix, commit and
|
||||
send a pull request. Commits which do not comply with the coding standards
|
||||
are ignored (use gofmt!). If you send pull requests make absolute sure that you
|
||||
commit on the `develop` branch and that you do not merge to master.
|
||||
Commits that are directly based on master are simply ignored.
|
||||
are ignored (use gofmt!).
|
||||
|
||||
See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
|
||||
for more details on configuring your environment, testing, and
|
||||
|
||||
10
.travis.yml
10
.travis.yml
@@ -13,15 +13,15 @@ matrix:
|
||||
go: 1.6.2
|
||||
- os: linux
|
||||
dist: trusty
|
||||
go: 1.7
|
||||
go: 1.7.4
|
||||
- os: osx
|
||||
go: 1.7
|
||||
go: 1.7.4
|
||||
|
||||
# This builder does the Ubuntu PPA and Linux Azure uploads
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
go: 1.7
|
||||
go: 1.7.4
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
- azure-linux
|
||||
@@ -55,7 +55,7 @@ matrix:
|
||||
|
||||
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
|
||||
- os: osx
|
||||
go: 1.7
|
||||
go: 1.7.4
|
||||
env:
|
||||
- azure-osx
|
||||
- mobile
|
||||
@@ -90,7 +90,7 @@ install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- go run build/ci.go install
|
||||
- go run build/ci.go test -coverage -vet
|
||||
- go run build/ci.go test -coverage -vet -misspell
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
|
||||
@@ -39,9 +39,7 @@ The go-ethereum project comes with several wrappers/executables found in the `cm
|
||||
| `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`). |
|
||||
| `gethrpctest` | Developer utility tool to support our [ethereum/rpc-test](https://github.com/ethereum/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ethereum/rpc-tests/blob/master/README.md) for details. |
|
||||
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ethereum/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. |
|
||||
| `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 |
|
||||
| `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. |
|
||||
|
||||
## Running geth
|
||||
|
||||
|
||||
@@ -91,8 +91,30 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||
// first we need to create a slice of the type
|
||||
var refSlice reflect.Value
|
||||
switch elem.T {
|
||||
case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int.
|
||||
refSlice = reflect.ValueOf([]*big.Int(nil))
|
||||
case IntTy, UintTy, BoolTy:
|
||||
// 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
|
||||
refSlice = reflect.ValueOf([]common.Address(nil))
|
||||
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)
|
||||
switch elem.T {
|
||||
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:
|
||||
inter = common.BytesToBig(returnOutput).Uint64() > 0
|
||||
case AddressTy:
|
||||
@@ -169,7 +211,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
|
||||
// argument in T.
|
||||
func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -233,7 +275,7 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
|
||||
return common.BytesToAddress(returnOutput), nil
|
||||
case HashTy:
|
||||
return common.BytesToHash(returnOutput), nil
|
||||
case BytesTy, FixedBytesTy:
|
||||
case BytesTy, FixedBytesTy, FunctionTy:
|
||||
return returnOutput, nil
|
||||
case StringTy:
|
||||
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 {
|
||||
var fields []struct {
|
||||
Type string
|
||||
Name string
|
||||
Constant bool
|
||||
Indexed bool
|
||||
Inputs []Argument
|
||||
Outputs []Argument
|
||||
Type string
|
||||
Name string
|
||||
Constant bool
|
||||
Indexed bool
|
||||
Anonymous bool
|
||||
Inputs []Argument
|
||||
Outputs []Argument
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &fields); err != nil {
|
||||
@@ -375,8 +418,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
|
||||
}
|
||||
case "event":
|
||||
abi.Events[field.Name] = Event{
|
||||
Name: field.Name,
|
||||
Inputs: field.Inputs,
|
||||
Name: field.Name,
|
||||
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]", []uint16{1, 2, 3}, ""},
|
||||
{"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[1]", []common.Address{common.Address{1}}, ""},
|
||||
{"address[1]", [1]common.Address{common.Address{1}}, ""},
|
||||
{"address[2]", [1]common.Address{common.Address{1}}, "abi: cannot use [1]array as type [2]array as argument"},
|
||||
{"address[]", []common.Address{{1}}, ""},
|
||||
{"address[1]", []common.Address{{1}}, ""},
|
||||
{"address[1]", [1]common.Address{{1}}, ""},
|
||||
{"address[2]", [1]common.Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"},
|
||||
{"bytes32", [32]byte{}, ""},
|
||||
{"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"},
|
||||
{"bytes32", common.Hash{1}, ""},
|
||||
@@ -80,7 +80,8 @@ func TestTypeCheck(t *testing.T) {
|
||||
{"bytes", [2]byte{0, 1}, ""},
|
||||
{"bytes", common.Hash{1}, ""},
|
||||
{"string", "hello world", ""},
|
||||
{"bytes32[]", [][32]byte{[32]byte{}}, ""},
|
||||
{"bytes32[]", [][32]byte{{}}, ""},
|
||||
{"function", [24]byte{}, ""},
|
||||
} {
|
||||
typ, err := NewType(test.typ)
|
||||
if err != nil {
|
||||
@@ -197,6 +198,13 @@ func TestSimpleMethodUnpack(t *testing.T) {
|
||||
"interface",
|
||||
"",
|
||||
},
|
||||
{
|
||||
`[ { "type": "function" } ]`,
|
||||
pad([]byte{1}, 32, false),
|
||||
[24]byte{1},
|
||||
"function",
|
||||
"",
|
||||
},
|
||||
} {
|
||||
abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
|
||||
abi, err := JSON(strings.NewReader(abiDefinition))
|
||||
@@ -255,6 +263,10 @@ func TestSimpleMethodUnpack(t *testing.T) {
|
||||
var v common.Hash
|
||||
err = abi.Unpack(&v, "method", test.marshalledOutput)
|
||||
outvar = v
|
||||
case "function":
|
||||
var v [24]byte
|
||||
err = abi.Unpack(&v, "method", test.marshalledOutput)
|
||||
outvar = v
|
||||
case "interface":
|
||||
err = abi.Unpack(&outvar, "method", test.marshalledOutput)
|
||||
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) {
|
||||
for i, test := range []struct {
|
||||
typ string
|
||||
@@ -331,8 +367,9 @@ func TestPack(t *testing.T) {
|
||||
{"uint16[]", []uint16{1, 2}, formatSliceOutput([]byte{1}, []byte{2})},
|
||||
{"bytes20", [20]byte{1}, pad([]byte{1}, 32, false)},
|
||||
{"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))},
|
||||
{"bytes32[]", []common.Hash{common.Hash{1}, common.Hash{2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))},
|
||||
{"address[]", []common.Address{{1}, {2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, 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)
|
||||
if err != nil {
|
||||
@@ -445,12 +482,12 @@ func TestReader(t *testing.T) {
|
||||
Uint256, _ := NewType("uint256")
|
||||
exp := ABI{
|
||||
Methods: map[string]Method{
|
||||
"balance": Method{
|
||||
"balance": {
|
||||
"balance", true, nil, nil,
|
||||
},
|
||||
"send": Method{
|
||||
"send": {
|
||||
"send", false, []Argument{
|
||||
Argument{"amount", Uint256, false},
|
||||
{"amount", Uint256, false},
|
||||
}, nil,
|
||||
},
|
||||
},
|
||||
@@ -549,7 +586,7 @@ func TestTestSlice(t *testing.T) {
|
||||
|
||||
func TestMethodSignature(t *testing.T) {
|
||||
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)"
|
||||
if m.Sig() != exp {
|
||||
t.Error("signature mismatch", exp, "!=", m.Sig())
|
||||
@@ -561,7 +598,7 @@ func TestMethodSignature(t *testing.T) {
|
||||
}
|
||||
|
||||
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)"
|
||||
if m.Sig() != exp {
|
||||
t.Error("signature mismatch", exp, "!=", m.Sig())
|
||||
@@ -752,23 +789,58 @@ func TestDefaultFunctionParsing(t *testing.T) {
|
||||
func TestBareEvents(t *testing.T) {
|
||||
const definition = `[
|
||||
{ "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))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(abi.Events) != 2 {
|
||||
t.Error("expected 2 events")
|
||||
if len(abi.Events) != len(expectedEvents) {
|
||||
t.Fatalf("invalid number of events after parsing, want %d, got %d", len(expectedEvents), len(abi.Events))
|
||||
}
|
||||
|
||||
if _, ok := abi.Events["balance"]; !ok {
|
||||
t.Error("expected 'balance' event to be present")
|
||||
}
|
||||
|
||||
if _, ok := abi.Events["name"]; !ok {
|
||||
t.Error("expected 'name' event to be present")
|
||||
for name, exp := range expectedEvents {
|
||||
got, ok := abi.Events[name]
|
||||
if !ok {
|
||||
t.Errorf("could not found event %s", name)
|
||||
continue
|
||||
}
|
||||
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 {
|
||||
var extarg struct {
|
||||
Name string
|
||||
Type string
|
||||
Name string
|
||||
Type string
|
||||
Indexed bool
|
||||
}
|
||||
err := json.Unmarshal(data, &extarg)
|
||||
if err != nil {
|
||||
@@ -44,6 +45,7 @@ func (a *Argument) UnmarshalJSON(data []byte) error {
|
||||
return err
|
||||
}
|
||||
a.Name = extarg.Name
|
||||
a.Indexed = extarg.Indexed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
|
||||
if address != keyAddr {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -225,7 +225,11 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||
from.SetBalance(common.MaxBig)
|
||||
// Execute the 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)
|
||||
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||
return ret, gasUsed, err
|
||||
|
||||
@@ -170,7 +170,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||
if value == nil {
|
||||
value = new(big.Int)
|
||||
}
|
||||
nonce := uint64(0)
|
||||
var nonce uint64
|
||||
if opts.Nonce == nil {
|
||||
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
|
||||
if err != nil {
|
||||
|
||||
@@ -147,21 +147,21 @@ func bindTypeGo(kind abi.Type) string {
|
||||
|
||||
switch {
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%scommon.Address", parts[1])
|
||||
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
return fmt.Sprintf("%s[%s]byte", parts[2], parts[1])
|
||||
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
@@ -172,7 +172,7 @@ func bindTypeGo(kind abi.Type) string {
|
||||
return fmt.Sprintf("%s*big.Int", parts[3])
|
||||
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
@@ -191,7 +191,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||
|
||||
switch {
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
@@ -201,7 +201,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||
return fmt.Sprintf("Addresses")
|
||||
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
@@ -211,7 +211,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||
return "byte[]"
|
||||
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
@@ -230,7 +230,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||
return fmt.Sprintf("BigInts")
|
||||
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
@@ -240,7 +240,7 @@ func bindTypeJava(kind abi.Type) string {
|
||||
return fmt.Sprintf("bool[]")
|
||||
|
||||
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 {
|
||||
return stringKind
|
||||
}
|
||||
@@ -278,7 +278,7 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
|
||||
case "bool[]":
|
||||
return "Bools"
|
||||
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 {
|
||||
return javaKind
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) {
|
||||
|
||||
// Create the transaction.
|
||||
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.
|
||||
var (
|
||||
|
||||
@@ -25,10 +25,12 @@ import (
|
||||
)
|
||||
|
||||
// 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 {
|
||||
Name string
|
||||
Inputs []Argument
|
||||
Name string
|
||||
Anonymous bool
|
||||
Inputs []Argument
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
|
||||
case FixedBytesTy:
|
||||
case FixedBytesTy, FunctionTy:
|
||||
if reflectValue.Kind() == reflect.Array {
|
||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ const (
|
||||
FixedBytesTy
|
||||
BytesTy
|
||||
HashTy
|
||||
RealTy
|
||||
FixedpointTy
|
||||
FunctionTy
|
||||
)
|
||||
|
||||
// Type is the reflection of the supported argument type
|
||||
@@ -57,16 +58,16 @@ var (
|
||||
// Types can be in the format of:
|
||||
//
|
||||
// Input = Type [ "[" [ Number ] "]" ] Name .
|
||||
// Type = [ "u" ] "int" [ Number ] .
|
||||
// Type = [ "u" ] "int" [ Number ] [ x ] [ Number ].
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// string int uint real
|
||||
// string int uint fixed
|
||||
// string32 int8 uint8 uint[]
|
||||
// address int256 uint256 real[2]
|
||||
fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?")
|
||||
// address int256 uint256 fixed128x128[2]
|
||||
fullTypeRegex = regexp.MustCompile(`([a-zA-Z0-9]+)(\[([0-9]*)\])?`)
|
||||
// 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.
|
||||
@@ -90,14 +91,19 @@ func NewType(t string) (typ Type, err error) {
|
||||
}
|
||||
typ.Elem = &sliceType
|
||||
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.
|
||||
parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
|
||||
// varSize is the size of the variable
|
||||
var varSize int
|
||||
if len(parsedType[2]) > 0 {
|
||||
if len(parsedType[3]) > 0 {
|
||||
var err error
|
||||
varSize, err = strconv.Atoi(parsedType[2])
|
||||
if err != nil {
|
||||
@@ -111,7 +117,12 @@ func NewType(t string) (typ Type, err error) {
|
||||
varSize = 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 {
|
||||
case "int":
|
||||
@@ -148,6 +159,12 @@ func NewType(t string) (typ Type, err error) {
|
||||
typ.T = FixedBytesTy
|
||||
typ.SliceSize = varSize
|
||||
}
|
||||
case "function":
|
||||
sliceType, _ := NewType("uint8")
|
||||
typ.Elem = &sliceType
|
||||
typ.IsArray = true
|
||||
typ.T = FunctionTy
|
||||
typ.SliceSize = 24
|
||||
default:
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Sign calculates a ECDSA signature for the given hash.
|
||||
// Note, Ethereum signatures have a particular format as described in the
|
||||
// yellow paper. Use the SignEthereum function to calculate a signature
|
||||
// in Ethereum format.
|
||||
// Sign calculates a ECDSA signature for the given hash. The produced signature
|
||||
// is in the [R || S || V] format where V is 0 or 1.
|
||||
func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
|
||||
am.mu.RLock()
|
||||
defer am.mu.RUnlock()
|
||||
|
||||
unlockedKey, found := am.unlocked[addr]
|
||||
if !found {
|
||||
return nil, ErrLocked
|
||||
@@ -150,28 +149,16 @@ func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
|
||||
return crypto.Sign(hash, unlockedKey.PrivateKey)
|
||||
}
|
||||
|
||||
// SignEthereum calculates a ECDSA signature for the given hash.
|
||||
// The signature has the format as described in the Ethereum yellow paper.
|
||||
func (am *Manager) SignEthereum(addr common.Address, hash []byte) ([]byte, error) {
|
||||
am.mu.RLock()
|
||||
defer am.mu.RUnlock()
|
||||
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)
|
||||
// SignWithPassphrase signs hash if the private key matching the given address
|
||||
// can be decrypted with the given passphrase. The produced signature is in the
|
||||
// [R || S || V] format where V is 0 or 1.
|
||||
func (am *Manager) SignWithPassphrase(a Account, passphrase string, hash []byte) (signature []byte, err error) {
|
||||
_, key, err := am.getDecryptedKey(a, passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer zeroKey(key.PrivateKey)
|
||||
return crypto.SignEthereum(hash, key.PrivateKey)
|
||||
return crypto.Sign(hash, key.PrivateKey)
|
||||
}
|
||||
|
||||
// Unlock unlocks the given account indefinitely.
|
||||
|
||||
@@ -95,7 +95,7 @@ func TestSignWithPassphrase(t *testing.T) {
|
||||
t.Fatal("expected account to be locked")
|
||||
}
|
||||
|
||||
_, err = am.SignWithPassphrase(acc.Address, pass, testSigData)
|
||||
_, err = am.SignWithPassphrase(acc, pass, testSigData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -104,7 +104,7 @@ func TestSignWithPassphrase(t *testing.T) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
@@ -115,6 +115,9 @@ func TestTimedUnlock(t *testing.T) {
|
||||
|
||||
pass := "foo"
|
||||
a1, err := am.NewAccount(pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Signing without passphrase fails because account is locked
|
||||
_, err = am.Sign(a1.Address, testSigData)
|
||||
@@ -147,6 +150,9 @@ func TestOverrideUnlock(t *testing.T) {
|
||||
|
||||
pass := "foo"
|
||||
a1, err := am.NewAccount(pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Unlock indefinitely.
|
||||
if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil {
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@@ -53,6 +54,9 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
|
||||
return nil, err
|
||||
}
|
||||
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid hex in encSeed")
|
||||
}
|
||||
iv := encSeedBytes[:16]
|
||||
cipherText := encSeedBytes[16:]
|
||||
/*
|
||||
|
||||
@@ -22,8 +22,8 @@ environment:
|
||||
|
||||
install:
|
||||
- rmdir C:\go /s /q
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.3.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.7.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.4.windows-%GETH_ARCH%.zip
|
||||
- 7z x go1.7.4.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
|
||||
- go version
|
||||
- gcc --version
|
||||
|
||||
|
||||
59
build/ci.go
59
build/ci.go
@@ -24,7 +24,7 @@ Usage: go run ci.go <command> <command flags/arguments>
|
||||
Available commands are:
|
||||
|
||||
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
|
||||
importkeys -- imports signing keys from env
|
||||
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
||||
@@ -72,9 +72,7 @@ var (
|
||||
executablePath("abigen"),
|
||||
executablePath("evm"),
|
||||
executablePath("geth"),
|
||||
executablePath("bzzd"),
|
||||
executablePath("bzzhash"),
|
||||
executablePath("bzzup"),
|
||||
executablePath("swarm"),
|
||||
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.",
|
||||
},
|
||||
{
|
||||
Name: "bzzd",
|
||||
Description: "Ethereum Swarm daemon",
|
||||
},
|
||||
{
|
||||
Name: "bzzup",
|
||||
Description: "Ethereum Swarm command line file/directory uploader",
|
||||
},
|
||||
{
|
||||
Name: "bzzhash",
|
||||
Description: "Ethereum Swarm file/directory hash calculator",
|
||||
Name: "swarm",
|
||||
Description: "Ethereum Swarm daemon and tools",
|
||||
},
|
||||
{
|
||||
Name: "abigen",
|
||||
@@ -112,7 +102,8 @@ var (
|
||||
|
||||
// Distros for which packages are created.
|
||||
// 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"))
|
||||
@@ -204,7 +195,7 @@ func doInstall(cmdline []string) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for name, _ := range pkgs {
|
||||
for name := range pkgs {
|
||||
if name == "main" {
|
||||
gobuild := goToolArch(*arch, "build", buildFlags(env)...)
|
||||
gobuild.Args = append(gobuild.Args, "-v")
|
||||
@@ -271,6 +262,7 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd {
|
||||
func doTest(cmdline []string) {
|
||||
var (
|
||||
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")
|
||||
)
|
||||
flag.CommandLine.Parse(cmdline)
|
||||
@@ -296,7 +288,9 @@ func doTest(cmdline []string) {
|
||||
if *vet {
|
||||
build.MustRun(goTool("vet", packages...))
|
||||
}
|
||||
|
||||
if *misspell {
|
||||
spellcheck(packages)
|
||||
}
|
||||
// Run the actual tests.
|
||||
gotest := goTool("test")
|
||||
// Test a single package at a time. CI builders are slow
|
||||
@@ -309,6 +303,34 @@ func doTest(cmdline []string) {
|
||||
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
|
||||
|
||||
func doArchive(cmdline []string) {
|
||||
@@ -638,6 +660,7 @@ func doWindowsInstaller(cmdline []string) {
|
||||
build.Render("build/nsis.geth.nsi", filepath.Join(*workdir, "geth.nsi"), 0644, nil)
|
||||
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.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.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, "COPYING"), "COPYING", 0755)
|
||||
@@ -800,7 +823,7 @@ func doXCodeFramework(cmdline []string) {
|
||||
// Build the iOS XCode framework
|
||||
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||
build.MustRun(gomobileTool("init"))
|
||||
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "--prefix", "GE", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||
|
||||
if *local {
|
||||
// If we're building locally, use the build folder and stop afterwards
|
||||
|
||||
@@ -17,8 +17,12 @@
|
||||
#
|
||||
# Requirements:
|
||||
# - 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)
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# TODO:
|
||||
@@ -37,6 +41,7 @@ RequestExecutionLevel admin
|
||||
SetCompressor /SOLID lzma
|
||||
|
||||
!include LogicLib.nsh
|
||||
!include PathUpdate.nsh
|
||||
!include EnvVarUpdate.nsh
|
||||
|
||||
!macro VerifyUserIsAdmin
|
||||
|
||||
@@ -37,8 +37,9 @@ Section "Geth" GETH_IDX
|
||||
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc"
|
||||
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\geth.ipc"
|
||||
|
||||
# Add geth to PATH
|
||||
${EnvVarUpdate} $0 "PATH" "A" "HKLM" $INSTDIR
|
||||
# Add instdir to PATH
|
||||
Push "$INSTDIR"
|
||||
Call AddToPath
|
||||
SectionEnd
|
||||
|
||||
# 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\geth.ipc"
|
||||
|
||||
# Remove install directory from PATH
|
||||
${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" $INSTDIR
|
||||
Push "$INSTDIR"
|
||||
Call un.RemoveFromPath
|
||||
|
||||
# Cleanup registry (deletes all sub keys)
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}"
|
||||
|
||||
@@ -185,7 +185,7 @@ func getFiles() []string {
|
||||
files = append(files, line)
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("error getting files:", err)
|
||||
log.Fatal("error getting files:", err)
|
||||
}
|
||||
return files
|
||||
}
|
||||
@@ -294,7 +294,7 @@ func getInfo(files <-chan string, out chan<- *info, wg *sync.WaitGroup) {
|
||||
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) {
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
)
|
||||
|
||||
@@ -32,20 +33,28 @@ func main() {
|
||||
fmt.Println(err)
|
||||
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)
|
||||
|
||||
for pc := uint64(0); pc < uint64(len(code)); pc++ {
|
||||
op := vm.OpCode(code[pc])
|
||||
fmt.Printf("%-5d %v", pc, 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:
|
||||
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
|
||||
default:
|
||||
fmt.Printf("%-5d %v\n", pc, op)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,12 +88,7 @@ func runTestWithReader(test string, r io.Reader) error {
|
||||
default:
|
||||
err = fmt.Errorf("Invalid test type specified: %v", test)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func getFiles(path string) ([]string, error) {
|
||||
|
||||
156
cmd/evm/main.go
156
cmd/evm/main.go
@@ -20,21 +20,18 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
goruntime "runtime"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
@@ -47,14 +44,6 @@ var (
|
||||
Name: "debug",
|
||||
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{
|
||||
Name: "code",
|
||||
Usage: "EVM code",
|
||||
@@ -98,6 +87,10 @@ var (
|
||||
Name: "create",
|
||||
Usage: "indicates the action should be create rather than call",
|
||||
}
|
||||
DisableGasMeteringFlag = cli.BoolFlag{
|
||||
Name: "nogasmetering",
|
||||
Usage: "disable gas metering",
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -105,8 +98,6 @@ func init() {
|
||||
CreateFlag,
|
||||
DebugFlag,
|
||||
VerbosityFlag,
|
||||
ForceJitFlag,
|
||||
DisableJitFlag,
|
||||
SysStatFlag,
|
||||
CodeFlag,
|
||||
CodeFileFlag,
|
||||
@@ -115,6 +106,7 @@ func init() {
|
||||
ValueFlag,
|
||||
DumpFlag,
|
||||
InputFlag,
|
||||
DisableGasMeteringFlag,
|
||||
}
|
||||
app.Action = run
|
||||
}
|
||||
@@ -129,13 +121,6 @@ func run(ctx *cli.Context) error {
|
||||
|
||||
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()
|
||||
|
||||
var (
|
||||
@@ -168,25 +153,32 @@ func run(ctx *cli.Context) error {
|
||||
|
||||
if ctx.GlobalBool(CreateFlag.Name) {
|
||||
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
|
||||
ret, _, err = vmenv.Create(
|
||||
sender,
|
||||
input,
|
||||
common.Big(ctx.GlobalString(GasFlag.Name)),
|
||||
common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||
common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||
)
|
||||
ret, _, err = runtime.Create(input, &runtime.Config{
|
||||
Origin: sender.Address(),
|
||||
State: statedb,
|
||||
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
|
||||
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: logger,
|
||||
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
|
||||
|
||||
receiver.SetCode(crypto.Keccak256Hash(code), code)
|
||||
ret, err = vmenv.Call(
|
||||
sender,
|
||||
receiver.Address(),
|
||||
common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)),
|
||||
common.Big(ctx.GlobalString(GasFlag.Name)),
|
||||
common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||
common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||
)
|
||||
|
||||
ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
|
||||
Origin: sender.Address(),
|
||||
State: statedb,
|
||||
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
|
||||
GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
|
||||
Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: logger,
|
||||
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
|
||||
},
|
||||
})
|
||||
}
|
||||
vmdone := time.Since(tstart)
|
||||
|
||||
@@ -197,8 +189,8 @@ func run(ctx *cli.Context) error {
|
||||
vm.StdErrFormat(logger.StructLogs())
|
||||
|
||||
if ctx.GlobalBool(SysStatFlag.Name) {
|
||||
var mem runtime.MemStats
|
||||
runtime.ReadMemStats(&mem)
|
||||
var mem goruntime.MemStats
|
||||
goruntime.ReadMemStats(&mem)
|
||||
fmt.Printf("vm took %v\n", vmdone)
|
||||
fmt.Printf(`alloc: %d
|
||||
tot alloc: %d
|
||||
@@ -223,87 +215,3 @@ func main() {
|
||||
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",
|
||||
}
|
||||
for _, m := range wantMessages {
|
||||
if strings.Index(geth.stderrText(), m) == -1 {
|
||||
if !strings.Contains(geth.stderrText(), m) {
|
||||
t.Errorf("stderr text does not contain %q", m)
|
||||
}
|
||||
}
|
||||
@@ -193,7 +193,7 @@ Passphrase: {{.InputLine "foobar"}}
|
||||
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
||||
}
|
||||
for _, m := range wantMessages {
|
||||
if strings.Index(geth.stderrText(), m) == -1 {
|
||||
if !strings.Contains(geth.stderrText(), m) {
|
||||
t.Errorf("stderr text does not contain %q", m)
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
|
||||
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
|
||||
}
|
||||
for _, m := range wantMessages {
|
||||
if strings.Index(geth.stderrText(), m) == -1 {
|
||||
if !strings.Contains(geth.stderrText(), m) {
|
||||
t.Errorf("stderr text does not contain %q", m)
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ In order to avoid this warning, you need to remove the following duplicate key f
|
||||
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
|
||||
}
|
||||
for _, m := range wantMessages {
|
||||
if strings.Index(geth.stderrText(), m) == -1 {
|
||||
if !strings.Contains(geth.stderrText(), m) {
|
||||
t.Errorf("stderr text does not contain %q", m)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/syndtr/goleveldb/leveldb/util"
|
||||
@@ -39,6 +40,18 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
initCommand = cli.Command{
|
||||
Action: initGenesis,
|
||||
Name: "init",
|
||||
Usage: "Bootstrap and initialize a new genesis block",
|
||||
ArgsUsage: "<genesisPath>",
|
||||
Category: "BLOCKCHAIN COMMANDS",
|
||||
Description: `
|
||||
The init command initializes a new genesis block and definition for the network.
|
||||
This is a destructive action and changes the network in which you will be
|
||||
participating.
|
||||
`,
|
||||
}
|
||||
importCommand = cli.Command{
|
||||
Action: importChain,
|
||||
Name: "import",
|
||||
@@ -95,6 +108,30 @@ Use "ethereum dump 0" to dump the genesis block.
|
||||
}
|
||||
)
|
||||
|
||||
// initGenesis will initialise the given JSON format genesis file and writes it as
|
||||
// the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
|
||||
func initGenesis(ctx *cli.Context) error {
|
||||
genesisPath := ctx.Args().First()
|
||||
if len(genesisPath) == 0 {
|
||||
utils.Fatalf("must supply path to genesis JSON file")
|
||||
}
|
||||
|
||||
stack := makeFullNode(ctx)
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack)
|
||||
|
||||
genesisFile, err := os.Open(genesisPath)
|
||||
if err != nil {
|
||||
utils.Fatalf("failed to read genesis file: %v", err)
|
||||
}
|
||||
|
||||
block, err := core.WriteGenesisBlock(chaindb, genesisFile)
|
||||
if err != nil {
|
||||
utils.Fatalf("failed to write genesis block: %v", err)
|
||||
}
|
||||
glog.V(logger.Info).Infof("successfully wrote genesis block and/or chain rule set: %x", block.Hash())
|
||||
return nil
|
||||
}
|
||||
|
||||
func importChain(ctx *cli.Context) error {
|
||||
if len(ctx.Args()) != 1 {
|
||||
utils.Fatalf("This command requires an argument.")
|
||||
|
||||
@@ -83,75 +83,28 @@ var daoGenesisForkBlock = big.NewInt(314)
|
||||
// TestDAOForkBlockNewChain tests that the DAO hard-fork number and the nodes support/opposition is correctly
|
||||
// set in the database after various initialization procedures and invocations.
|
||||
func TestDAOForkBlockNewChain(t *testing.T) {
|
||||
for _, arg := range []struct {
|
||||
for i, arg := range []struct {
|
||||
testnet bool
|
||||
genesis string
|
||||
votes [][2]bool
|
||||
expectBlock *big.Int
|
||||
expectVote bool
|
||||
}{
|
||||
// Test DAO Default Mainnet
|
||||
{false, "", [][2]bool{{false, false}}, params.MainNetDAOForkBlock, true},
|
||||
// test DAO Support Mainnet
|
||||
{false, "", [][2]bool{{true, false}}, params.MainNetDAOForkBlock, true},
|
||||
// test DAO Oppose Mainnet
|
||||
{false, "", [][2]bool{{false, true}}, params.MainNetDAOForkBlock, false},
|
||||
// test DAO Switch To Support Mainnet
|
||||
{false, "", [][2]bool{{false, true}, {true, false}}, params.MainNetDAOForkBlock, true},
|
||||
// test DAO Switch To Oppose Mainnet
|
||||
{false, "", [][2]bool{{true, false}, {false, true}}, params.MainNetDAOForkBlock, false},
|
||||
{false, "", params.MainNetDAOForkBlock, true},
|
||||
// test DAO Default Testnet
|
||||
{true, "", [][2]bool{{false, false}}, params.TestNetDAOForkBlock, true},
|
||||
// test DAO Support Testnet
|
||||
{true, "", [][2]bool{{true, false}}, params.TestNetDAOForkBlock, true},
|
||||
// test DAO Oppose Testnet
|
||||
{true, "", [][2]bool{{false, true}}, params.TestNetDAOForkBlock, false},
|
||||
// test DAO Switch To Support Testnet
|
||||
{true, "", [][2]bool{{false, true}, {true, false}}, params.TestNetDAOForkBlock, true},
|
||||
// test DAO Switch To Oppose Testnet
|
||||
{true, "", [][2]bool{{true, false}, {false, true}}, params.TestNetDAOForkBlock, false},
|
||||
{true, "", params.TestNetDAOForkBlock, true},
|
||||
// test DAO Init Old Privnet
|
||||
{false, daoOldGenesis, [][2]bool{}, nil, false},
|
||||
// test DAO Default Old Privnet
|
||||
{false, daoOldGenesis, [][2]bool{{false, false}}, nil, false},
|
||||
// test DAO Support Old Privnet
|
||||
{false, daoOldGenesis, [][2]bool{{true, false}}, nil, true},
|
||||
// test DAO Oppose Old Privnet
|
||||
{false, daoOldGenesis, [][2]bool{{false, true}}, nil, false},
|
||||
// test DAO Switch To Support Old Privnet
|
||||
{false, daoOldGenesis, [][2]bool{{false, true}, {true, false}}, nil, true},
|
||||
// test DAO Switch To Oppose Old Privnet
|
||||
{false, daoOldGenesis, [][2]bool{{true, false}, {false, true}}, nil, false},
|
||||
// test DAO Init No Fork Privnet
|
||||
{false, daoNoForkGenesis, [][2]bool{}, daoGenesisForkBlock, false},
|
||||
{false, daoOldGenesis, nil, false},
|
||||
// test DAO Default No Fork Privnet
|
||||
{false, daoNoForkGenesis, [][2]bool{{false, false}}, daoGenesisForkBlock, false},
|
||||
// test DAO Support No Fork Privnet
|
||||
{false, daoNoForkGenesis, [][2]bool{{true, false}}, daoGenesisForkBlock, true},
|
||||
// test DAO Oppose No Fork Privnet
|
||||
{false, daoNoForkGenesis, [][2]bool{{false, true}}, daoGenesisForkBlock, false},
|
||||
// test DAO Switch To Support No Fork Privnet
|
||||
{false, daoNoForkGenesis, [][2]bool{{false, true}, {true, false}}, daoGenesisForkBlock, true},
|
||||
// test DAO Switch To Oppose No Fork Privnet
|
||||
{false, daoNoForkGenesis, [][2]bool{{true, false}, {false, true}}, daoGenesisForkBlock, false},
|
||||
// test DAO Init Pro Fork Privnet
|
||||
{false, daoProForkGenesis, [][2]bool{}, daoGenesisForkBlock, true},
|
||||
{false, daoNoForkGenesis, daoGenesisForkBlock, false},
|
||||
// test DAO Default Pro Fork Privnet
|
||||
{false, daoProForkGenesis, [][2]bool{{false, false}}, daoGenesisForkBlock, true},
|
||||
// test DAO Support Pro Fork Privnet
|
||||
{false, daoProForkGenesis, [][2]bool{{true, false}}, daoGenesisForkBlock, true},
|
||||
// test DAO Oppose Pro Fork Privnet
|
||||
{false, daoProForkGenesis, [][2]bool{{false, true}}, daoGenesisForkBlock, false},
|
||||
// test DAO Switch To Support Pro Fork Privnet
|
||||
{false, daoProForkGenesis, [][2]bool{{false, true}, {true, false}}, daoGenesisForkBlock, true},
|
||||
// test DAO Switch To Oppose Pro Fork Privnet
|
||||
{false, daoProForkGenesis, [][2]bool{{true, false}, {false, true}}, daoGenesisForkBlock, false},
|
||||
{false, daoProForkGenesis, daoGenesisForkBlock, true},
|
||||
} {
|
||||
testDAOForkBlockNewChain(t, arg.testnet, arg.genesis, arg.votes, arg.expectBlock, arg.expectVote)
|
||||
testDAOForkBlockNewChain(t, i, arg.testnet, arg.genesis, arg.expectBlock, arg.expectVote)
|
||||
}
|
||||
}
|
||||
|
||||
func testDAOForkBlockNewChain(t *testing.T, testnet bool, genesis string, votes [][2]bool, expectBlock *big.Int, expectVote bool) {
|
||||
func testDAOForkBlockNewChain(t *testing.T, test int, testnet bool, genesis string, expectBlock *big.Int, expectVote bool) {
|
||||
// Create a temporary data directory to use and inspect later
|
||||
datadir := tmpdir(t)
|
||||
defer os.RemoveAll(datadir)
|
||||
@@ -160,21 +113,15 @@ func testDAOForkBlockNewChain(t *testing.T, testnet bool, genesis string, votes
|
||||
if genesis != "" {
|
||||
json := filepath.Join(datadir, "genesis.json")
|
||||
if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil {
|
||||
t.Fatalf("failed to write genesis file: %v", err)
|
||||
t.Fatalf("test %d: failed to write genesis file: %v", test, err)
|
||||
}
|
||||
runGeth(t, "--datadir", datadir, "init", json).cmd.Wait()
|
||||
}
|
||||
for _, vote := range votes {
|
||||
} else {
|
||||
// Force chain initialization
|
||||
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir}
|
||||
if testnet {
|
||||
args = append(args, "--testnet")
|
||||
}
|
||||
if vote[0] {
|
||||
args = append(args, "--support-dao-fork")
|
||||
}
|
||||
if vote[1] {
|
||||
args = append(args, "--oppose-dao-fork")
|
||||
}
|
||||
geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...)
|
||||
geth.cmd.Wait()
|
||||
}
|
||||
@@ -185,7 +132,7 @@ func testDAOForkBlockNewChain(t *testing.T, testnet bool, genesis string, votes
|
||||
}
|
||||
db, err := ethdb.NewLDBDatabase(path, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open test database: %v", err)
|
||||
t.Fatalf("test %d: failed to open test database: %v", test, err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
@@ -198,20 +145,20 @@ func testDAOForkBlockNewChain(t *testing.T, testnet bool, genesis string, votes
|
||||
}
|
||||
config, err := core.GetChainConfig(db, genesisHash)
|
||||
if err != nil {
|
||||
t.Errorf("failed to retrieve chain config: %v", err)
|
||||
t.Errorf("test %d: failed to retrieve chain config: %v", test, err)
|
||||
return // we want to return here, the other checks can't make it past this point (nil panic).
|
||||
}
|
||||
// Validate the DAO hard-fork block number against the expected value
|
||||
if config.DAOForkBlock == nil {
|
||||
if expectBlock != nil {
|
||||
t.Errorf("dao hard-fork block mismatch: have nil, want %v", expectBlock)
|
||||
t.Errorf("test %d: dao hard-fork block mismatch: have nil, want %v", test, expectBlock)
|
||||
}
|
||||
} else if expectBlock == nil {
|
||||
t.Errorf("dao hard-fork block mismatch: have %v, want nil", config.DAOForkBlock)
|
||||
t.Errorf("test %d: dao hard-fork block mismatch: have %v, want nil", test, config.DAOForkBlock)
|
||||
} else if config.DAOForkBlock.Cmp(expectBlock) != 0 {
|
||||
t.Errorf("dao hard-fork block mismatch: have %v, want %v", config.DAOForkBlock, expectBlock)
|
||||
t.Errorf("test %d: dao hard-fork block mismatch: have %v, want %v", test, config.DAOForkBlock, expectBlock)
|
||||
}
|
||||
if config.DAOForkSupport != expectVote {
|
||||
t.Errorf("dao hard-fork support mismatch: have %v, want %v", config.DAOForkSupport, expectVote)
|
||||
t.Errorf("test %d: dao hard-fork support mismatch: have %v, want %v", test, config.DAOForkSupport, expectVote)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 Geth 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 geth.main, just modified to handle the function arg passing
|
||||
if err := app.Run(strings.Split("geth "+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 Geth 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")
|
||||
}
|
||||
}()
|
||||
}
|
||||
146
cmd/geth/main.go
146
cmd/geth/main.go
@@ -20,20 +20,15 @@ package main
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/ethash"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/console"
|
||||
"github.com/ethereum/go-ethereum/contracts/release"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/internal/debug"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
@@ -64,59 +59,26 @@ func init() {
|
||||
app.HideVersion = true // we have a command to print the version
|
||||
app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
|
||||
app.Commands = []cli.Command{
|
||||
// See chaincmd.go:
|
||||
initCommand,
|
||||
importCommand,
|
||||
exportCommand,
|
||||
upgradedbCommand,
|
||||
removedbCommand,
|
||||
dumpCommand,
|
||||
// See monitorcmd.go:
|
||||
monitorCommand,
|
||||
// See accountcmd.go:
|
||||
accountCommand,
|
||||
walletCommand,
|
||||
// See consolecmd.go:
|
||||
consoleCommand,
|
||||
attachCommand,
|
||||
javascriptCommand,
|
||||
{
|
||||
Action: makedag,
|
||||
Name: "makedag",
|
||||
Usage: "Generate ethash DAG (for testing)",
|
||||
ArgsUsage: "<blockNum> <outputDir>",
|
||||
Category: "MISCELLANEOUS COMMANDS",
|
||||
Description: `
|
||||
The makedag command generates an ethash DAG in /tmp/dag.
|
||||
|
||||
This command exists to support the system testing project.
|
||||
Regular users do not need to execute it.
|
||||
`,
|
||||
},
|
||||
{
|
||||
Action: version,
|
||||
Name: "version",
|
||||
Usage: "Print version numbers",
|
||||
ArgsUsage: " ",
|
||||
Category: "MISCELLANEOUS COMMANDS",
|
||||
Description: `
|
||||
The output of this command is supposed to be machine-readable.
|
||||
`,
|
||||
},
|
||||
{
|
||||
Action: initGenesis,
|
||||
Name: "init",
|
||||
Usage: "Bootstrap and initialize a new genesis block",
|
||||
ArgsUsage: "<genesisPath>",
|
||||
Category: "BLOCKCHAIN COMMANDS",
|
||||
Description: `
|
||||
The init command initializes a new genesis block and definition for the network.
|
||||
This is a destructive action and changes the network in which you will be
|
||||
participating.
|
||||
`,
|
||||
},
|
||||
{
|
||||
Action: license,
|
||||
Name: "license",
|
||||
Usage: "Display license information",
|
||||
ArgsUsage: " ",
|
||||
Category: "MISCELLANEOUS COMMANDS",
|
||||
},
|
||||
// See misccmd.go:
|
||||
makedagCommand,
|
||||
versionCommand,
|
||||
licenseCommand,
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
@@ -126,7 +88,6 @@ participating.
|
||||
utils.BootnodesFlag,
|
||||
utils.DataDirFlag,
|
||||
utils.KeyStoreDirFlag,
|
||||
utils.OlympicFlag,
|
||||
utils.FastSyncFlag,
|
||||
utils.LightModeFlag,
|
||||
utils.LightServFlag,
|
||||
@@ -140,8 +101,6 @@ participating.
|
||||
utils.MaxPendingPeersFlag,
|
||||
utils.EtherbaseFlag,
|
||||
utils.GasPriceFlag,
|
||||
utils.SupportDAOFork,
|
||||
utils.OpposeDAOFork,
|
||||
utils.MinerThreadsFlag,
|
||||
utils.MiningEnabledFlag,
|
||||
utils.AutoDAGFlag,
|
||||
@@ -208,7 +167,6 @@ participating.
|
||||
}
|
||||
|
||||
app.After = func(ctx *cli.Context) error {
|
||||
logger.Flush()
|
||||
debug.Exit()
|
||||
console.Stdin.Close() // Resets terminal mode.
|
||||
return nil
|
||||
@@ -232,30 +190,6 @@ func geth(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// initGenesis will initialise the given JSON format genesis file and writes it as
|
||||
// the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
|
||||
func initGenesis(ctx *cli.Context) error {
|
||||
genesisPath := ctx.Args().First()
|
||||
if len(genesisPath) == 0 {
|
||||
utils.Fatalf("must supply path to genesis JSON file")
|
||||
}
|
||||
|
||||
stack := makeFullNode(ctx)
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack)
|
||||
|
||||
genesisFile, err := os.Open(genesisPath)
|
||||
if err != nil {
|
||||
utils.Fatalf("failed to read genesis file: %v", err)
|
||||
}
|
||||
|
||||
block, err := core.WriteGenesisBlock(chaindb, genesisFile)
|
||||
if err != nil {
|
||||
utils.Fatalf("failed to write genesis block: %v", err)
|
||||
}
|
||||
glog.V(logger.Info).Infof("successfully wrote genesis block and/or chain rule set: %x", block.Hash())
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeFullNode(ctx *cli.Context) *node.Node {
|
||||
// Create the default extradata and construct the base node
|
||||
var clientInfo = struct {
|
||||
@@ -330,65 +264,3 @@ func startNode(ctx *cli.Context, stack *node.Node) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makedag(ctx *cli.Context) error {
|
||||
args := ctx.Args()
|
||||
wrongArgs := func() {
|
||||
utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`)
|
||||
}
|
||||
switch {
|
||||
case len(args) == 2:
|
||||
blockNum, err := strconv.ParseUint(args[0], 0, 64)
|
||||
dir := args[1]
|
||||
if err != nil {
|
||||
wrongArgs()
|
||||
} else {
|
||||
dir = filepath.Clean(dir)
|
||||
// seems to require a trailing slash
|
||||
if !strings.HasSuffix(dir, "/") {
|
||||
dir = dir + "/"
|
||||
}
|
||||
_, err = ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
utils.Fatalf("Can't find dir")
|
||||
}
|
||||
fmt.Println("making DAG, this could take awhile...")
|
||||
ethash.MakeDAG(blockNum, dir)
|
||||
}
|
||||
default:
|
||||
wrongArgs()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func version(ctx *cli.Context) error {
|
||||
fmt.Println(strings.Title(clientIdentifier))
|
||||
fmt.Println("Version:", params.Version)
|
||||
if gitCommit != "" {
|
||||
fmt.Println("Git Commit:", gitCommit)
|
||||
}
|
||||
fmt.Println("Protocol Versions:", eth.ProtocolVersions)
|
||||
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 license(_ *cli.Context) error {
|
||||
fmt.Println(`Geth 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.
|
||||
|
||||
Geth 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 geth. If not, see <http://www.gnu.org/licenses/>.
|
||||
`)
|
||||
return nil
|
||||
}
|
||||
|
||||
128
cmd/geth/misccmd.go
Normal file
128
cmd/geth/misccmd.go
Normal file
@@ -0,0 +1,128 @@
|
||||
// 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/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/ethash"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
makedagCommand = cli.Command{
|
||||
Action: makedag,
|
||||
Name: "makedag",
|
||||
Usage: "Generate ethash DAG (for testing)",
|
||||
ArgsUsage: "<blockNum> <outputDir>",
|
||||
Category: "MISCELLANEOUS COMMANDS",
|
||||
Description: `
|
||||
The makedag command generates an ethash DAG in /tmp/dag.
|
||||
|
||||
This command exists to support the system testing project.
|
||||
Regular users do not need to execute it.
|
||||
`,
|
||||
}
|
||||
versionCommand = cli.Command{
|
||||
Action: version,
|
||||
Name: "version",
|
||||
Usage: "Print version numbers",
|
||||
ArgsUsage: " ",
|
||||
Category: "MISCELLANEOUS COMMANDS",
|
||||
Description: `
|
||||
The output of this command is supposed to be machine-readable.
|
||||
`,
|
||||
}
|
||||
licenseCommand = cli.Command{
|
||||
Action: license,
|
||||
Name: "license",
|
||||
Usage: "Display license information",
|
||||
ArgsUsage: " ",
|
||||
Category: "MISCELLANEOUS COMMANDS",
|
||||
}
|
||||
)
|
||||
|
||||
func makedag(ctx *cli.Context) error {
|
||||
args := ctx.Args()
|
||||
wrongArgs := func() {
|
||||
utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`)
|
||||
}
|
||||
switch {
|
||||
case len(args) == 2:
|
||||
blockNum, err := strconv.ParseUint(args[0], 0, 64)
|
||||
dir := args[1]
|
||||
if err != nil {
|
||||
wrongArgs()
|
||||
} else {
|
||||
dir = filepath.Clean(dir)
|
||||
// seems to require a trailing slash
|
||||
if !strings.HasSuffix(dir, "/") {
|
||||
dir = dir + "/"
|
||||
}
|
||||
_, err = ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
utils.Fatalf("Can't find dir")
|
||||
}
|
||||
fmt.Println("making DAG, this could take awhile...")
|
||||
ethash.MakeDAG(blockNum, dir)
|
||||
}
|
||||
default:
|
||||
wrongArgs()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func version(ctx *cli.Context) error {
|
||||
fmt.Println(strings.Title(clientIdentifier))
|
||||
fmt.Println("Version:", params.Version)
|
||||
if gitCommit != "" {
|
||||
fmt.Println("Git Commit:", gitCommit)
|
||||
}
|
||||
fmt.Println("Protocol Versions:", eth.ProtocolVersions)
|
||||
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 license(_ *cli.Context) error {
|
||||
fmt.Println(`Geth 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.
|
||||
|
||||
Geth 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 geth. If not, see <http://www.gnu.org/licenses/>.
|
||||
`)
|
||||
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.
|
||||
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] {
|
||||
var found bool
|
||||
metrics, found = metrics[part].(map[string]interface{})
|
||||
if !found {
|
||||
return 0
|
||||
|
||||
@@ -67,7 +67,6 @@ var AppHelpFlagGroups = []flagGroup{
|
||||
utils.DataDirFlag,
|
||||
utils.KeyStoreDirFlag,
|
||||
utils.NetworkIdFlag,
|
||||
utils.OlympicFlag,
|
||||
utils.TestNetFlag,
|
||||
utils.DevModeFlag,
|
||||
utils.IdentityFlag,
|
||||
|
||||
@@ -19,22 +19,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Println("Usage: bzzhash <file name>")
|
||||
os.Exit(0)
|
||||
func hash(ctx *cli.Context) {
|
||||
args := ctx.Args()
|
||||
if len(args) < 1 {
|
||||
log.Fatal("Usage: swarm hash <file name>")
|
||||
}
|
||||
f, err := os.Open(os.Args[1])
|
||||
f, err := os.Open(args[0])
|
||||
if err != nil {
|
||||
fmt.Println("Error opening file " + os.Args[1])
|
||||
fmt.Println("Error opening file " + args[1])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -42,7 +41,7 @@ func main() {
|
||||
chunker := storage.NewTreeChunker(storage.NewChunkerParams())
|
||||
key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
log.Fatalf("%v\n", err)
|
||||
} else {
|
||||
fmt.Printf("%v\n", key)
|
||||
}
|
||||
@@ -43,11 +43,21 @@ import (
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
const clientIdentifier = "bzzd"
|
||||
const (
|
||||
clientIdentifier = "swarm"
|
||||
versionString = "0.2"
|
||||
)
|
||||
|
||||
var (
|
||||
gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
|
||||
app = utils.NewApp(gitCommit, "Ethereum Swarm server daemon")
|
||||
gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
|
||||
app = utils.NewApp(gitCommit, "Ethereum Swarm")
|
||||
testbetBootNodes = []string{
|
||||
"enode://ec8ae764f7cb0417bdfb009b9d0f18ab3818a3a4e8e7c67dd5f18971a93510a2e6f43cd0b69a27e439a9629457ea804104f37c85e41eed057d3faabbf7744cdf@13.74.157.139:30429",
|
||||
"enode://c2e1fceb3bf3be19dff71eec6cccf19f2dbf7567ee017d130240c670be8594bc9163353ca55dd8df7a4f161dd94b36d0615c17418b5a3cdcbb4e9d99dfa4de37@13.74.157.139:30430",
|
||||
"enode://fe29b82319b734ce1ec68b84657d57145fee237387e63273989d354486731e59f78858e452ef800a020559da22dcca759536e6aa5517c53930d29ce0b1029286@13.74.157.139:30431",
|
||||
"enode://1d7187e7bde45cf0bee489ce9852dd6d1a0d9aa67a33a6b8e6db8a4fbc6fcfa6f0f1a5419343671521b863b187d1c73bad3603bae66421d157ffef357669ddb8@13.74.157.139:30432",
|
||||
"enode://0e4cba800f7b1ee73673afa6a4acead4018f0149d2e3216be3f133318fd165b324cd71b81fbe1e80deac8dbf56e57a49db7be67f8b9bc81bd2b7ee496434fb5d@13.74.157.139:30433",
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -65,30 +75,49 @@ var (
|
||||
}
|
||||
SwarmNetworkIdFlag = cli.IntFlag{
|
||||
Name: "bzznetworkid",
|
||||
Usage: "Network identifier (integer, default 322=swarm testnet)",
|
||||
Usage: "Network identifier (integer, default 3=swarm testnet)",
|
||||
Value: network.NetworkId,
|
||||
}
|
||||
SwarmConfigPathFlag = cli.StringFlag{
|
||||
Name: "bzzconfig",
|
||||
Usage: "Swarm config file path (datadir/bzz)",
|
||||
}
|
||||
SwarmSwapEnabled = cli.BoolFlag{
|
||||
SwarmSwapEnabledFlag = cli.BoolFlag{
|
||||
Name: "swap",
|
||||
Usage: "Swarm SWAP enabled (default false)",
|
||||
}
|
||||
SwarmSyncEnabled = cli.BoolTFlag{
|
||||
SwarmSyncEnabledFlag = cli.BoolTFlag{
|
||||
Name: "sync",
|
||||
Usage: "Swarm Syncing enabled (default true)",
|
||||
}
|
||||
EthAPI = cli.StringFlag{
|
||||
EthAPIFlag = cli.StringFlag{
|
||||
Name: "ethapi",
|
||||
Usage: "URL of the Ethereum API provider",
|
||||
Value: node.DefaultIPCEndpoint("geth"),
|
||||
}
|
||||
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() {
|
||||
// Override flag defaults so bzzd can run alongside geth.
|
||||
utils.ListenPortFlag.Value = 30399
|
||||
@@ -96,8 +125,39 @@ func init() {
|
||||
utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3"
|
||||
|
||||
// Set up the cli app.
|
||||
app.Commands = nil
|
||||
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{
|
||||
utils.IdentityFlag,
|
||||
utils.DataDirFlag,
|
||||
@@ -115,14 +175,20 @@ func init() {
|
||||
utils.IPCApiFlag,
|
||||
utils.IPCPathFlag,
|
||||
// bzzd-specific flags
|
||||
EthAPI,
|
||||
CorsStringFlag,
|
||||
EthAPIFlag,
|
||||
SwarmConfigPathFlag,
|
||||
SwarmSwapEnabled,
|
||||
SwarmSyncEnabled,
|
||||
SwarmSwapEnabledFlag,
|
||||
SwarmSyncEnabledFlag,
|
||||
SwarmPortFlag,
|
||||
SwarmAccountFlag,
|
||||
SwarmNetworkIdFlag,
|
||||
ChequebookAddrFlag,
|
||||
// upload flags
|
||||
SwarmApiFlag,
|
||||
SwarmRecursiveUploadFlag,
|
||||
SwarmWantManifestFlag,
|
||||
SwarmUploadDefaultPath,
|
||||
}
|
||||
app.Flags = append(app.Flags, debug.Flags...)
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
@@ -142,17 +208,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 {
|
||||
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
|
||||
registerBzzService(ctx, stack)
|
||||
utils.StartNode(stack)
|
||||
|
||||
networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name)
|
||||
// Add bootnodes as initial peers.
|
||||
if ctx.GlobalIsSet(utils.BootnodesFlag.Name) {
|
||||
bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",")
|
||||
injectBootnodes(stack.Server(), bootnodes)
|
||||
} else {
|
||||
injectBootnodes(stack.Server(), defaultBootnodes)
|
||||
if networkId == 3 {
|
||||
injectBootnodes(stack.Server(), testbetBootNodes)
|
||||
}
|
||||
}
|
||||
|
||||
stack.Wait()
|
||||
@@ -175,22 +257,21 @@ func registerBzzService(ctx *cli.Context, stack *node.Node) {
|
||||
if len(bzzport) > 0 {
|
||||
bzzconfig.Port = bzzport
|
||||
}
|
||||
swapEnabled := ctx.GlobalBool(SwarmSwapEnabled.Name)
|
||||
syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabled.Name)
|
||||
swapEnabled := ctx.GlobalBool(SwarmSwapEnabledFlag.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) {
|
||||
var client *ethclient.Client
|
||||
if ethapi == "" {
|
||||
err = fmt.Errorf("use ethapi flag to connect to a an eth client and talk to the blockchain")
|
||||
} else {
|
||||
if len(ethapi) > 0 {
|
||||
client, err = ethclient.Dial(ethapi)
|
||||
if err != nil {
|
||||
utils.Fatalf("Can't connect: %v", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
utils.Fatalf("Can't connect: %v", err)
|
||||
}
|
||||
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled)
|
||||
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled, cors)
|
||||
}
|
||||
if err := stack.Register(boot); err != nil {
|
||||
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
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
@@ -65,7 +67,6 @@ func Fatalf(format string, args ...interface{}) {
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
|
||||
logger.Flush()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -93,7 +94,7 @@ func StartNode(stack *node.Node) {
|
||||
|
||||
func FormatTransactionData(data string) []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 {
|
||||
d := common.FormatData(dataItem)
|
||||
ret = append(ret, d...)
|
||||
@@ -133,7 +134,15 @@ func ImportChain(chain *core.BlockChain, fn string) error {
|
||||
return err
|
||||
}
|
||||
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.
|
||||
blocks := make(types.Blocks, importBatchSize)
|
||||
@@ -195,10 +204,18 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
glog.Infoln("Exported blockchain to ", fn)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -210,7 +227,14 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
glog.Infoln("Exported blockchain to ", fn)
|
||||
|
||||
@@ -23,8 +23,6 @@ import (
|
||||
"os/user"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// 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.
|
||||
// e.g. ~/.ethereum -> /home/username/.ethereum
|
||||
type DirectoryFlag struct {
|
||||
cli.GenericFlag
|
||||
Name string
|
||||
Value DirectoryString
|
||||
Usage string
|
||||
@@ -54,15 +51,10 @@ type DirectoryFlag struct {
|
||||
}
|
||||
|
||||
func (self DirectoryFlag) String() string {
|
||||
var fmtString string
|
||||
fmtString = "%s %v\t%v"
|
||||
|
||||
fmtString := "%s %v\t%v"
|
||||
if len(self.Value.Value) > 0 {
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -122,7 +114,7 @@ func withEnvHint(envVar, str string) string {
|
||||
return str + envText
|
||||
}
|
||||
|
||||
func (self DirectoryFlag) getName() string {
|
||||
func (self DirectoryFlag) GetName() string {
|
||||
return self.Name
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -116,16 +115,12 @@ var (
|
||||
}
|
||||
NetworkIdFlag = cli.IntFlag{
|
||||
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,
|
||||
}
|
||||
OlympicFlag = cli.BoolFlag{
|
||||
Name: "olympic",
|
||||
Usage: "Olympic network: pre-configured pre-release test network",
|
||||
}
|
||||
TestNetFlag = cli.BoolFlag{
|
||||
Name: "testnet",
|
||||
Usage: "Morden network: pre-configured test network with modified starting nonces (replay protection)",
|
||||
Usage: "Ropsten network: pre-configured test network",
|
||||
}
|
||||
DevModeFlag = cli.BoolFlag{
|
||||
Name: "dev",
|
||||
@@ -177,15 +172,6 @@ var (
|
||||
Usage: "Number of trie node generations to keep in memory",
|
||||
Value: int(state.MaxTrieCacheGen),
|
||||
}
|
||||
// Fork settings
|
||||
SupportDAOFork = cli.BoolFlag{
|
||||
Name: "support-dao-fork",
|
||||
Usage: "Updates the chain rules to support the DAO hard-fork",
|
||||
}
|
||||
OpposeDAOFork = cli.BoolFlag{
|
||||
Name: "oppose-dao-fork",
|
||||
Usage: "Updates the chain rules to oppose the DAO hard-fork",
|
||||
}
|
||||
// Miner settings
|
||||
MiningEnabledFlag = cli.BoolFlag{
|
||||
Name: "mine",
|
||||
@@ -494,17 +480,15 @@ func makeNodeUserIdent(ctx *cli.Context) string {
|
||||
// MakeBootstrapNodes creates a list of bootstrap nodes from the command line
|
||||
// flags, reverting to pre-configured ones if none have been specified.
|
||||
func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
||||
// Return pre-configured nodes if none were manually requested
|
||||
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||
return params.TestnetBootnodes
|
||||
}
|
||||
return params.MainnetBootnodes
|
||||
urls := params.MainnetBootnodes
|
||||
if ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||
urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
|
||||
} else if ctx.GlobalBool(TestNetFlag.Name) {
|
||||
urls = params.TestnetBootnodes
|
||||
}
|
||||
// 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)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||
@@ -518,14 +502,13 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
||||
// MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line
|
||||
// flags, reverting to pre-configured ones if none have been specified.
|
||||
func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
|
||||
// Return pre-configured nodes if none were manually requested
|
||||
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||
return params.DiscoveryV5Bootnodes
|
||||
urls := params.DiscoveryV5Bootnodes
|
||||
if ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||
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)
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||
@@ -724,7 +707,7 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
|
||||
// given node.
|
||||
func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||
// Avoid conflicting network flags
|
||||
networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag}
|
||||
networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag}
|
||||
for _, flag := range netFlags {
|
||||
if ctx.GlobalBool(flag.Name) {
|
||||
networks++
|
||||
@@ -762,12 +745,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||
|
||||
// Override any default configs in dev mode or the test net
|
||||
switch {
|
||||
case ctx.GlobalBool(OlympicFlag.Name):
|
||||
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
|
||||
ethConf.NetworkId = 1
|
||||
}
|
||||
ethConf.Genesis = core.OlympicGenesisBlock()
|
||||
|
||||
case ctx.GlobalBool(TestNetFlag.Name):
|
||||
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
|
||||
ethConf.NetworkId = 3
|
||||
@@ -775,7 +752,7 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
|
||||
ethConf.Genesis = core.DefaultTestnetGenesisBlock()
|
||||
|
||||
case ctx.GlobalBool(DevModeFlag.Name):
|
||||
ethConf.Genesis = core.OlympicGenesisBlock()
|
||||
ethConf.Genesis = core.DevGenesisBlock()
|
||||
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
|
||||
ethConf.GasPrice = new(big.Int)
|
||||
}
|
||||
@@ -832,16 +809,6 @@ func RegisterEthStatsService(stack *node.Node, url string) {
|
||||
|
||||
// SetupNetwork configures the system for either the main net or some test network.
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -901,13 +868,6 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainCon
|
||||
config.ChainId = params.MainNetChainID
|
||||
}
|
||||
}
|
||||
// Force override any existing configs if explicitly requested
|
||||
switch {
|
||||
case ctx.GlobalBool(SupportDAOFork.Name):
|
||||
config.DAOForkSupport = true
|
||||
case ctx.GlobalBool(OpposeDAOFork.Name):
|
||||
config.DAOForkSupport = false
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -939,12 +899,13 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
|
||||
var err error
|
||||
chainDb = MakeChainDatabase(ctx, stack)
|
||||
|
||||
if ctx.GlobalBool(OlympicFlag.Name) {
|
||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||
_, err := core.WriteTestNetGenesisBlock(chainDb)
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
chainConfig := MakeChainConfigFromDb(ctx, chainDb)
|
||||
|
||||
pow := pow.PoW(core.FakePow{})
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestMisc(t *testing.T) {
|
||||
c := []byte{1, 2, 3, 4}
|
||||
z := BitTest(a, 1)
|
||||
|
||||
if z != true {
|
||||
if !z {
|
||||
t.Error("Expected true got", z)
|
||||
}
|
||||
|
||||
@@ -79,11 +79,11 @@ func TestBigCopy(t *testing.T) {
|
||||
z := BigToBytes(c, 16)
|
||||
zbytes := []byte{232, 212, 165, 16, 0}
|
||||
|
||||
if bytes.Compare(y, ybytes) != 0 {
|
||||
if !bytes.Equal(y, ybytes) {
|
||||
t.Error("Got", ybytes)
|
||||
}
|
||||
|
||||
if bytes.Compare(z, zbytes) != 0 {
|
||||
if !bytes.Equal(z, zbytes) {
|
||||
t.Error("Got", zbytes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func Hex2BytesFixed(str string, flen int) []byte {
|
||||
return h
|
||||
} else {
|
||||
if len(h) > flen {
|
||||
return h[len(h)-flen : len(h)]
|
||||
return h[len(h)-flen:]
|
||||
} else {
|
||||
hh := make([]byte, flen)
|
||||
copy(hh[flen-len(h):flen], h[:])
|
||||
|
||||
@@ -181,7 +181,7 @@ func TestFromHex(t *testing.T) {
|
||||
input := "0x01"
|
||||
expected := []byte{1}
|
||||
result := FromHex(input)
|
||||
if bytes.Compare(expected, result) != 0 {
|
||||
if !bytes.Equal(expected, result) {
|
||||
t.Errorf("Expected % x got % x", expected, result)
|
||||
}
|
||||
}
|
||||
@@ -190,7 +190,7 @@ func TestFromHexOddLength(t *testing.T) {
|
||||
input := "0x1"
|
||||
expected := []byte{1}
|
||||
result := FromHex(input)
|
||||
if bytes.Compare(expected, result) != 0 {
|
||||
if !bytes.Equal(expected, result) {
|
||||
t.Errorf("Expected % x got % x", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -34,7 +32,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
versionRegexp = regexp.MustCompile("[0-9]+\\.[0-9]+\\.[0-9]+")
|
||||
versionRegexp = regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`)
|
||||
solcParams = []string{
|
||||
"--combined-json", "bin,abi,userdoc,devdoc",
|
||||
"--add-std", // include standard lib contracts
|
||||
@@ -96,27 +94,16 @@ func CompileSolidityString(solc, source string) (map[string]*Contract, error) {
|
||||
if solc == "" {
|
||||
solc = "solc"
|
||||
}
|
||||
// Write source to a temporary file. Compiling stdin used to be supported
|
||||
// but seems to produce an exception with solc 0.3.5.
|
||||
infile, err := ioutil.TempFile("", "geth-compile-solidity")
|
||||
if err != nil {
|
||||
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())
|
||||
args := append(solcParams, "--")
|
||||
cmd := exec.Command(solc, append(args, "-")...)
|
||||
cmd.Stdin = strings.NewReader(source)
|
||||
return runsolc(cmd, source)
|
||||
}
|
||||
|
||||
// CompileSolidity compiles all given Solidity source files.
|
||||
func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
|
||||
if len(sourcefiles) == 0 {
|
||||
return nil, errors.New("solc: no source ")
|
||||
return nil, errors.New("solc: no source files")
|
||||
}
|
||||
source, err := slurpFiles(sourcefiles)
|
||||
if err != nil {
|
||||
@@ -125,10 +112,13 @@ func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract,
|
||||
if solc == "" {
|
||||
solc = "solc"
|
||||
}
|
||||
|
||||
var stderr, stdout bytes.Buffer
|
||||
args := append(solcParams, "--")
|
||||
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.Stdout = &stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
@@ -27,8 +28,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
supportedSolcVersion = "0.3.5"
|
||||
testSource = `
|
||||
testSource = `
|
||||
contract test {
|
||||
/// @notice Will multiply ` + "`a`" + ` by 7.
|
||||
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":{}}}`
|
||||
)
|
||||
|
||||
func skipUnsupported(t *testing.T) {
|
||||
sol, err := SolidityVersion("")
|
||||
if err != nil {
|
||||
func skipWithoutSolc(t *testing.T) {
|
||||
if _, err := exec.LookPath("solc"); err != nil {
|
||||
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) {
|
||||
skipUnsupported(t)
|
||||
skipWithoutSolc(t)
|
||||
|
||||
contracts, err := CompileSolidityString("", testSource)
|
||||
if err != nil {
|
||||
t.Fatalf("error compiling source. result %v: %v", contracts, err)
|
||||
@@ -64,19 +59,20 @@ func TestCompiler(t *testing.T) {
|
||||
if !ok {
|
||||
t.Fatal("info for contract 'test' not present in result")
|
||||
}
|
||||
if c.Code != testCode {
|
||||
t.Errorf("wrong code: expected\n%s, got\n%s", testCode, c.Code)
|
||||
if c.Code == "" {
|
||||
t.Error("empty code")
|
||||
}
|
||||
if c.Info.Source != testSource {
|
||||
t.Error("wrong source")
|
||||
}
|
||||
if c.Info.CompilerVersion != supportedSolcVersion {
|
||||
t.Errorf("wrong version: expected %q, got %q", supportedSolcVersion, c.Info.CompilerVersion)
|
||||
if c.Info.CompilerVersion == "" {
|
||||
t.Error("empty version")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompileError(t *testing.T) {
|
||||
skipUnsupported(t)
|
||||
skipWithoutSolc(t)
|
||||
|
||||
contracts, err := CompileSolidityString("", testSource[4:])
|
||||
if err == nil {
|
||||
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.
|
||||
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
|
||||
// values rounded to three decimals.
|
||||
|
||||
@@ -169,12 +169,7 @@ func EncodeBig(bigint *big.Int) string {
|
||||
if nbits == 0 {
|
||||
return "0x0"
|
||||
}
|
||||
enc := make([]byte, 2, (nbits/8)*2+2)
|
||||
copy(enc, "0x")
|
||||
for i := len(bigint.Bits()) - 1; i >= 0; i-- {
|
||||
enc = strconv.AppendUint(enc, uint64(bigint.Bits()[i]), 16)
|
||||
}
|
||||
return string(enc)
|
||||
return fmt.Sprintf("0x%x", bigint)
|
||||
}
|
||||
|
||||
func has0xPrefix(input string) bool {
|
||||
|
||||
@@ -46,6 +46,7 @@ var (
|
||||
{referenceBig("1"), "0x1"},
|
||||
{referenceBig("ff"), "0xff"},
|
||||
{referenceBig("112233445566778899aabbccddeeff"), "0x112233445566778899aabbccddeeff"},
|
||||
{referenceBig("80a7f2c1bcc396c00"), "0x80a7f2c1bcc396c00"},
|
||||
}
|
||||
|
||||
encodeUint64Tests = []marshalTest{
|
||||
|
||||
@@ -109,13 +109,8 @@ func (b *Big) MarshalJSON() ([]byte, error) {
|
||||
if nbits == 0 {
|
||||
return jsonZero, nil
|
||||
}
|
||||
enc := make([]byte, 3, (nbits/8)*2+4)
|
||||
copy(enc, `"0x`)
|
||||
for i := len(bigint.Bits()) - 1; i >= 0; i-- {
|
||||
enc = strconv.AppendUint(enc, uint64(bigint.Bits()[i]), 16)
|
||||
}
|
||||
enc = append(enc, '"')
|
||||
return enc, nil
|
||||
enc := fmt.Sprintf(`"0x%x"`, bigint)
|
||||
return []byte(enc), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
@@ -237,7 +232,7 @@ func checkJSON(input []byte) (raw []byte, err error) {
|
||||
return nil, errNonString
|
||||
}
|
||||
if len(input) == 2 {
|
||||
return nil, ErrEmptyString
|
||||
return nil, nil // empty strings are allowed
|
||||
}
|
||||
if !bytesHave0xPrefix(input[1:]) {
|
||||
return nil, ErrMissingPrefix
|
||||
@@ -255,7 +250,7 @@ func checkNumberJSON(input []byte) (raw []byte, err error) {
|
||||
}
|
||||
input = input[1 : len(input)-1]
|
||||
if len(input) == 0 {
|
||||
return nil, ErrEmptyString
|
||||
return nil, nil // empty strings are allowed
|
||||
}
|
||||
if !bytesHave0xPrefix(input) {
|
||||
return nil, ErrMissingPrefix
|
||||
|
||||
@@ -60,13 +60,13 @@ var unmarshalBytesTests = []unmarshalTest{
|
||||
{input: "", wantErr: errNonString},
|
||||
{input: "null", wantErr: errNonString},
|
||||
{input: "10", wantErr: errNonString},
|
||||
{input: `""`, wantErr: ErrEmptyString},
|
||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||
{input: `"0x0"`, wantErr: ErrOddLength},
|
||||
{input: `"0xxx"`, wantErr: ErrSyntax},
|
||||
{input: `"0x01zz01"`, wantErr: ErrSyntax},
|
||||
|
||||
// valid encoding
|
||||
{input: `""`, want: referenceBytes("")},
|
||||
{input: `"0x"`, want: referenceBytes("")},
|
||||
{input: `"0x02"`, want: referenceBytes("02")},
|
||||
{input: `"0X02"`, want: referenceBytes("02")},
|
||||
@@ -125,7 +125,6 @@ var unmarshalBigTests = []unmarshalTest{
|
||||
{input: "", wantErr: errNonString},
|
||||
{input: "null", wantErr: errNonString},
|
||||
{input: "10", wantErr: errNonString},
|
||||
{input: `""`, wantErr: ErrEmptyString},
|
||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||
{input: `"0x"`, wantErr: ErrEmptyNumber},
|
||||
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
||||
@@ -133,6 +132,7 @@ var unmarshalBigTests = []unmarshalTest{
|
||||
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
||||
|
||||
// valid encoding
|
||||
{input: `""`, want: big.NewInt(0)},
|
||||
{input: `"0x0"`, want: big.NewInt(0)},
|
||||
{input: `"0x2"`, want: big.NewInt(0x2)},
|
||||
{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
|
||||
@@ -198,7 +198,6 @@ var unmarshalUint64Tests = []unmarshalTest{
|
||||
{input: "", wantErr: errNonString},
|
||||
{input: "null", wantErr: errNonString},
|
||||
{input: "10", wantErr: errNonString},
|
||||
{input: `""`, wantErr: ErrEmptyString},
|
||||
{input: `"0"`, wantErr: ErrMissingPrefix},
|
||||
{input: `"0x"`, wantErr: ErrEmptyNumber},
|
||||
{input: `"0x01"`, wantErr: ErrLeadingZero},
|
||||
@@ -207,6 +206,7 @@ var unmarshalUint64Tests = []unmarshalTest{
|
||||
{input: `"0x1zz01"`, wantErr: ErrSyntax},
|
||||
|
||||
// valid encoding
|
||||
{input: `""`, want: uint64(0)},
|
||||
{input: `"0x0"`, want: uint64(0)},
|
||||
{input: `"0x2"`, want: uint64(0x2)},
|
||||
{input: `"0x2F2"`, want: uint64(0x2f2)},
|
||||
|
||||
@@ -41,24 +41,24 @@ func TestSum(t *testing.T) {
|
||||
|
||||
func TestDist(t *testing.T) {
|
||||
var vectors = []Vector{
|
||||
Vector{big.NewInt(1000), big.NewInt(1234)},
|
||||
Vector{big.NewInt(500), big.NewInt(10023)},
|
||||
Vector{big.NewInt(1034), big.NewInt(1987)},
|
||||
Vector{big.NewInt(1034), big.NewInt(1987)},
|
||||
Vector{big.NewInt(8983), big.NewInt(1977)},
|
||||
Vector{big.NewInt(98382), big.NewInt(1887)},
|
||||
Vector{big.NewInt(12398), big.NewInt(1287)},
|
||||
Vector{big.NewInt(12398), big.NewInt(1487)},
|
||||
Vector{big.NewInt(12398), big.NewInt(1987)},
|
||||
Vector{big.NewInt(12398), big.NewInt(128)},
|
||||
Vector{big.NewInt(12398), big.NewInt(1987)},
|
||||
Vector{big.NewInt(1398), big.NewInt(187)},
|
||||
Vector{big.NewInt(12328), big.NewInt(1927)},
|
||||
Vector{big.NewInt(12398), big.NewInt(1987)},
|
||||
Vector{big.NewInt(22398), big.NewInt(1287)},
|
||||
Vector{big.NewInt(1370), big.NewInt(1981)},
|
||||
Vector{big.NewInt(12398), big.NewInt(1957)},
|
||||
Vector{big.NewInt(42198), big.NewInt(1987)},
|
||||
{big.NewInt(1000), big.NewInt(1234)},
|
||||
{big.NewInt(500), big.NewInt(10023)},
|
||||
{big.NewInt(1034), big.NewInt(1987)},
|
||||
{big.NewInt(1034), big.NewInt(1987)},
|
||||
{big.NewInt(8983), big.NewInt(1977)},
|
||||
{big.NewInt(98382), big.NewInt(1887)},
|
||||
{big.NewInt(12398), big.NewInt(1287)},
|
||||
{big.NewInt(12398), big.NewInt(1487)},
|
||||
{big.NewInt(12398), big.NewInt(1987)},
|
||||
{big.NewInt(12398), big.NewInt(128)},
|
||||
{big.NewInt(12398), big.NewInt(1987)},
|
||||
{big.NewInt(1398), big.NewInt(187)},
|
||||
{big.NewInt(12328), big.NewInt(1927)},
|
||||
{big.NewInt(12398), big.NewInt(1987)},
|
||||
{big.NewInt(22398), big.NewInt(1287)},
|
||||
{big.NewInt(1370), big.NewInt(1981)},
|
||||
{big.NewInt(12398), big.NewInt(1957)},
|
||||
{big.NewInt(42198), big.NewInt(1987)},
|
||||
}
|
||||
|
||||
VectorsBy(GasSort).Sort(vectors)
|
||||
|
||||
@@ -76,9 +76,9 @@ func compressChunk(dat []byte) (ret []byte, n int) {
|
||||
}
|
||||
return []byte{token, byte(j + 2)}, j
|
||||
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
|
||||
} 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
|
||||
}
|
||||
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
|
||||
// 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.
|
||||
func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
||||
var (
|
||||
@@ -75,7 +75,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
|
||||
default:
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
// 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
|
||||
// the RPC call.
|
||||
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
|
||||
// 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.
|
||||
func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) {
|
||||
var (
|
||||
@@ -270,18 +270,15 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
|
||||
} else {
|
||||
resultVal, err := JSON.Call("parse", string(result))
|
||||
if err != nil {
|
||||
resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object()
|
||||
setError(resp, -32603, err.Error())
|
||||
} else {
|
||||
resp.Set("result", resultVal)
|
||||
}
|
||||
}
|
||||
case rpc.Error:
|
||||
resp.Set("error", map[string]interface{}{
|
||||
"code": err.ErrorCode(),
|
||||
"message": err.Error(),
|
||||
})
|
||||
setError(resp, err.ErrorCode(), err.Error())
|
||||
default:
|
||||
resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object()
|
||||
setError(resp, -32603, err.Error())
|
||||
}
|
||||
resps.Call("push", resp)
|
||||
}
|
||||
@@ -300,12 +297,8 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
|
||||
return response
|
||||
}
|
||||
|
||||
func newErrorResponse(call otto.FunctionCall, code int, msg string, id interface{}) otto.Value {
|
||||
// Bundle the error into a JSON RPC call response
|
||||
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
|
||||
func setError(resp *otto.Object, code int, msg string) {
|
||||
resp.Set("error", map[string]interface{}{"code": code, "message": msg})
|
||||
}
|
||||
|
||||
// throwJSException panics on an otto.Value. The Otto VM will recover from the
|
||||
|
||||
@@ -36,9 +36,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
passwordRegexp = regexp.MustCompile("personal.[nus]")
|
||||
onlyWhitespace = regexp.MustCompile("^\\s*$")
|
||||
exit = regexp.MustCompile("^\\s*exit\\s*;*\\s*$")
|
||||
passwordRegexp = regexp.MustCompile(`personal.[nus]`)
|
||||
onlyWhitespace = regexp.MustCompile(`^\s*$`)
|
||||
exit = regexp.MustCompile(`^\s*exit\s*;*\s*$`)
|
||||
)
|
||||
|
||||
// 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
|
||||
// E.g. in case of nested lines eth.getBalance(eth.coinb<tab><tab>
|
||||
start := 0
|
||||
for start = pos - 1; start > 0; start-- {
|
||||
start := pos - 1
|
||||
for ; start > 0; start-- {
|
||||
// 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') {
|
||||
continue
|
||||
@@ -275,10 +275,7 @@ func (c *Console) Evaluate(statement string) error {
|
||||
fmt.Fprintf(c.printer, "[native] error: %v\n", r)
|
||||
}
|
||||
}()
|
||||
if err := c.jsre.Evaluate(statement, c.printer); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return c.jsre.Evaluate(statement, c.printer)
|
||||
}
|
||||
|
||||
// Interactive starts an interactive user session, where input is propted from
|
||||
|
||||
@@ -44,7 +44,7 @@ type UserPrompter interface {
|
||||
PromptConfirm(prompt string) (bool, error)
|
||||
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
// the user to scoll back to.
|
||||
// the user to scroll back to.
|
||||
func (p *terminalPrompter) SetHistory(history []string) {
|
||||
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)
|
||||
}
|
||||
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 {
|
||||
var sig []byte
|
||||
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
|
||||
// note this is called even if issueing cheque fails
|
||||
// note this is called even if issuing cheque fails
|
||||
// so we reattempt depositing
|
||||
if self.threshold != nil {
|
||||
if self.balance.Cmp(self.threshold) < 0 {
|
||||
|
||||
@@ -73,8 +73,8 @@ func TestIssueAndReceive(t *testing.T) {
|
||||
}
|
||||
chbook.sent[addr1] = new(big.Int).SetUint64(42)
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func TestIssueAndReceive(t *testing.T) {
|
||||
t.Fatalf("expected: %v, got %v", "0", chbook.Balance())
|
||||
}
|
||||
|
||||
ch, err = chbook.Issue(addr1, amount)
|
||||
ch, err := chbook.Issue(addr1, amount)
|
||||
if err != nil {
|
||||
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())
|
||||
}
|
||||
|
||||
ch, err := chbook.Issue(addr1, common.Big1)
|
||||
if err != nil {
|
||||
var ch *Cheque
|
||||
if ch, err = chbook.Issue(addr1, common.Big1); err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
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")
|
||||
contr1, err := deploy(key1, common.Big2, backend)
|
||||
contr1, _ := deploy(key1, common.Big2, backend)
|
||||
chbook1, err := NewChequebook(path1, contr1, key1, backend)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
@@ -223,7 +223,8 @@ func TestVerifyErrors(t *testing.T) {
|
||||
func TestDeposit(t *testing.T) {
|
||||
path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
|
||||
backend := newTestBackend()
|
||||
contr0, err := deploy(key0, new(big.Int), backend)
|
||||
contr0, _ := deploy(key0, new(big.Int), backend)
|
||||
|
||||
chbook, err := NewChequebook(path0, contr0, key0, backend)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
@@ -361,7 +362,8 @@ func TestDeposit(t *testing.T) {
|
||||
func TestCash(t *testing.T) {
|
||||
path := filepath.Join(os.TempDir(), "chequebook-test.json")
|
||||
backend := newTestBackend()
|
||||
contr0, err := deploy(key0, common.Big2, backend)
|
||||
contr0, _ := deploy(key0, common.Big2, backend)
|
||||
|
||||
chbook, err := NewChequebook(path, contr0, key0, backend)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, got %v", err)
|
||||
@@ -380,11 +382,12 @@ func TestCash(t *testing.T) {
|
||||
}
|
||||
|
||||
// cashing latest cheque
|
||||
_, err = chbox.Receive(ch)
|
||||
if err != nil {
|
||||
if _, err = chbox.Receive(ch); err != nil {
|
||||
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()
|
||||
|
||||
chbook.balance = new(big.Int).Set(common.Big3)
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
var (
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
name = "my name on ENS"
|
||||
hash = crypto.Sha3Hash([]byte("my content"))
|
||||
hash = crypto.Keccak256Hash([]byte("my content"))
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
)
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ contract ReleaseOracle {
|
||||
}
|
||||
|
||||
// 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[]) {
|
||||
return voters;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ contract ReleaseOracle {
|
||||
voters[i] = voters[voters.length - 1];
|
||||
voters.length--;
|
||||
|
||||
delete verProp; // Nuke any version proposal (no suprise releases!)
|
||||
delete verProp; // Nuke any version proposal (no surprise releases!)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
|
||||
toaddr := common.Address{}
|
||||
data := make([]byte, nbytes)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from])
|
||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from])
|
||||
gen.AddTx(tx)
|
||||
from = to
|
||||
}
|
||||
|
||||
@@ -24,11 +24,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/pow/ezp"
|
||||
)
|
||||
|
||||
func testChainConfig() *params.ChainConfig {
|
||||
@@ -49,20 +47,19 @@ func proc() (Validator, *BlockChain) {
|
||||
}
|
||||
|
||||
func TestNumber(t *testing.T) {
|
||||
pow := ezp.New()
|
||||
_, chain := proc()
|
||||
|
||||
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
||||
cfg := testChainConfig()
|
||||
header := makeHeader(cfg, chain.Genesis(), statedb)
|
||||
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 {
|
||||
t.Errorf("expected block number error, got %q", err)
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Errorf("didn't expect block number error")
|
||||
}
|
||||
@@ -77,7 +74,7 @@ func TestPutReceipt(t *testing.T) {
|
||||
hash[0] = 2
|
||||
|
||||
receipt := new(types.Receipt)
|
||||
receipt.Logs = vm.Logs{&vm.Log{
|
||||
receipt.Logs = []*types.Log{{
|
||||
Address: addr,
|
||||
Topics: []common.Hash{hash},
|
||||
Data: []byte("hi"),
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
@@ -46,9 +47,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
chainlogger = logger.NewLogger("CHAIN")
|
||||
jsonlogger = logger.NewJsonLogger()
|
||||
|
||||
blockInsertTimer = metrics.NewTimer("chain/inserts")
|
||||
|
||||
ErrNoGenesis = errors.New("Genesis not found in chain")
|
||||
@@ -150,7 +148,7 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.P
|
||||
return nil, err
|
||||
}
|
||||
// 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 {
|
||||
// get the canonical block corresponding to the offending header's number
|
||||
headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
|
||||
@@ -402,10 +400,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) {
|
||||
|
||||
// Export writes the active chain to the given writer.
|
||||
func (self *BlockChain) Export(w io.Writer) error {
|
||||
if err := self.ExportN(w, uint64(0), self.currentBlock.NumberU64()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return self.ExportN(w, uint64(0), self.currentBlock.NumberU64())
|
||||
}
|
||||
|
||||
// ExportN writes a subset of the active chain to the given writer.
|
||||
@@ -601,7 +596,11 @@ func (self *BlockChain) procFutureBlocks() {
|
||||
}
|
||||
if len(blocks) > 0 {
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,6 +674,18 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty
|
||||
// transaction and receipt data.
|
||||
// XXX should this be moved to the test?
|
||||
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)
|
||||
defer self.wg.Done()
|
||||
|
||||
@@ -789,7 +800,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
|
||||
if stats.ignored > 0 {
|
||||
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
|
||||
}
|
||||
@@ -843,6 +854,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
|
||||
// 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) {
|
||||
// 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)
|
||||
defer self.wg.Done()
|
||||
|
||||
@@ -853,9 +876,9 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||
// faster than direct delivery and requires much less mutex
|
||||
// acquiring.
|
||||
var (
|
||||
stats = insertStats{startTime: time.Now()}
|
||||
stats = insertStats{startTime: mclock.Now()}
|
||||
events = make([]interface{}, 0, len(chain))
|
||||
coalescedLogs vm.Logs
|
||||
coalescedLogs []*types.Log
|
||||
nonceChecked = make([]bool, len(chain))
|
||||
)
|
||||
|
||||
@@ -916,10 +939,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||
}
|
||||
|
||||
self.reportBlock(block, nil, err)
|
||||
|
||||
return i, err
|
||||
}
|
||||
|
||||
// Create a new statedb using the parent block and report an
|
||||
// error if it fails.
|
||||
switch {
|
||||
@@ -988,7 +1009,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()))
|
||||
}
|
||||
blockInsertTimer.UpdateSince(bstart)
|
||||
events = append(events, ChainSideEvent{block, logs})
|
||||
events = append(events, ChainSideEvent{block})
|
||||
|
||||
case SplitStatTy:
|
||||
events = append(events, ChainSplitEvent{block, logs})
|
||||
@@ -1011,7 +1032,7 @@ type insertStats struct {
|
||||
queued, processed, ignored int
|
||||
usedGas uint64
|
||||
lastIndex int
|
||||
startTime time.Time
|
||||
startTime mclock.AbsTime
|
||||
}
|
||||
|
||||
// statsReportLimit is the time limit during import after which we always print
|
||||
@@ -1023,28 +1044,24 @@ const statsReportLimit = 8 * time.Second
|
||||
func (st *insertStats) report(chain []*types.Block, index int) {
|
||||
// Fetch the timings for the batch
|
||||
var (
|
||||
now = time.Now()
|
||||
elapsed = now.Sub(st.startTime)
|
||||
now = mclock.Now()
|
||||
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 index == len(chain)-1 || elapsed >= statsReportLimit {
|
||||
start, end := chain[st.lastIndex], chain[index]
|
||||
txcount := countTransactions(chain[st.lastIndex : index+1])
|
||||
|
||||
extra := ""
|
||||
var hashes, extra string
|
||||
if st.queued > 0 || st.ignored > 0 {
|
||||
extra = fmt.Sprintf(" (%d queued %d ignored)", st.queued, st.ignored)
|
||||
}
|
||||
hashes := ""
|
||||
if st.processed > 1 {
|
||||
hashes = fmt.Sprintf("%x… / %x…", start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
|
||||
} else {
|
||||
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}
|
||||
}
|
||||
@@ -1062,24 +1079,25 @@ func countTransactions(chain []*types.Block) (c int) {
|
||||
// event about them
|
||||
func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||
var (
|
||||
newChain types.Blocks
|
||||
oldChain types.Blocks
|
||||
commonBlock *types.Block
|
||||
oldStart = oldBlock
|
||||
newStart = newBlock
|
||||
deletedTxs types.Transactions
|
||||
deletedLogs vm.Logs
|
||||
deletedLogsByHash = make(map[common.Hash]vm.Logs)
|
||||
newChain types.Blocks
|
||||
oldChain types.Blocks
|
||||
commonBlock *types.Block
|
||||
oldStart = oldBlock
|
||||
newStart = newBlock
|
||||
deletedTxs types.Transactions
|
||||
deletedLogs []*types.Log
|
||||
// collectLogs collects the logs that were generated during the
|
||||
// processing of the block that corresponds with the given hash.
|
||||
// These logs are later announced as deleted.
|
||||
collectLogs = func(h common.Hash) {
|
||||
// Coalesce logs
|
||||
// Coalesce logs and set 'Removed'.
|
||||
receipts := GetBlockReceipts(self.chainDb, h, self.hc.GetBlockNumber(h))
|
||||
for _, receipt := range receipts {
|
||||
deletedLogs = append(deletedLogs, receipt.Logs...)
|
||||
|
||||
deletedLogsByHash[h] = receipt.Logs
|
||||
for _, log := range receipt.Logs {
|
||||
del := *log
|
||||
del.Removed = true
|
||||
deletedLogs = append(deletedLogs, &del)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -1173,7 +1191,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||
if len(oldChain) > 0 {
|
||||
go func() {
|
||||
for _, block := range oldChain {
|
||||
self.eventMux.Post(ChainSideEvent{Block: block, Logs: deletedLogsByHash[block.Hash()]})
|
||||
self.eventMux.Post(ChainSideEvent{Block: block})
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -1183,7 +1201,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||
|
||||
// postChainEvents iterates over the events generated by a chain insertion and
|
||||
// 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
|
||||
self.eventMux.Post(logs)
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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 i%3 == 2 {
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
@@ -883,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
|
||||
// Create two transactions shared between the chains:
|
||||
// - postponed: transaction included at a later block 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)
|
||||
swapped, _ := types.NewTransaction(1, 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.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:
|
||||
// - 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) {
|
||||
switch i {
|
||||
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(postponed) // This transaction will be postponed till block #3 in the fork
|
||||
|
||||
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(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) {
|
||||
switch i {
|
||||
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
|
||||
|
||||
case 2:
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
@@ -995,7 +995,7 @@ func TestLogReorgs(t *testing.T) {
|
||||
subs := evmux.Subscribe(RemovedLogsEvent{})
|
||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
||||
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 {
|
||||
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) {
|
||||
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 {
|
||||
gen.OffsetTime(-1)
|
||||
}
|
||||
@@ -1107,7 +1107,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||
|
||||
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) {
|
||||
// try to retrieve a block by its canonical hash and see if the block data can be retrieved.
|
||||
for {
|
||||
@@ -1152,7 +1152,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||
tx *types.Transaction
|
||||
err 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 {
|
||||
@@ -1215,7 +1215,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||
tx *types.Transaction
|
||||
err 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 {
|
||||
@@ -1260,11 +1260,11 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||
)
|
||||
switch i {
|
||||
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:
|
||||
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:
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -108,7 +108,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||
b.SetCoinbase(common.Address{})
|
||||
}
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -55,13 +55,13 @@ func ExampleGenerateChain() {
|
||||
switch i {
|
||||
case 0:
|
||||
// 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)
|
||||
case 1:
|
||||
// In block 2, addr1 sends some more ether to addr2.
|
||||
// addr2 passes it on to addr3.
|
||||
tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
||||
tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
|
||||
tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
|
||||
tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
|
||||
gen.AddTx(tx1)
|
||||
gen.AddTx(tx2)
|
||||
case 2:
|
||||
|
||||
@@ -45,11 +45,11 @@ func ValidateDAOHeaderExtraData(config *params.ChainConfig, header *types.Header
|
||||
}
|
||||
// Depending whether we support or oppose the fork, validate the extra-data contents
|
||||
if config.DAOForkSupport {
|
||||
if bytes.Compare(header.Extra, params.DAOForkBlockExtra) != 0 {
|
||||
if !bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
||||
return ValidationError("DAO pro-fork bad block extra-data: 0x%x", header.Extra)
|
||||
}
|
||||
} else {
|
||||
if bytes.Compare(header.Extra, params.DAOForkBlockExtra) == 0 {
|
||||
if bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
||||
return ValidationError("DAO no-fork bad block extra-data: 0x%x", header.Extra)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@@ -63,6 +64,8 @@ var (
|
||||
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
|
||||
|
||||
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
|
||||
@@ -564,6 +567,9 @@ func mipmapKey(num, level uint64) []byte {
|
||||
// WriteMapmapBloom writes each address included in the receipts' logs to the
|
||||
// MIP bloom bin.
|
||||
func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts) error {
|
||||
mipmapBloomMu.Lock()
|
||||
defer mipmapBloomMu.Unlock()
|
||||
|
||||
batch := db.NewBatch()
|
||||
for _, level := range MIPMapLevels {
|
||||
key := mipmapKey(number, level)
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
@@ -393,9 +392,9 @@ func TestReceiptStorage(t *testing.T) {
|
||||
receipt1 := &types.Receipt{
|
||||
PostState: []byte{0x01},
|
||||
CumulativeGasUsed: big.NewInt(1),
|
||||
Logs: vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x11})},
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
||||
Logs: []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte{0x11})},
|
||||
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
||||
},
|
||||
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
|
||||
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
||||
@@ -404,9 +403,9 @@ func TestReceiptStorage(t *testing.T) {
|
||||
receipt2 := &types.Receipt{
|
||||
PostState: []byte{0x02},
|
||||
CumulativeGasUsed: big.NewInt(2),
|
||||
Logs: vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x22})},
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
||||
Logs: []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte{0x22})},
|
||||
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
||||
},
|
||||
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
|
||||
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
||||
@@ -431,7 +430,7 @@ func TestReceiptStorage(t *testing.T) {
|
||||
rlpHave, _ := rlp.EncodeToBytes(r)
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -452,9 +451,9 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||
receipt1 := &types.Receipt{
|
||||
PostState: []byte{0x01},
|
||||
CumulativeGasUsed: big.NewInt(1),
|
||||
Logs: vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x11})},
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
||||
Logs: []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte{0x11})},
|
||||
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
||||
},
|
||||
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
|
||||
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
||||
@@ -463,9 +462,9 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||
receipt2 := &types.Receipt{
|
||||
PostState: []byte{0x02},
|
||||
CumulativeGasUsed: big.NewInt(2),
|
||||
Logs: vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x22})},
|
||||
&vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
||||
Logs: []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte{0x22})},
|
||||
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
||||
},
|
||||
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
|
||||
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
||||
@@ -489,7 +488,7 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||
rlpHave, _ := rlp.EncodeToBytes(rs[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])
|
||||
}
|
||||
}
|
||||
@@ -505,14 +504,14 @@ func TestMipmapBloom(t *testing.T) {
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
|
||||
receipt1 := new(types.Receipt)
|
||||
receipt1.Logs = vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte("test"))},
|
||||
&vm.Log{Address: common.BytesToAddress([]byte("address"))},
|
||||
receipt1.Logs = []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte("test"))},
|
||||
{Address: common.BytesToAddress([]byte("address"))},
|
||||
}
|
||||
receipt2 := new(types.Receipt)
|
||||
receipt2.Logs = vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte("test"))},
|
||||
&vm.Log{Address: common.BytesToAddress([]byte("address1"))},
|
||||
receipt2.Logs = []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte("test"))},
|
||||
{Address: common.BytesToAddress([]byte("address1"))},
|
||||
}
|
||||
|
||||
WriteMipmapBloom(db, 1, types.Receipts{receipt1})
|
||||
@@ -528,14 +527,14 @@ func TestMipmapBloom(t *testing.T) {
|
||||
// reset
|
||||
db, _ = ethdb.NewMemDatabase()
|
||||
receipt := new(types.Receipt)
|
||||
receipt.Logs = vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte("test"))},
|
||||
receipt.Logs = []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte("test"))},
|
||||
}
|
||||
WriteMipmapBloom(db, 999, types.Receipts{receipt1})
|
||||
|
||||
receipt = new(types.Receipt)
|
||||
receipt.Logs = vm.Logs{
|
||||
&vm.Log{Address: common.BytesToAddress([]byte("test 1"))},
|
||||
receipt.Logs = []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte("test 1"))},
|
||||
}
|
||||
WriteMipmapBloom(db, 1000, types.Receipts{receipt})
|
||||
|
||||
@@ -568,17 +567,12 @@ func TestMipmapChain(t *testing.T) {
|
||||
switch i {
|
||||
case 1:
|
||||
receipt := types.NewReceipt(nil, new(big.Int))
|
||||
receipt.Logs = vm.Logs{
|
||||
&vm.Log{
|
||||
Address: addr,
|
||||
Topics: []common.Hash{hash1},
|
||||
},
|
||||
}
|
||||
receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}}
|
||||
gen.AddUncheckedReceipt(receipt)
|
||||
receipts = types.Receipts{receipt}
|
||||
case 1000:
|
||||
receipt := types.NewReceipt(nil, new(big.Int))
|
||||
receipt.Logs = vm.Logs{&vm.Log{Address: addr2}}
|
||||
receipt.Logs = []*types.Log{{Address: addr2}}
|
||||
gen.AddUncheckedReceipt(receipt)
|
||||
receipts = types.Receipts{receipt}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -21,7 +21,6 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
)
|
||||
|
||||
// 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.
|
||||
type PendingLogsEvent struct {
|
||||
Logs vm.Logs
|
||||
Logs []*types.Log
|
||||
}
|
||||
|
||||
// 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 }
|
||||
|
||||
// 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
|
||||
type ChainSplitEvent struct {
|
||||
Block *types.Block
|
||||
Logs vm.Logs
|
||||
Logs []*types.Log
|
||||
}
|
||||
|
||||
type ChainEvent struct {
|
||||
Block *types.Block
|
||||
Hash common.Hash
|
||||
Logs vm.Logs
|
||||
Logs []*types.Log
|
||||
}
|
||||
|
||||
type ChainSideEvent struct {
|
||||
Block *types.Block
|
||||
Logs vm.Logs
|
||||
}
|
||||
|
||||
type PendingBlockEvent struct {
|
||||
Block *types.Block
|
||||
Logs vm.Logs
|
||||
Logs []*types.Log
|
||||
}
|
||||
|
||||
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/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/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/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/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()))
|
||||
}
|
||||
|
||||
// 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.
|
||||
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
|
||||
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
|
||||
// genesis block.
|
||||
func DefaultGenesisBlock() string {
|
||||
@@ -198,6 +192,8 @@ func DefaultGenesisBlock() string {
|
||||
return string(blob)
|
||||
}
|
||||
|
||||
// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum
|
||||
// test network genesis block.
|
||||
func DefaultTestnetGenesisBlock() string {
|
||||
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
|
||||
blob, err := ioutil.ReadAll(reader)
|
||||
@@ -207,26 +203,12 @@ func DefaultTestnetGenesisBlock() string {
|
||||
return string(blob)
|
||||
}
|
||||
|
||||
// OlympicGenesisBlock assembles a JSON string representing the Olympic genesis
|
||||
// block.
|
||||
func OlympicGenesisBlock() string {
|
||||
return fmt.Sprintf(`{
|
||||
"nonce":"0x%x",
|
||||
"gasLimit":"0x%x",
|
||||
"difficulty":"0x%x",
|
||||
"alloc": {
|
||||
"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())
|
||||
// DevGenesisBlock assembles a JSON string representing a local dev genesis block.
|
||||
func DevGenesisBlock() string {
|
||||
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock)))
|
||||
blob, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to load dev genesis: %v", err))
|
||||
}
|
||||
return string(blob)
|
||||
}
|
||||
|
||||
@@ -224,6 +224,17 @@ type WhCallback func(*types.Header) error
|
||||
// of the header retrieval mechanisms already need to verfy nonces, as well as
|
||||
// because nonces can be verified sparsely, not needing to check each.
|
||||
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
|
||||
stats := struct{ processed, ignored int }{}
|
||||
start := time.Now()
|
||||
@@ -328,7 +339,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
|
||||
if stats.ignored > 0 {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ func (it *NodeIterator) step() error {
|
||||
if !it.dataIt.Next() {
|
||||
it.dataIt = nil
|
||||
}
|
||||
if bytes.Compare(account.CodeHash, emptyCodeHash) != 0 {
|
||||
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
|
||||
it.codeHash = common.BytesToHash(account.CodeHash)
|
||||
it.code, err = it.state.db.Get(account.CodeHash)
|
||||
if err != nil {
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestNodeIteratorCoverage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Cross check the hashes and the database itself
|
||||
for hash, _ := range hashes {
|
||||
for hash := range hashes {
|
||||
if _, err := db.Get(hash.Bytes()); err != nil {
|
||||
t.Errorf("failed to retrieve reported node %x: %v", hash, err)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ func TestRemove(t *testing.T) {
|
||||
ms, account := create()
|
||||
|
||||
nn := make([]bool, 10)
|
||||
for i, _ := range nn {
|
||||
for i := range nn {
|
||||
nn[i] = true
|
||||
}
|
||||
account.nonces = append(account.nonces, nn...)
|
||||
@@ -68,7 +68,7 @@ func TestReuse(t *testing.T) {
|
||||
ms, account := create()
|
||||
|
||||
nn := make([]bool, 10)
|
||||
for i, _ := range nn {
|
||||
for i := range nn {
|
||||
nn[i] = true
|
||||
}
|
||||
account.nonces = append(account.nonces, nn...)
|
||||
@@ -84,16 +84,16 @@ func TestReuse(t *testing.T) {
|
||||
func TestRemoteNonceChange(t *testing.T) {
|
||||
ms, account := create()
|
||||
nn := make([]bool, 10)
|
||||
for i, _ := range nn {
|
||||
for i := range nn {
|
||||
nn[i] = true
|
||||
}
|
||||
account.nonces = append(account.nonces, nn...)
|
||||
nonce := ms.NewNonce(addr)
|
||||
ms.NewNonce(addr)
|
||||
|
||||
ms.StateDB.stateObjects[addr].data.Nonce = 200
|
||||
nonce = ms.NewNonce(addr)
|
||||
nonce := ms.NewNonce(addr)
|
||||
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)
|
||||
@@ -101,7 +101,7 @@ func TestRemoteNonceChange(t *testing.T) {
|
||||
ms.StateDB.stateObjects[addr].data.Nonce = 200
|
||||
nonce = ms.NewNonce(addr)
|
||||
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
|
||||
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 {
|
||||
stateObject := newObject(db, self.address, self.data, onDirty)
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
@@ -71,7 +72,7 @@ type StateDB struct {
|
||||
|
||||
thash, bhash common.Hash
|
||||
txIndex int
|
||||
logs map[common.Hash]vm.Logs
|
||||
logs map[common.Hash][]*types.Log
|
||||
logSize uint
|
||||
|
||||
// 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),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||
refund: new(big.Int),
|
||||
logs: make(map[common.Hash]vm.Logs),
|
||||
logs: make(map[common.Hash][]*types.Log),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -118,7 +119,7 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) {
|
||||
stateObjects: make(map[common.Address]*StateObject),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||
refund: new(big.Int),
|
||||
logs: make(map[common.Hash]vm.Logs),
|
||||
logs: make(map[common.Hash][]*types.Log),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -138,7 +139,7 @@ func (self *StateDB) Reset(root common.Hash) error {
|
||||
self.thash = common.Hash{}
|
||||
self.bhash = common.Hash{}
|
||||
self.txIndex = 0
|
||||
self.logs = make(map[common.Hash]vm.Logs)
|
||||
self.logs = make(map[common.Hash][]*types.Log)
|
||||
self.logSize = 0
|
||||
self.clearJournalAndRefund()
|
||||
|
||||
@@ -175,7 +176,7 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
|
||||
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})
|
||||
|
||||
log.TxHash = self.thash
|
||||
@@ -186,12 +187,12 @@ func (self *StateDB) AddLog(log *vm.Log) {
|
||||
self.logSize++
|
||||
}
|
||||
|
||||
func (self *StateDB) GetLogs(hash common.Hash) vm.Logs {
|
||||
func (self *StateDB) GetLogs(hash common.Hash) []*types.Log {
|
||||
return self.logs[hash]
|
||||
}
|
||||
|
||||
func (self *StateDB) Logs() vm.Logs {
|
||||
var logs vm.Logs
|
||||
func (self *StateDB) Logs() []*types.Log {
|
||||
var logs []*types.Log
|
||||
for _, lgs := range self.logs {
|
||||
logs = append(logs, lgs...)
|
||||
}
|
||||
@@ -209,7 +210,7 @@ func (self *StateDB) Exist(addr common.Address) bool {
|
||||
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)
|
||||
func (self *StateDB) Empty(addr common.Address) bool {
|
||||
so := self.GetStateObject(addr)
|
||||
@@ -293,6 +294,7 @@ func (self *StateDB) HasSuicided(addr common.Address) bool {
|
||||
* SETTERS
|
||||
*/
|
||||
|
||||
// AddBalance adds amount to the account associated with addr
|
||||
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||
stateObject := self.GetOrNewStateObject(addr)
|
||||
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) {
|
||||
stateObject := self.GetOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
@@ -465,16 +475,16 @@ func (self *StateDB) Copy() *StateDB {
|
||||
stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
|
||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
|
||||
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,
|
||||
}
|
||||
// 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.stateObjectsDirty[addr] = struct{}{}
|
||||
}
|
||||
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)
|
||||
}
|
||||
return state
|
||||
@@ -520,7 +530,7 @@ func (self *StateDB) GetRefund() *big.Int {
|
||||
// It is called in between transactions to get the root hash that
|
||||
// goes into transaction receipts.
|
||||
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||
for addr, _ := range s.stateObjectsDirty {
|
||||
for addr := range s.stateObjectsDirty {
|
||||
stateObject := s.stateObjects[addr]
|
||||
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
|
||||
s.deleteStateObject(stateObject)
|
||||
@@ -543,7 +553,7 @@ func (s *StateDB) DeleteSuicides() {
|
||||
// Reset refund so that any used-gas calculations can use this method.
|
||||
s.clearJournalAndRefund()
|
||||
|
||||
for addr, _ := range s.stateObjectsDirty {
|
||||
for addr := range s.stateObjectsDirty {
|
||||
stateObject := s.stateObjects[addr]
|
||||
|
||||
// If the object has been removed by a suicide
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
"testing/quick"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
@@ -221,7 +221,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||
fn: func(a testAction, s *StateDB) {
|
||||
data := make([]byte, 2)
|
||||
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),
|
||||
},
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
@@ -32,7 +31,7 @@ import (
|
||||
type StateSync trie.TrieSync
|
||||
|
||||
// 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
|
||||
|
||||
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
|
||||
// was committed to the database and also the index of an entry if processing of
|
||||
// it failed.
|
||||
func (s *StateSync) Process(list []trie.SyncResult) (bool, int, error) {
|
||||
return (*trie.TrieSync)(s).Process(list)
|
||||
func (s *StateSync) Process(list []trie.SyncResult, dbw trie.DatabaseWriter) (bool, int, error) {
|
||||
return (*trie.TrieSync)(s).Process(list, dbw)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,7 @@ func testIterativeStateSync(t *testing.T, batch int) {
|
||||
}
|
||||
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)
|
||||
}
|
||||
queue = append(queue[:0], sched.Missing(batch)...)
|
||||
@@ -168,7 +168,7 @@ func TestIterativeDelayedStateSync(t *testing.T) {
|
||||
}
|
||||
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)
|
||||
}
|
||||
queue = append(queue[len(results):], sched.Missing(0)...)
|
||||
@@ -198,7 +198,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
|
||||
for len(queue) > 0 {
|
||||
// Fetch all the queued nodes in a random order
|
||||
results := make([]trie.SyncResult, 0, len(queue))
|
||||
for hash, _ := range queue {
|
||||
for hash := range queue {
|
||||
data, err := srcDb.Get(hash.Bytes())
|
||||
if err != nil {
|
||||
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})
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
queue = make(map[common.Hash]struct{})
|
||||
@@ -235,7 +235,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||
for len(queue) > 0 {
|
||||
// Sync only half of the scheduled nodes, even those in random order
|
||||
results := make([]trie.SyncResult, 0, len(queue)/2+1)
|
||||
for hash, _ := range queue {
|
||||
for hash := range queue {
|
||||
delete(queue, hash)
|
||||
|
||||
data, err := srcDb.Get(hash.Bytes())
|
||||
@@ -249,7 +249,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
for _, hash := range sched.Missing(0) {
|
||||
@@ -283,7 +283,7 @@ func TestIncompleteStateSync(t *testing.T) {
|
||||
results[i] = trie.SyncResult{Hash: hash, Data: data}
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
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
|
||||
codeHash := false
|
||||
for _, acc := range srcAccounts {
|
||||
if bytes.Compare(root.Bytes(), crypto.Sha3(acc.code)) == 0 {
|
||||
if root == crypto.Keccak256Hash(acc.code) {
|
||||
codeHash = true
|
||||
break
|
||||
}
|
||||
|
||||
@@ -57,13 +57,13 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcess
|
||||
// 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
|
||||
// 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 (
|
||||
receipts types.Receipts
|
||||
totalUsedGas = big.NewInt(0)
|
||||
err error
|
||||
header = block.Header()
|
||||
allLogs vm.Logs
|
||||
allLogs []*types.Log
|
||||
gp = new(GasPool).AddGas(block.GasLimit())
|
||||
)
|
||||
// Mutate the the block and state according to any hard-fork specs
|
||||
@@ -74,12 +74,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
for i, tx := range block.Transactions() {
|
||||
//fmt.Println("tx:", 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 {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
receipts = append(receipts, receipt)
|
||||
allLogs = append(allLogs, logs...)
|
||||
allLogs = append(allLogs, receipt.Logs...)
|
||||
}
|
||||
AccumulateRewards(statedb, header, block.Uncles())
|
||||
|
||||
@@ -87,37 +87,44 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
}
|
||||
|
||||
// ApplyTransaction attempts to apply a transaction to the given state database
|
||||
// and uses the input parameters for its environment.
|
||||
//
|
||||
// ApplyTransactions returns the generated receipts and vm logs during the
|
||||
// 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, vm.Logs, *big.Int, error) {
|
||||
// and uses the input parameters for its environment. It returns the receipt
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
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) {
|
||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, msg, header, cfg), msg, gp)
|
||||
// Create a new context to be used in the EVM environment
|
||||
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 {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Update the state with pending changes
|
||||
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.TxHash = tx.Hash()
|
||||
receipt.GasUsed = new(big.Int).Set(gas)
|
||||
if MessageCreatesContract(msg) {
|
||||
receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce())
|
||||
// if the transaction created a contract, store the creation address in the receipt.
|
||||
if msg.To() == nil {
|
||||
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
|
||||
}
|
||||
|
||||
logs := statedb.GetLogs(tx.Hash())
|
||||
receipt.Logs = logs
|
||||
// Set the receipt logs and create a bloom for filtering
|
||||
receipt.Logs = statedb.GetLogs(tx.Hash())
|
||||
receipt.Bloom = types.CreateBloom(types.Receipts{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
|
||||
|
||||
@@ -55,9 +55,9 @@ type StateTransition struct {
|
||||
initialGas *big.Int
|
||||
value *big.Int
|
||||
data []byte
|
||||
state vm.Database
|
||||
state vm.StateDB
|
||||
|
||||
env vm.Environment
|
||||
env *vm.EVM
|
||||
}
|
||||
|
||||
// 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.
|
||||
func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTransition {
|
||||
func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition {
|
||||
return &StateTransition{
|
||||
gp: gp,
|
||||
env: env,
|
||||
@@ -116,7 +116,7 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran
|
||||
initialGas: new(big.Int),
|
||||
value: msg.Value(),
|
||||
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
|
||||
// indicates a core error meaning that the message would always fail for that particular
|
||||
// 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)
|
||||
|
||||
ret, _, gasUsed, err := st.TransitionDb()
|
||||
@@ -159,7 +159,7 @@ func (self *StateTransition) to() vm.Account {
|
||||
|
||||
func (self *StateTransition) useGas(amount *big.Int) error {
|
||||
if self.gas.Cmp(amount) < 0 {
|
||||
return vm.OutOfGasError
|
||||
return vm.ErrOutOfGas
|
||||
}
|
||||
self.gas.Sub(self.gas, amount)
|
||||
|
||||
@@ -217,47 +217,44 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||
msg := self.msg
|
||||
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)
|
||||
// Pay intrinsic gas
|
||||
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
|
||||
return nil, nil, nil, InvalidTxError(err)
|
||||
}
|
||||
|
||||
vmenv := self.env
|
||||
//var addr common.Address
|
||||
var (
|
||||
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 {
|
||||
ret, _, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value)
|
||||
if homestead && err == vm.CodeStoreOutOfGasError {
|
||||
ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value)
|
||||
if homestead && err == vm.ErrCodeStoreOutOfGas {
|
||||
self.gas = Big0
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
ret = nil
|
||||
glog.V(logger.Core).Infoln("VM create err:", err)
|
||||
}
|
||||
} else {
|
||||
// Increment the nonce for the next transaction
|
||||
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)
|
||||
if err != nil {
|
||||
glog.V(logger.Core).Infoln("VM call err:", err)
|
||||
ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.value)
|
||||
}
|
||||
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())
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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 len(removed) > 0 {
|
||||
*m.index = make([]uint64, 0, len(m.items))
|
||||
for nonce, _ := range m.items {
|
||||
for nonce := range m.items {
|
||||
*m.index = append(*m.index, nonce)
|
||||
}
|
||||
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
|
||||
// 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-
|
||||
// executable/future queue, with minor behavoiral changes.
|
||||
// executable/future queue, with minor behavioral changes.
|
||||
type txList struct {
|
||||
strict bool // Whether nonces are strictly continuous or not
|
||||
txs *txSortedMap // Heap indexed sorted hash map of the transactions
|
||||
|
||||
@@ -37,15 +37,14 @@ import (
|
||||
|
||||
var (
|
||||
// Transaction Pool Errors
|
||||
ErrInvalidSender = errors.New("Invalid sender")
|
||||
ErrNonce = errors.New("Nonce too low")
|
||||
ErrCheap = errors.New("Gas price too low for acceptance")
|
||||
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")
|
||||
ErrIntrinsicGas = errors.New("Intrinsic gas too low")
|
||||
ErrGasLimit = errors.New("Exceeds block gas limit")
|
||||
ErrNegativeValue = errors.New("Negative value")
|
||||
ErrInvalidSender = errors.New("Invalid sender")
|
||||
ErrNonce = errors.New("Nonce too low")
|
||||
ErrCheap = errors.New("Gas price too low for acceptance")
|
||||
ErrBalance = errors.New("Insufficient balance")
|
||||
ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value")
|
||||
ErrIntrinsicGas = errors.New("Intrinsic gas too low")
|
||||
ErrGasLimit = errors.New("Exceeds block gas limit")
|
||||
ErrNegativeValue = errors.New("Negative value")
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -124,6 +123,8 @@ func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentState
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
|
||||
pool.resetState()
|
||||
|
||||
pool.wg.Add(2)
|
||||
go pool.eventLoop()
|
||||
go pool.expirationLoop()
|
||||
@@ -176,7 +177,7 @@ func (pool *TxPool) resetState() {
|
||||
// any transactions that have been included in the block or
|
||||
// have been invalidated because of another transaction (e.g.
|
||||
// higher gas price)
|
||||
pool.demoteUnexecutables()
|
||||
pool.demoteUnexecutables(currentState)
|
||||
|
||||
// Update all accounts to the latest known pending nonce
|
||||
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
|
||||
// or remove those that have become invalid
|
||||
pool.promoteExecutables()
|
||||
pool.promoteExecutables(currentState)
|
||||
}
|
||||
|
||||
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
|
||||
// account and sorted by nonce. The returned transaction set is a copy and can be
|
||||
// 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()
|
||||
defer pool.mu.Unlock()
|
||||
|
||||
state, err := pool.currentState()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check queue first
|
||||
pool.promoteExecutables()
|
||||
pool.promoteExecutables(state)
|
||||
|
||||
// invalidate any txs
|
||||
pool.demoteUnexecutables()
|
||||
pool.demoteUnexecutables(state)
|
||||
|
||||
pending := make(map[common.Address]types.Transactions)
|
||||
for addr, list := range pool.pending {
|
||||
pending[addr] = list.Flatten()
|
||||
}
|
||||
return pending
|
||||
return pending, nil
|
||||
}
|
||||
|
||||
// SetLocal marks a transaction as local, skipping gas price
|
||||
@@ -280,13 +286,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||
if err != nil {
|
||||
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
|
||||
if currentState.GetNonce(from) > tx.Nonce() {
|
||||
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
|
||||
// later pending promotion and execution.
|
||||
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()
|
||||
if pool.all[hash] != nil {
|
||||
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!
|
||||
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
|
||||
if pool.pending[addr] == nil {
|
||||
pool.pending[addr] = newTxList(true)
|
||||
@@ -410,13 +405,19 @@ func (pool *TxPool) Add(tx *types.Transaction) error {
|
||||
if err := pool.add(tx); err != nil {
|
||||
return err
|
||||
}
|
||||
pool.promoteExecutables()
|
||||
|
||||
state, err := pool.currentState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pool.promoteExecutables(state)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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()
|
||||
defer pool.mu.Unlock()
|
||||
|
||||
@@ -425,7 +426,15 @@ func (pool *TxPool) AddBatch(txs []*types.Transaction) {
|
||||
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
|
||||
@@ -499,17 +508,7 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
||||
// promoteExecutables moves transactions that have become processable from the
|
||||
// future queue to the set of pending transactions. During this process, all
|
||||
// invalidated transactions (low nonce, low balance) are deleted.
|
||||
func (pool *TxPool) promoteExecutables() {
|
||||
// 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
|
||||
}
|
||||
func (pool *TxPool) promoteExecutables(state *state.StateDB) {
|
||||
// Iterate over all accounts and promote any executable transactions
|
||||
queued := uint64(0)
|
||||
for addr, list := range pool.queue {
|
||||
@@ -610,7 +609,7 @@ func (pool *TxPool) promoteExecutables() {
|
||||
if queued > maxQueuedInTotal {
|
||||
// Sort all accounts with queued transactions by heartbeat
|
||||
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]})
|
||||
}
|
||||
sort.Sort(addresses)
|
||||
@@ -645,13 +644,7 @@ func (pool *TxPool) promoteExecutables() {
|
||||
// demoteUnexecutables removes invalid and processed transactions from the pools
|
||||
// executable/pending queue and any subsequent transactions that become unexecutable
|
||||
// are moved back into the future queue.
|
||||
func (pool *TxPool) demoteUnexecutables() {
|
||||
// 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
|
||||
}
|
||||
func (pool *TxPool) demoteUnexecutables(state *state.StateDB) {
|
||||
// Iterate over all accounts and demote any non-executable transactions
|
||||
for addr, list := range pool.pending {
|
||||
nonce := state.GetNonce(addr)
|
||||
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -51,14 +51,84 @@ func deriveSender(tx *types.Transaction) (common.Address, error) {
|
||||
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) {
|
||||
pool, key := setupTxPool()
|
||||
|
||||
tx := transaction(0, big.NewInt(100), key)
|
||||
if err := pool.Add(tx); err != ErrNonExistentAccount {
|
||||
t.Error("expected", ErrNonExistentAccount)
|
||||
}
|
||||
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1))
|
||||
@@ -97,9 +167,10 @@ func TestTransactionQueue(t *testing.T) {
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1000))
|
||||
pool.resetState()
|
||||
pool.enqueueTx(tx.Hash(), tx)
|
||||
|
||||
pool.promoteExecutables()
|
||||
pool.promoteExecutables(currentState)
|
||||
if len(pool.pending) != 1 {
|
||||
t.Error("expected valid txs to be 1 is", len(pool.pending))
|
||||
}
|
||||
@@ -108,7 +179,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||
from, _ = deriveSender(tx)
|
||||
currentState.SetNonce(from, 2)
|
||||
pool.enqueueTx(tx.Hash(), tx)
|
||||
pool.promoteExecutables()
|
||||
pool.promoteExecutables(currentState)
|
||||
if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok {
|
||||
t.Error("expected transaction to be in tx pool")
|
||||
}
|
||||
@@ -124,11 +195,13 @@ func TestTransactionQueue(t *testing.T) {
|
||||
from, _ = deriveSender(tx1)
|
||||
currentState, _ = pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1000))
|
||||
pool.resetState()
|
||||
|
||||
pool.enqueueTx(tx1.Hash(), tx1)
|
||||
pool.enqueueTx(tx2.Hash(), tx2)
|
||||
pool.enqueueTx(tx3.Hash(), tx3)
|
||||
|
||||
pool.promoteExecutables()
|
||||
pool.promoteExecutables(currentState)
|
||||
|
||||
if len(pool.pending) != 1 {
|
||||
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) {
|
||||
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)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1))
|
||||
@@ -214,9 +287,9 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||
resetState()
|
||||
|
||||
signer := types.HomesteadSigner{}
|
||||
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, key)
|
||||
tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(signer, key)
|
||||
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), 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.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil), 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
|
||||
if err := pool.add(tx1); err != nil {
|
||||
@@ -225,7 +298,8 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||
if err := pool.add(tx2); err != nil {
|
||||
t.Error("didn't expect error", err)
|
||||
}
|
||||
pool.promoteExecutables()
|
||||
state, _ := pool.currentState()
|
||||
pool.promoteExecutables(state)
|
||||
if pool.pending[addr].Len() != 1 {
|
||||
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 {
|
||||
t.Error("didn't expect error", err)
|
||||
}
|
||||
pool.promoteExecutables()
|
||||
pool.promoteExecutables(state)
|
||||
if pool.pending[addr].Len() != 1 {
|
||||
t.Error("expected 1 pending transactions, got", pool.pending[addr].Len())
|
||||
}
|
||||
@@ -295,6 +369,7 @@ func TestRemovedTxEvent(t *testing.T) {
|
||||
from, _ := deriveSender(tx)
|
||||
currentState, _ := pool.currentState()
|
||||
currentState.AddBalance(from, big.NewInt(1000000000000))
|
||||
pool.resetState()
|
||||
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
|
||||
pool.eventMux.Post(ChainHeadEvent{nil})
|
||||
if pool.pending[from].Len() != 1 {
|
||||
@@ -452,6 +527,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
|
||||
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000000))
|
||||
pool.resetState()
|
||||
|
||||
// Keep queuing up transactions and make sure all above a limit are dropped
|
||||
for i := uint64(1); i <= maxQueuedPerAccount+5; i++ {
|
||||
@@ -564,6 +640,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
|
||||
|
||||
state, _ := pool.currentState()
|
||||
state.AddBalance(account, big.NewInt(1000000))
|
||||
pool.resetState()
|
||||
|
||||
// Keep queuing up transactions and make sure all above a limit are dropped
|
||||
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
|
||||
b.ResetTimer()
|
||||
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
|
||||
b.ResetTimer()
|
||||
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
|
||||
// failed.
|
||||
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
|
||||
// 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
|
||||
binary.BigEndian.PutUint64(cpy.Nonce[:], nonce)
|
||||
cpy.Nonce = nonce
|
||||
cpy.MixDigest = mixDigest
|
||||
return &Block{
|
||||
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, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
|
||||
tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100"))
|
||||
fmt.Println(block.Transactions()[0].Hash())
|
||||
fmt.Println(tx1.data)
|
||||
fmt.Println(tx1.Hash())
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
@@ -95,17 +94,11 @@ func CreateBloom(receipts Receipts) Bloom {
|
||||
return BytesToBloom(bin.Bytes())
|
||||
}
|
||||
|
||||
func LogsBloom(logs vm.Logs) *big.Int {
|
||||
func LogsBloom(logs []*Log) *big.Int {
|
||||
bin := new(big.Int)
|
||||
for _, log := range logs {
|
||||
data := make([]common.Hash, len(log.Topics))
|
||||
bin.Or(bin, bloom9(log.Address.Bytes()))
|
||||
|
||||
for i, topic := range log.Topics {
|
||||
data[i] = topic
|
||||
}
|
||||
|
||||
for _, b := range data {
|
||||
for _, b := range log.Topics {
|
||||
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/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/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/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/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/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
@@ -40,7 +39,7 @@ type Receipt struct {
|
||||
PostState []byte
|
||||
CumulativeGasUsed *big.Int
|
||||
Bloom Bloom
|
||||
Logs vm.Logs
|
||||
Logs []*Log
|
||||
|
||||
// Implementation fields (don't reorder!)
|
||||
TxHash common.Hash
|
||||
@@ -52,7 +51,7 @@ type jsonReceipt struct {
|
||||
PostState *common.Hash `json:"root"`
|
||||
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
|
||||
Bloom *Bloom `json:"logsBloom"`
|
||||
Logs *vm.Logs `json:"logs"`
|
||||
Logs []*Log `json:"logs"`
|
||||
TxHash *common.Hash `json:"transactionHash"`
|
||||
ContractAddress *common.Address `json:"contractAddress"`
|
||||
GasUsed *hexutil.Big `json:"gasUsed"`
|
||||
@@ -76,7 +75,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
||||
PostState []byte
|
||||
CumulativeGasUsed *big.Int
|
||||
Bloom Bloom
|
||||
Logs vm.Logs
|
||||
Logs []*Log
|
||||
}
|
||||
if err := s.Decode(&receipt); err != nil {
|
||||
return err
|
||||
@@ -93,7 +92,7 @@ func (r *Receipt) MarshalJSON() ([]byte, error) {
|
||||
PostState: &root,
|
||||
CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed),
|
||||
Bloom: &r.Bloom,
|
||||
Logs: &r.Logs,
|
||||
Logs: r.Logs,
|
||||
TxHash: &r.TxHash,
|
||||
ContractAddress: &r.ContractAddress,
|
||||
GasUsed: (*hexutil.Big)(r.GasUsed),
|
||||
@@ -120,7 +119,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||
PostState: (*dec.PostState)[:],
|
||||
CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed),
|
||||
Bloom: *dec.Bloom,
|
||||
Logs: *dec.Logs,
|
||||
Logs: dec.Logs,
|
||||
TxHash: *dec.TxHash,
|
||||
GasUsed: (*big.Int)(dec.GasUsed),
|
||||
}
|
||||
@@ -142,9 +141,9 @@ type ReceiptForStorage Receipt
|
||||
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
|
||||
// into an RLP stream.
|
||||
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 {
|
||||
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})
|
||||
}
|
||||
@@ -158,7 +157,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||
Bloom Bloom
|
||||
TxHash common.Hash
|
||||
ContractAddress common.Address
|
||||
Logs []*vm.LogForStorage
|
||||
Logs []*LogForStorage
|
||||
GasUsed *big.Int
|
||||
}
|
||||
if err := s.Decode(&receipt); err != nil {
|
||||
@@ -166,9 +165,9 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||
}
|
||||
// Assign the consensus fields
|
||||
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 {
|
||||
r.Logs[i] = (*vm.Log)(log)
|
||||
r.Logs[i] = (*Log)(log)
|
||||
}
|
||||
// Assign the implementation fields
|
||||
r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user