Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Julian Yap 2017-01-15 03:07:47 -10:00
commit 341132925f
533 changed files with 31381 additions and 11594 deletions

View file

@ -13,15 +13,15 @@ matrix:
go: 1.6.2 go: 1.6.2
- os: linux - os: linux
dist: trusty dist: trusty
go: 1.7 go: 1.7.4
- os: osx - os: osx
go: 1.7 go: 1.7.4
# This builder does the Ubuntu PPA and Linux Azure uploads # This builder does the Ubuntu PPA and Linux Azure uploads
- os: linux - os: linux
dist: trusty dist: trusty
sudo: required sudo: required
go: 1.7 go: 1.7.4
env: env:
- ubuntu-ppa - ubuntu-ppa
- azure-linux - azure-linux
@ -55,7 +55,7 @@ matrix:
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads # This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
- os: osx - os: osx
go: 1.7 go: 1.7.4
env: env:
- azure-osx - azure-osx
- mobile - mobile
@ -90,7 +90,7 @@ install:
- go get golang.org/x/tools/cmd/cover - go get golang.org/x/tools/cmd/cover
script: script:
- go run build/ci.go install - go run build/ci.go install
- go run build/ci.go test -coverage -vet - go run build/ci.go test -coverage -vet -misspell
notifications: notifications:
webhooks: webhooks:

View file

@ -39,9 +39,7 @@ The go-ubiq project comes with several wrappers/executables found in the `cmd` d
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). | | `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow insolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug`). |
| `gubiqrpctest` | Developer utility tool to support our [ubiq/rpc-test](https://github.com/ubiq/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ubiq/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ubiq/rpc-tests/blob/master/README.md) for details. | | `gubiqrpctest` | Developer utility tool to support our [ubiq/rpc-test](https://github.com/ubiq/rpc-tests) test suite which validates baseline conformity to the [Ethereum JSON RPC](https://github.com/ubiq/wiki/wiki/JSON-RPC) specs. Please see the [test suite's readme](https://github.com/ubiq/rpc-tests/blob/master/README.md) for details. |
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ubiq/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). | | `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://github.com/ubiq/wiki/wiki/RLP)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
| `bzzd` | swarm daemon. This is the entrypoint for the swarm network. `bzzd --help` for command line options. See https://swarm-guide.readthedocs.io for swarm documentation. | | `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. |
| `bzzup` | swarm command line file uploader. `bzzup --help` for command line options |
| `bzzhash` | command to calculate the swarm hash of a file or directory. `bzzhash --help` for command line options |
## Running gubiq ## Running gubiq

View file

@ -1 +1 @@
1.5.5 1.5.7

View file

@ -91,8 +91,30 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
// first we need to create a slice of the type // first we need to create a slice of the type
var refSlice reflect.Value var refSlice reflect.Value
switch elem.T { switch elem.T {
case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int. case IntTy, UintTy, BoolTy:
// 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)) refSlice = reflect.ValueOf([]*big.Int(nil))
}
case AddressTy: // address must be of slice Address case AddressTy: // address must be of slice Address
refSlice = reflect.ValueOf([]common.Address(nil)) refSlice = reflect.ValueOf([]common.Address(nil))
case HashTy: // hash must be of slice hash case HashTy: // hash must be of slice hash
@ -147,7 +169,27 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
// set inter to the correct type (cast) // set inter to the correct type (cast)
switch elem.T { switch elem.T {
case IntTy, UintTy: case IntTy, UintTy:
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) inter = common.BytesToBig(returnOutput)
}
case BoolTy: case BoolTy:
inter = common.BytesToBig(returnOutput).Uint64() > 0 inter = common.BytesToBig(returnOutput).Uint64() > 0
case AddressTy: case AddressTy:
@ -169,7 +211,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) {
// argument in T. // argument in T.
func toGoType(i int, t Argument, output []byte) (interface{}, error) { func toGoType(i int, t Argument, output []byte) (interface{}, error) {
// we need to treat slices differently // we need to treat slices differently
if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy { if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy {
return toGoSlice(i, t, output) return toGoSlice(i, t, output)
} }
@ -233,7 +275,7 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) {
return common.BytesToAddress(returnOutput), nil return common.BytesToAddress(returnOutput), nil
case HashTy: case HashTy:
return common.BytesToHash(returnOutput), nil return common.BytesToHash(returnOutput), nil
case BytesTy, FixedBytesTy: case BytesTy, FixedBytesTy, FunctionTy:
return returnOutput, nil return returnOutput, nil
case StringTy: case StringTy:
return string(returnOutput), nil return string(returnOutput), nil
@ -349,6 +391,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
Name string Name string
Constant bool Constant bool
Indexed bool Indexed bool
Anonymous bool
Inputs []Argument Inputs []Argument
Outputs []Argument Outputs []Argument
} }
@ -376,6 +419,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
case "event": case "event":
abi.Events[field.Name] = Event{ abi.Events[field.Name] = Event{
Name: field.Name, Name: field.Name,
Anonymous: field.Anonymous,
Inputs: field.Inputs, Inputs: field.Inputs,
} }
} }

View file

@ -67,10 +67,10 @@ func TestTypeCheck(t *testing.T) {
{"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, {"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
{"uint16[3]", []uint16{1, 2, 3}, ""}, {"uint16[3]", []uint16{1, 2, 3}, ""},
{"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, {"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
{"address[]", []common.Address{common.Address{1}}, ""}, {"address[]", []common.Address{{1}}, ""},
{"address[1]", []common.Address{common.Address{1}}, ""}, {"address[1]", []common.Address{{1}}, ""},
{"address[1]", [1]common.Address{common.Address{1}}, ""}, {"address[1]", [1]common.Address{{1}}, ""},
{"address[2]", [1]common.Address{common.Address{1}}, "abi: cannot use [1]array as type [2]array as argument"}, {"address[2]", [1]common.Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"},
{"bytes32", [32]byte{}, ""}, {"bytes32", [32]byte{}, ""},
{"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"}, {"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"},
{"bytes32", common.Hash{1}, ""}, {"bytes32", common.Hash{1}, ""},
@ -80,7 +80,8 @@ func TestTypeCheck(t *testing.T) {
{"bytes", [2]byte{0, 1}, ""}, {"bytes", [2]byte{0, 1}, ""},
{"bytes", common.Hash{1}, ""}, {"bytes", common.Hash{1}, ""},
{"string", "hello world", ""}, {"string", "hello world", ""},
{"bytes32[]", [][32]byte{[32]byte{}}, ""}, {"bytes32[]", [][32]byte{{}}, ""},
{"function", [24]byte{}, ""},
} { } {
typ, err := NewType(test.typ) typ, err := NewType(test.typ)
if err != nil { if err != nil {
@ -197,6 +198,13 @@ func TestSimpleMethodUnpack(t *testing.T) {
"interface", "interface",
"", "",
}, },
{
`[ { "type": "function" } ]`,
pad([]byte{1}, 32, false),
[24]byte{1},
"function",
"",
},
} { } {
abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(abiDefinition)) abi, err := JSON(strings.NewReader(abiDefinition))
@ -255,6 +263,10 @@ func TestSimpleMethodUnpack(t *testing.T) {
var v common.Hash var v common.Hash
err = abi.Unpack(&v, "method", test.marshalledOutput) err = abi.Unpack(&v, "method", test.marshalledOutput)
outvar = v outvar = v
case "function":
var v [24]byte
err = abi.Unpack(&v, "method", test.marshalledOutput)
outvar = v
case "interface": case "interface":
err = abi.Unpack(&outvar, "method", test.marshalledOutput) err = abi.Unpack(&outvar, "method", test.marshalledOutput)
default: default:
@ -320,6 +332,30 @@ func TestUnpackSetInterfaceSlice(t *testing.T) {
} }
} }
func TestUnpackSetInterfaceArrayOutput(t *testing.T) {
var (
var1 = new([1]uint32)
var2 = new([1]uint32)
)
out := []interface{}{var1, var2}
abi, err := JSON(strings.NewReader(`[{"type":"function", "name":"ints", "outputs":[{"type":"uint32[1]"}, {"type":"uint32[1]"}]}]`))
if err != nil {
t.Fatal(err)
}
marshalledReturn := append(pad([]byte{1}, 32, true), pad([]byte{2}, 32, true)...)
err = abi.Unpack(&out, "ints", marshalledReturn)
if err != nil {
t.Fatal(err)
}
if *var1 != [1]uint32{1} {
t.Error("expected var1 to be [1], got", *var1)
}
if *var2 != [1]uint32{2} {
t.Error("expected var2 to be [2], got", *var2)
}
}
func TestPack(t *testing.T) { func TestPack(t *testing.T) {
for i, test := range []struct { for i, test := range []struct {
typ string typ string
@ -331,8 +367,9 @@ func TestPack(t *testing.T) {
{"uint16[]", []uint16{1, 2}, formatSliceOutput([]byte{1}, []byte{2})}, {"uint16[]", []uint16{1, 2}, formatSliceOutput([]byte{1}, []byte{2})},
{"bytes20", [20]byte{1}, pad([]byte{1}, 32, false)}, {"bytes20", [20]byte{1}, pad([]byte{1}, 32, false)},
{"uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, formatSliceOutput([]byte{1}, []byte{2})}, {"uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, formatSliceOutput([]byte{1}, []byte{2})},
{"address[]", []common.Address{common.Address{1}, common.Address{2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, false))}, {"address[]", []common.Address{{1}, {2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, false))},
{"bytes32[]", []common.Hash{common.Hash{1}, common.Hash{2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))}, {"bytes32[]", []common.Hash{{1}, {2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))},
{"function", [24]byte{1}, pad([]byte{1}, 32, false)},
} { } {
typ, err := NewType(test.typ) typ, err := NewType(test.typ)
if err != nil { if err != nil {
@ -445,12 +482,12 @@ func TestReader(t *testing.T) {
Uint256, _ := NewType("uint256") Uint256, _ := NewType("uint256")
exp := ABI{ exp := ABI{
Methods: map[string]Method{ Methods: map[string]Method{
"balance": Method{ "balance": {
"balance", true, nil, nil, "balance", true, nil, nil,
}, },
"send": Method{ "send": {
"send", false, []Argument{ "send", false, []Argument{
Argument{"amount", Uint256, false}, {"amount", Uint256, false},
}, nil, }, nil,
}, },
}, },
@ -549,7 +586,7 @@ func TestTestSlice(t *testing.T) {
func TestMethodSignature(t *testing.T) { func TestMethodSignature(t *testing.T) {
String, _ := NewType("string") String, _ := NewType("string")
m := Method{"foo", false, []Argument{Argument{"bar", String, false}, Argument{"baz", String, false}}, nil} m := Method{"foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil}
exp := "foo(string,string)" exp := "foo(string,string)"
if m.Sig() != exp { if m.Sig() != exp {
t.Error("signature mismatch", exp, "!=", m.Sig()) t.Error("signature mismatch", exp, "!=", m.Sig())
@ -561,7 +598,7 @@ func TestMethodSignature(t *testing.T) {
} }
uintt, _ := NewType("uint") uintt, _ := NewType("uint")
m = Method{"foo", false, []Argument{Argument{"bar", uintt, false}}, nil} m = Method{"foo", false, []Argument{{"bar", uintt, false}}, nil}
exp = "foo(uint256)" exp = "foo(uint256)"
if m.Sig() != exp { if m.Sig() != exp {
t.Error("signature mismatch", exp, "!=", m.Sig()) t.Error("signature mismatch", exp, "!=", m.Sig())
@ -752,23 +789,58 @@ func TestDefaultFunctionParsing(t *testing.T) {
func TestBareEvents(t *testing.T) { func TestBareEvents(t *testing.T) {
const definition = `[ const definition = `[
{ "type" : "event", "name" : "balance" }, { "type" : "event", "name" : "balance" },
{ "type" : "event", "name" : "name" }]` { "type" : "event", "name" : "anon", "anonymous" : true},
{ "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] }
]`
arg0, _ := NewType("uint256")
arg1, _ := NewType("address")
expectedEvents := map[string]struct {
Anonymous bool
Args []Argument
}{
"balance": {false, nil},
"anon": {true, nil},
"args": {false, []Argument{
{Name: "arg0", Type: arg0, Indexed: false},
{Name: "arg1", Type: arg1, Indexed: true},
}},
}
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(abi.Events) != 2 { if len(abi.Events) != len(expectedEvents) {
t.Error("expected 2 events") t.Fatalf("invalid number of events after parsing, want %d, got %d", len(expectedEvents), len(abi.Events))
} }
if _, ok := abi.Events["balance"]; !ok { for name, exp := range expectedEvents {
t.Error("expected 'balance' event to be present") got, ok := abi.Events[name]
if !ok {
t.Errorf("could not found event %s", name)
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)
}
} }
if _, ok := abi.Events["name"]; !ok {
t.Error("expected 'name' event to be present")
} }
} }

View file

@ -33,6 +33,7 @@ func (a *Argument) UnmarshalJSON(data []byte) error {
var extarg struct { var extarg struct {
Name string Name string
Type string Type string
Indexed bool
} }
err := json.Unmarshal(data, &extarg) err := json.Unmarshal(data, &extarg)
if err != nil { if err != nil {
@ -44,6 +45,7 @@ func (a *Argument) UnmarshalJSON(data []byte) error {
return err return err
} }
a.Name = extarg.Name a.Name = extarg.Name
a.Indexed = extarg.Indexed
return nil return nil
} }

View file

@ -52,7 +52,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
if address != keyAddr { if address != keyAddr {
return nil, errors.New("not authorized to sign this account") return nil, errors.New("not authorized to sign this account")
} }
signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key) signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -225,7 +225,11 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
from.SetBalance(common.MaxBig) from.SetBalance(common.MaxBig)
// Execute the call. // Execute the call.
msg := callmsg{call} msg := callmsg{call}
vmenv := core.NewEnv(statedb, chainConfig, b.blockchain, msg, block.Header(), vm.Config{})
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{})
gaspool := new(core.GasPool).AddGas(common.MaxBig) gaspool := new(core.GasPool).AddGas(common.MaxBig)
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
return ret, gasUsed, err return ret, gasUsed, err

View file

@ -170,7 +170,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
if value == nil { if value == nil {
value = new(big.Int) value = new(big.Int)
} }
nonce := uint64(0) var nonce uint64
if opts.Nonce == nil { if opts.Nonce == nil {
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From) nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
if err != nil { if err != nil {

View file

@ -147,21 +147,21 @@ func bindTypeGo(kind abi.Type) string {
switch { switch {
case strings.HasPrefix(stringKind, "address"): case strings.HasPrefix(stringKind, "address"):
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 2 { if len(parts) != 2 {
return stringKind return stringKind
} }
return fmt.Sprintf("%scommon.Address", parts[1]) return fmt.Sprintf("%scommon.Address", parts[1])
case strings.HasPrefix(stringKind, "bytes"): case strings.HasPrefix(stringKind, "bytes"):
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 3 { if len(parts) != 3 {
return stringKind return stringKind
} }
return fmt.Sprintf("%s[%s]byte", parts[2], parts[1]) return fmt.Sprintf("%s[%s]byte", parts[2], parts[1])
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 4 { if len(parts) != 4 {
return stringKind return stringKind
} }
@ -172,7 +172,7 @@ func bindTypeGo(kind abi.Type) string {
return fmt.Sprintf("%s*big.Int", parts[3]) return fmt.Sprintf("%s*big.Int", parts[3])
case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"): case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"):
parts := regexp.MustCompile("([a-z]+)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`([a-z]+)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 3 { if len(parts) != 3 {
return stringKind return stringKind
} }
@ -191,7 +191,7 @@ func bindTypeJava(kind abi.Type) string {
switch { switch {
case strings.HasPrefix(stringKind, "address"): case strings.HasPrefix(stringKind, "address"):
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 2 { if len(parts) != 2 {
return stringKind return stringKind
} }
@ -201,7 +201,7 @@ func bindTypeJava(kind abi.Type) string {
return fmt.Sprintf("Addresses") return fmt.Sprintf("Addresses")
case strings.HasPrefix(stringKind, "bytes"): case strings.HasPrefix(stringKind, "bytes"):
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 3 { if len(parts) != 3 {
return stringKind return stringKind
} }
@ -211,7 +211,7 @@ func bindTypeJava(kind abi.Type) string {
return "byte[]" return "byte[]"
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 4 { if len(parts) != 4 {
return stringKind return stringKind
} }
@ -230,7 +230,7 @@ func bindTypeJava(kind abi.Type) string {
return fmt.Sprintf("BigInts") return fmt.Sprintf("BigInts")
case strings.HasPrefix(stringKind, "bool"): case strings.HasPrefix(stringKind, "bool"):
parts := regexp.MustCompile("bool(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`bool(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 2 { if len(parts) != 2 {
return stringKind return stringKind
} }
@ -240,7 +240,7 @@ func bindTypeJava(kind abi.Type) string {
return fmt.Sprintf("bool[]") return fmt.Sprintf("bool[]")
case strings.HasPrefix(stringKind, "string"): case strings.HasPrefix(stringKind, "string"):
parts := regexp.MustCompile("string(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) parts := regexp.MustCompile(`string(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 2 { if len(parts) != 2 {
return stringKind return stringKind
} }
@ -278,7 +278,7 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
case "bool[]": case "bool[]":
return "Bools" return "Bools"
case "BigInt": case "BigInt":
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(solKind.String()) parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String())
if len(parts) != 4 { if len(parts) != 4 {
return javaKind return javaKind
} }

View file

@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) {
// Create the transaction. // Create the transaction.
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
// Wait for it to get mined in the background. // Wait for it to get mined in the background.
var ( var (

View file

@ -25,9 +25,11 @@ import (
) )
// Event is an event potentially triggered by the EVM's LOG mechanism. The Event // Event is an event potentially triggered by the EVM's LOG mechanism. The Event
// holds type information (inputs) about the yielded output // holds type information (inputs) about the yielded output. Anonymous events
// don't get the signature canonical representation as the first LOG topic.
type Event struct { type Event struct {
Name string Name string
Anonymous bool
Inputs []Argument Inputs []Argument
} }

View file

@ -54,7 +54,7 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
reflectValue = mustArrayToByteSlice(reflectValue) reflectValue = mustArrayToByteSlice(reflectValue)
} }
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()) return packBytesSlice(reflectValue.Bytes(), reflectValue.Len())
case FixedBytesTy: case FixedBytesTy, FunctionTy:
if reflectValue.Kind() == reflect.Array { if reflectValue.Kind() == reflect.Array {
reflectValue = mustArrayToByteSlice(reflectValue) reflectValue = mustArrayToByteSlice(reflectValue)
} }

View file

@ -33,7 +33,8 @@ const (
FixedBytesTy FixedBytesTy
BytesTy BytesTy
HashTy HashTy
RealTy FixedpointTy
FunctionTy
) )
// Type is the reflection of the supported argument type // Type is the reflection of the supported argument type
@ -57,16 +58,16 @@ var (
// Types can be in the format of: // Types can be in the format of:
// //
// Input = Type [ "[" [ Number ] "]" ] Name . // Input = Type [ "[" [ Number ] "]" ] Name .
// Type = [ "u" ] "int" [ Number ] . // Type = [ "u" ] "int" [ Number ] [ x ] [ Number ].
// //
// Examples: // Examples:
// //
// string int uint real // string int uint fixed
// string32 int8 uint8 uint[] // string32 int8 uint8 uint[]
// address int256 uint256 real[2] // address int256 uint256 fixed128x128[2]
fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?") fullTypeRegex = regexp.MustCompile(`([a-zA-Z0-9]+)(\[([0-9]*)\])?`)
// typeRegex parses the abi sub types // typeRegex parses the abi sub types
typeRegex = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?") typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
) )
// NewType creates a new reflection type of abi type given in t. // NewType creates a new reflection type of abi type given in t.
@ -90,14 +91,19 @@ func NewType(t string) (typ Type, err error) {
} }
typ.Elem = &sliceType typ.Elem = &sliceType
typ.stringKind = sliceType.stringKind + t[len(res[1]):] typ.stringKind = sliceType.stringKind + t[len(res[1]):]
// 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 return typ, nil
} }
}
// parse the type and size of the abi-type. // parse the type and size of the abi-type.
parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0] parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0]
// varSize is the size of the variable // varSize is the size of the variable
var varSize int var varSize int
if len(parsedType[2]) > 0 { if len(parsedType[3]) > 0 {
var err error var err error
varSize, err = strconv.Atoi(parsedType[2]) varSize, err = strconv.Atoi(parsedType[2])
if err != nil { if err != nil {
@ -111,7 +117,12 @@ func NewType(t string) (typ Type, err error) {
varSize = 256 varSize = 256
t += "256" t += "256"
} }
// 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 typ.stringKind = t
}
switch varType { switch varType {
case "int": case "int":
@ -148,6 +159,12 @@ func NewType(t string) (typ Type, err error) {
typ.T = FixedBytesTy typ.T = FixedBytesTy
typ.SliceSize = varSize typ.SliceSize = varSize
} }
case "function":
sliceType, _ := NewType("uint8")
typ.Elem = &sliceType
typ.IsArray = true
typ.T = FunctionTy
typ.SliceSize = 24
default: default:
return Type{}, fmt.Errorf("unsupported arg type: %s", t) return Type{}, fmt.Errorf("unsupported arg type: %s", t)
} }
@ -168,7 +185,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
return nil, err return nil, err
} }
if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy { if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy {
var packed []byte var packed []byte
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {

78
accounts/abi/type_test.go Normal file
View 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))
}
}
}

View file

@ -136,13 +136,12 @@ func (am *Manager) DeleteAccount(a Account, passphrase string) error {
return err return err
} }
// Sign calculates a ECDSA signature for the given hash. // Sign calculates a ECDSA signature for the given hash. The produced signature
// Note, Ethereum signatures have a particular format as described in the // is in the [R || S || V] format where V is 0 or 1.
// yellow paper. Use the SignEthereum function to calculate a signature
// in Ethereum format.
func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) { func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
am.mu.RLock() am.mu.RLock()
defer am.mu.RUnlock() defer am.mu.RUnlock()
unlockedKey, found := am.unlocked[addr] unlockedKey, found := am.unlocked[addr]
if !found { if !found {
return nil, ErrLocked return nil, ErrLocked
@ -150,28 +149,16 @@ func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) {
return crypto.Sign(hash, unlockedKey.PrivateKey) return crypto.Sign(hash, unlockedKey.PrivateKey)
} }
// SignEthereum calculates a ECDSA signature for the given hash. // SignWithPassphrase signs hash if the private key matching the given address
// The signature has the format as described in the Ethereum yellow paper. // can be decrypted with the given passphrase. The produced signature is in the
func (am *Manager) SignEthereum(addr common.Address, hash []byte) ([]byte, error) { // [R || S || V] format where V is 0 or 1.
am.mu.RLock() func (am *Manager) SignWithPassphrase(a Account, passphrase string, hash []byte) (signature []byte, err error) {
defer am.mu.RUnlock() _, key, err := am.getDecryptedKey(a, passphrase)
unlockedKey, found := am.unlocked[addr]
if !found {
return nil, ErrLocked
}
return crypto.SignEthereum(hash, unlockedKey.PrivateKey)
}
// SignWithPassphrase signs hash if the private key matching the given
// address can be decrypted with the given passphrase.
func (am *Manager) SignWithPassphrase(addr common.Address, passphrase string, hash []byte) (signature []byte, err error) {
_, key, err := am.getDecryptedKey(Account{Address: addr}, passphrase)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer zeroKey(key.PrivateKey) defer zeroKey(key.PrivateKey)
return crypto.SignEthereum(hash, key.PrivateKey) return crypto.Sign(hash, key.PrivateKey)
} }
// Unlock unlocks the given account indefinitely. // Unlock unlocks the given account indefinitely.

View file

@ -95,7 +95,7 @@ func TestSignWithPassphrase(t *testing.T) {
t.Fatal("expected account to be locked") t.Fatal("expected account to be locked")
} }
_, err = am.SignWithPassphrase(acc.Address, pass, testSigData) _, err = am.SignWithPassphrase(acc, pass, testSigData)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -104,7 +104,7 @@ func TestSignWithPassphrase(t *testing.T) {
t.Fatal("expected account to be locked") t.Fatal("expected account to be locked")
} }
if _, err = am.SignWithPassphrase(acc.Address, "invalid passwd", testSigData); err == nil { if _, err = am.SignWithPassphrase(acc, "invalid passwd", testSigData); err == nil {
t.Fatal("expected SignHash to fail with invalid password") t.Fatal("expected SignHash to fail with invalid password")
} }
} }
@ -115,6 +115,9 @@ func TestTimedUnlock(t *testing.T) {
pass := "foo" pass := "foo"
a1, err := am.NewAccount(pass) a1, err := am.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
// Signing without passphrase fails because account is locked // Signing without passphrase fails because account is locked
_, err = am.Sign(a1.Address, testSigData) _, err = am.Sign(a1.Address, testSigData)
@ -147,6 +150,9 @@ func TestOverrideUnlock(t *testing.T) {
pass := "foo" pass := "foo"
a1, err := am.NewAccount(pass) a1, err := am.NewAccount(pass)
if err != nil {
t.Fatal(err)
}
// Unlock indefinitely. // Unlock indefinitely.
if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil { if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil {

View file

@ -22,6 +22,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/crypto"
@ -53,6 +54,9 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
return nil, err return nil, err
} }
encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed) encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed)
if err != nil {
return nil, errors.New("invalid hex in encSeed")
}
iv := encSeedBytes[:16] iv := encSeedBytes[:16]
cipherText := encSeedBytes[16:] cipherText := encSeedBytes[16:]
/* /*

View file

@ -22,8 +22,8 @@ environment:
install: install:
- rmdir C:\go /s /q - rmdir C:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.3.windows-%GETH_ARCH%.zip - appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.4.windows-%GETH_ARCH%.zip
- 7z x go1.7.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL - 7z x go1.7.4.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- go version - go version
- gcc --version - gcc --version

View file

@ -24,7 +24,7 @@ Usage: go run ci.go <command> <command flags/arguments>
Available commands are: Available commands are:
install [-arch architecture] [ packages... ] -- builds packages and executables install [-arch architecture] [ packages... ] -- builds packages and executables
test [ -coverage ] [ -vet ] [ packages... ] -- runs the tests test [ -coverage ] [ -vet ] [ -misspell ] [ packages... ] -- runs the tests
archive [-arch architecture] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts archive [-arch architecture] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts
importkeys -- imports signing keys from env importkeys -- imports signing keys from env
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
@ -72,9 +72,7 @@ var (
executablePath("abigen"), executablePath("abigen"),
executablePath("evm"), executablePath("evm"),
executablePath("gubiq"), executablePath("gubiq"),
executablePath("bzzd"), executablePath("swarm"),
executablePath("bzzhash"),
executablePath("bzzup"),
executablePath("rlpdump"), executablePath("rlpdump"),
} }
@ -93,16 +91,8 @@ var (
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.", Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
}, },
{ {
Name: "bzzd", Name: "swarm",
Description: "Ethereum Swarm daemon", Description: "Ethereum Swarm daemon and tools",
},
{
Name: "bzzup",
Description: "Ethereum Swarm command line file/directory uploader",
},
{
Name: "bzzhash",
Description: "Ethereum Swarm file/directory hash calculator",
}, },
{ {
Name: "abigen", Name: "abigen",
@ -112,7 +102,8 @@ var (
// Distros for which packages are created. // Distros for which packages are created.
// Note: vivid is unsupported because there is no golang-1.6 package for it. // Note: vivid is unsupported because there is no golang-1.6 package for it.
debDistros = []string{"trusty", "wily", "xenial", "yakkety"} // Note: wily is unsupported because it was officially deprecated on lanchpad.
debDistros = []string{"trusty", "xenial", "yakkety"}
) )
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@ -204,7 +195,7 @@ func doInstall(cmdline []string) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
for name, _ := range pkgs { for name := range pkgs {
if name == "main" { if name == "main" {
gobuild := goToolArch(*arch, "build", buildFlags(env)...) gobuild := goToolArch(*arch, "build", buildFlags(env)...)
gobuild.Args = append(gobuild.Args, "-v") gobuild.Args = append(gobuild.Args, "-v")
@ -271,6 +262,7 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd {
func doTest(cmdline []string) { func doTest(cmdline []string) {
var ( var (
vet = flag.Bool("vet", false, "Whether to run go vet") vet = flag.Bool("vet", false, "Whether to run go vet")
misspell = flag.Bool("misspell", false, "Whether to run the spell checker")
coverage = flag.Bool("coverage", false, "Whether to record code coverage") coverage = flag.Bool("coverage", false, "Whether to record code coverage")
) )
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)
@ -296,7 +288,9 @@ func doTest(cmdline []string) {
if *vet { if *vet {
build.MustRun(goTool("vet", packages...)) build.MustRun(goTool("vet", packages...))
} }
if *misspell {
spellcheck(packages)
}
// Run the actual tests. // Run the actual tests.
gotest := goTool("test") gotest := goTool("test")
// Test a single package at a time. CI builders are slow // Test a single package at a time. CI builders are slow
@ -309,6 +303,34 @@ func doTest(cmdline []string) {
build.MustRun(gotest) build.MustRun(gotest)
} }
// spellcheck runs the client9/misspell spellchecker package on all Go, Cgo and
// test files in the requested packages.
func spellcheck(packages []string) {
// Ensure the spellchecker is available
build.MustRun(goTool("get", "github.com/client9/misspell/cmd/misspell"))
// Windows chokes on long argument lists, check packages individualy
for _, pkg := range packages {
// The spell checker doesn't work on packages, gather all .go files for it
out, err := goTool("list", "-f", "{{.Dir}}{{range .GoFiles}}\n{{.}}{{end}}{{range .CgoFiles}}\n{{.}}{{end}}{{range .TestGoFiles}}\n{{.}}{{end}}", pkg).CombinedOutput()
if err != nil {
log.Fatalf("source file listing failed: %v\n%s", err, string(out))
}
// Retrieve the folder and assemble the source list
lines := strings.Split(string(out), "\n")
root := lines[0]
sources := make([]string, 0, len(lines)-1)
for _, line := range lines[1:] {
if line = strings.TrimSpace(line); line != "" {
sources = append(sources, filepath.Join(root, line))
}
}
// Run the spell checker for this particular package
build.MustRunCommand(filepath.Join(GOBIN, "misspell"), append([]string{"-error"}, sources...)...)
}
}
// Release Packaging // Release Packaging
func doArchive(cmdline []string) { func doArchive(cmdline []string) {
@ -638,6 +660,7 @@ func doWindowsInstaller(cmdline []string) {
build.Render("build/nsis.gubiq.nsi", filepath.Join(*workdir, "gubiq.nsi"), 0644, nil) build.Render("build/nsis.gubiq.nsi", filepath.Join(*workdir, "gubiq.nsi"), 0644, nil)
build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData) build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData)
build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools) build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools)
build.Render("build/nsis.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.nsh"), 0644, nil)
build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil) build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil)
build.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll", 0755) build.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll", 0755)
build.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING", 0755) build.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING", 0755)
@ -800,7 +823,7 @@ func doXCodeFramework(cmdline []string) {
// Build the iOS XCode framework // Build the iOS XCode framework
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile")) build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
build.MustRun(gomobileTool("init")) build.MustRun(gomobileTool("init"))
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "--prefix", "GE", "-v", "github.com/ubiq/go-ubiq/mobile") bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ubiq/go-ubiq/mobile")
if *local { if *local {
// If we're building locally, use the build folder and stop afterwards // If we're building locally, use the build folder and stop afterwards

View file

@ -17,8 +17,12 @@
# #
# Requirements: # Requirements:
# - NSIS, http://nsis.sourceforge.net/Main_Page # - NSIS, http://nsis.sourceforge.net/Main_Page
# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi) # - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
# #
# After intalling NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the
# files found in Stub.
#
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller # based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller
# #
# TODO: # TODO:
@ -37,6 +41,7 @@ RequestExecutionLevel admin
SetCompressor /SOLID lzma SetCompressor /SOLID lzma
!include LogicLib.nsh !include LogicLib.nsh
!include PathUpdate.nsh
!include EnvVarUpdate.nsh !include EnvVarUpdate.nsh
!macro VerifyUserIsAdmin !macro VerifyUserIsAdmin

View file

@ -37,8 +37,9 @@ Section "Gubiq" GETH_IDX
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc" ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc"
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\gubiq.ipc" ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\gubiq.ipc"
# Add gubiq to PATH # Add instdir to PATH
${EnvVarUpdate} $0 "PATH" "A" "HKLM" $INSTDIR Push "$INSTDIR"
Call AddToPath
SectionEnd SectionEnd
# Install optional develop tools. # Install optional develop tools.

153
build/nsis.pathupdate.nsh Normal file
View 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

View file

@ -25,7 +25,8 @@ Section "Uninstall"
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc" ${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc"
# Remove install directory from PATH # Remove install directory from PATH
${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" $INSTDIR Push "$INSTDIR"
Call un.RemoveFromPath
# Cleanup registry (deletes all sub keys) # Cleanup registry (deletes all sub keys)
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}"

View file

@ -185,7 +185,7 @@ func getFiles() []string {
files = append(files, line) files = append(files, line)
}) })
if err != nil { if err != nil {
log.Fatalf("error getting files:", err) log.Fatal("error getting files:", err)
} }
return files return files
} }
@ -294,7 +294,7 @@ func getInfo(files <-chan string, out chan<- *info, wg *sync.WaitGroup) {
wg.Done() wg.Done()
} }
// fileInfo finds the lowest year in which the given file was commited. // fileInfo finds the lowest year in which the given file was committed.
func fileInfo(file string) (*info, error) { func fileInfo(file string) (*info, error) {
info := &info{file: file, Year: int64(time.Now().Year())} info := &info{file: file, Year: int64(time.Now().Year())}
cmd := exec.Command("git", "log", "--follow", "--find-renames=80", "--find-copies=80", "--pretty=format:%ai", "--", file) cmd := exec.Command("git", "log", "--follow", "--find-renames=80", "--find-copies=80", "--pretty=format:%ai", "--", file)

View 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
}

View file

@ -18,11 +18,12 @@
package main package main
import ( import (
"encoding/hex"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/core/vm"
) )
@ -32,20 +33,28 @@ func main() {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
code = common.Hex2Bytes(string(code[:len(code)-1])) code, err = hex.DecodeString(strings.TrimSpace(string(code[:])))
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("%x\n", code) fmt.Printf("%x\n", code)
for pc := uint64(0); pc < uint64(len(code)); pc++ { for pc := uint64(0); pc < uint64(len(code)); pc++ {
op := vm.OpCode(code[pc]) op := vm.OpCode(code[pc])
fmt.Printf("%-5d %v", pc, op)
switch op { switch op {
case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8, vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15, vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22, vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29, vm.PUSH30, vm.PUSH31, vm.PUSH32: case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8, vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15, vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22, vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29, vm.PUSH30, vm.PUSH31, vm.PUSH32:
a := uint64(op) - uint64(vm.PUSH1) + 1 a := uint64(op) - uint64(vm.PUSH1) + 1
fmt.Printf(" => %x", code[pc+1:pc+1+a]) u := pc + 1 + a
if uint64(len(code)) <= pc || uint64(len(code)) < u {
pc += a 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()
} }
} }

View file

@ -88,12 +88,7 @@ func runTestWithReader(test string, r io.Reader) error {
default: default:
err = fmt.Errorf("Invalid test type specified: %v", test) err = fmt.Errorf("Invalid test type specified: %v", test)
} }
if err != nil {
return err return err
}
return nil
} }
func getFiles(path string) ([]string, error) { func getFiles(path string) ([]string, error) {

View file

@ -20,21 +20,18 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
"os" "os"
"runtime" goruntime "runtime"
"time" "time"
"github.com/ubiq/go-ubiq/cmd/utils" "github.com/ubiq/go-ubiq/cmd/utils"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core"
"github.com/ubiq/go-ubiq/core/state" "github.com/ubiq/go-ubiq/core/state"
"github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/core/vm"
"github.com/ubiq/go-ubiq/core/vm/runtime"
"github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/crypto"
"github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/ethdb"
"github.com/ubiq/go-ubiq/logger/glog" "github.com/ubiq/go-ubiq/logger/glog"
"github.com/ubiq/go-ubiq/params"
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
@ -47,14 +44,6 @@ var (
Name: "debug", Name: "debug",
Usage: "output full trace logs", Usage: "output full trace logs",
} }
ForceJitFlag = cli.BoolFlag{
Name: "forcejit",
Usage: "forces jit compilation",
}
DisableJitFlag = cli.BoolFlag{
Name: "nojit",
Usage: "disabled jit compilation",
}
CodeFlag = cli.StringFlag{ CodeFlag = cli.StringFlag{
Name: "code", Name: "code",
Usage: "EVM code", Usage: "EVM code",
@ -98,6 +87,10 @@ var (
Name: "create", Name: "create",
Usage: "indicates the action should be create rather than call", Usage: "indicates the action should be create rather than call",
} }
DisableGasMeteringFlag = cli.BoolFlag{
Name: "nogasmetering",
Usage: "disable gas metering",
}
) )
func init() { func init() {
@ -105,8 +98,6 @@ func init() {
CreateFlag, CreateFlag,
DebugFlag, DebugFlag,
VerbosityFlag, VerbosityFlag,
ForceJitFlag,
DisableJitFlag,
SysStatFlag, SysStatFlag,
CodeFlag, CodeFlag,
CodeFileFlag, CodeFileFlag,
@ -115,6 +106,7 @@ func init() {
ValueFlag, ValueFlag,
DumpFlag, DumpFlag,
InputFlag, InputFlag,
DisableGasMeteringFlag,
} }
app.Action = run app.Action = run
} }
@ -129,13 +121,6 @@ func run(ctx *cli.Context) error {
logger := vm.NewStructLogger(nil) logger := vm.NewStructLogger(nil)
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name)), vm.Config{
Debug: ctx.GlobalBool(DebugFlag.Name),
ForceJit: ctx.GlobalBool(ForceJitFlag.Name),
EnableJit: !ctx.GlobalBool(DisableJitFlag.Name),
Tracer: logger,
})
tstart := time.Now() tstart := time.Now()
var ( var (
@ -168,25 +153,32 @@ func run(ctx *cli.Context) error {
if ctx.GlobalBool(CreateFlag.Name) { if ctx.GlobalBool(CreateFlag.Name) {
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
ret, _, err = vmenv.Create( ret, _, err = runtime.Create(input, &runtime.Config{
sender, Origin: sender.Address(),
input, State: statedb,
common.Big(ctx.GlobalString(GasFlag.Name)), GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
common.Big(ctx.GlobalString(PriceFlag.Name)), GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
common.Big(ctx.GlobalString(ValueFlag.Name)), Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
) EVMConfig: vm.Config{
Tracer: logger,
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
},
})
} else { } else {
receiver := statedb.CreateAccount(common.StringToAddress("receiver")) receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
receiver.SetCode(crypto.Keccak256Hash(code), code) receiver.SetCode(crypto.Keccak256Hash(code), code)
ret, err = vmenv.Call(
sender, ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
receiver.Address(), Origin: sender.Address(),
common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), State: statedb,
common.Big(ctx.GlobalString(GasFlag.Name)), GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)),
common.Big(ctx.GlobalString(PriceFlag.Name)), GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)),
common.Big(ctx.GlobalString(ValueFlag.Name)), Value: common.Big(ctx.GlobalString(ValueFlag.Name)),
) EVMConfig: vm.Config{
Tracer: logger,
DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name),
},
})
} }
vmdone := time.Since(tstart) vmdone := time.Since(tstart)
@ -197,8 +189,8 @@ func run(ctx *cli.Context) error {
vm.StdErrFormat(logger.StructLogs()) vm.StdErrFormat(logger.StructLogs())
if ctx.GlobalBool(SysStatFlag.Name) { if ctx.GlobalBool(SysStatFlag.Name) {
var mem runtime.MemStats var mem goruntime.MemStats
runtime.ReadMemStats(&mem) goruntime.ReadMemStats(&mem)
fmt.Printf("vm took %v\n", vmdone) fmt.Printf("vm took %v\n", vmdone)
fmt.Printf(`alloc: %d fmt.Printf(`alloc: %d
tot alloc: %d tot alloc: %d
@ -223,87 +215,3 @@ func main() {
os.Exit(1) os.Exit(1)
} }
} }
type VMEnv struct {
state *state.StateDB
block *types.Block
transactor *common.Address
value *big.Int
depth int
Gas *big.Int
time *big.Int
logs []vm.StructLog
evm *vm.EVM
}
func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int, cfg vm.Config) *VMEnv {
env := &VMEnv{
state: state,
transactor: &transactor,
value: value,
time: big.NewInt(time.Now().Unix()),
}
env.evm = vm.New(env, cfg)
return env
}
// ruleSet implements vm.ChainConfig and will always default to the homestead rule set.
type ruleSet struct{}
func (ruleSet) IsHomestead(*big.Int) bool { return true }
func (ruleSet) GasTable(*big.Int) params.GasTable {
return params.GasTableHomesteadGasRepriceFork
}
func (self *VMEnv) ChainConfig() *params.ChainConfig { return params.TestChainConfig }
func (self *VMEnv) Vm() vm.Vm { return self.evm }
func (self *VMEnv) Db() vm.Database { return self.state }
func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() }
func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) }
func (self *VMEnv) Origin() common.Address { return *self.transactor }
func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 }
func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
func (self *VMEnv) Time() *big.Int { return self.time }
func (self *VMEnv) Difficulty() *big.Int { return common.Big1 }
func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) }
func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy }
func (self *VMEnv) Depth() int { return 0 }
func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) GetHash(n uint64) common.Hash {
if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
return self.block.Hash()
}
return common.Hash{}
}
func (self *VMEnv) AddLog(log *vm.Log) {
self.state.AddLog(log)
}
func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool {
return self.state.GetBalance(from).Cmp(balance) >= 0
}
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) {
core.Transfer(from, to, amount)
}
func (self *VMEnv) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
self.Gas = gas
return core.Call(self, caller, addr, data, gas, price, value)
}
func (self *VMEnv) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
return core.CallCode(self, caller, addr, data, gas, price, value)
}
func (self *VMEnv) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
return core.DelegateCall(self, caller, addr, data, gas, price)
}
func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
return core.Create(self, caller, data, gas, price, value)
}

View file

@ -148,7 +148,7 @@ Passphrase: {{.InputLine "foobar"}}
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a", "Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
} }
for _, m := range wantMessages { for _, m := range wantMessages {
if strings.Index(gubiq.stderrText(), m) == -1 { if !strings.Contains(gubiq.stderrText(), m) {
t.Errorf("stderr text does not contain %q", m) t.Errorf("stderr text does not contain %q", m)
} }
} }
@ -193,7 +193,7 @@ Passphrase: {{.InputLine "foobar"}}
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc", "Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
} }
for _, m := range wantMessages { for _, m := range wantMessages {
if strings.Index(gubiq.stderrText(), m) == -1 { if !strings.Contains(gubiq.stderrText(), m) {
t.Errorf("stderr text does not contain %q", m) t.Errorf("stderr text does not contain %q", m)
} }
} }
@ -212,7 +212,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
"Unlocked account 289d485d9771714cce91d3393d764e1311907acc", "Unlocked account 289d485d9771714cce91d3393d764e1311907acc",
} }
for _, m := range wantMessages { for _, m := range wantMessages {
if strings.Index(gubiq.stderrText(), m) == -1 { if !strings.Contains(gubiq.stderrText(), m) {
t.Errorf("stderr text does not contain %q", m) t.Errorf("stderr text does not contain %q", m)
} }
} }
@ -260,7 +260,7 @@ In order to avoid this warning, you need to remove the following duplicate key f
"Unlocked account f466859ead1932d743d622cb74fc058882e8648a", "Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
} }
for _, m := range wantMessages { for _, m := range wantMessages {
if strings.Index(gubiq.stderrText(), m) == -1 { if !strings.Contains(gubiq.stderrText(), m) {
t.Errorf("stderr text does not contain %q", m) t.Errorf("stderr text does not contain %q", m)
} }
} }

View file

@ -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);
}

View file

@ -1,46 +0,0 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// Contains a simple library definition to allow creating a Gubiq instance from
// straight C code.
package main
// #ifdef __cplusplus
// extern "C" {
// #endif
//
// extern int run(const char*);
//
// #ifdef __cplusplus
// }
// #endif
import "C"
import (
"fmt"
"os"
"strings"
)
//export doRun
func doRun(args *C.char) C.int {
// This is equivalent to gubiq.main, just modified to handle the function arg passing
if err := app.Run(strings.Split("gubiq "+C.GoString(args), " ")); err != nil {
fmt.Fprintln(os.Stderr, err)
return -1
}
return 0
}

View file

@ -1,56 +0,0 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// Contains specialized code for running Gubiq on Android.
package main
// #include <android/log.h>
// #cgo LDFLAGS: -llog
import "C"
import (
"bufio"
"os"
)
func init() {
// Redirect the standard output and error to logcat
oldStdout, oldStderr := os.Stdout, os.Stderr
outRead, outWrite, _ := os.Pipe()
errRead, errWrite, _ := os.Pipe()
os.Stdout = outWrite
os.Stderr = errWrite
go func() {
scanner := bufio.NewScanner(outRead)
for scanner.Scan() {
line := scanner.Text()
C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stdout"), C.CString(line))
oldStdout.WriteString(line + "\n")
}
}()
go func() {
scanner := bufio.NewScanner(errRead)
for scanner.Scan() {
line := scanner.Text()
C.__android_log_write(C.ANDROID_LOG_INFO, C.CString("Stderr"), C.CString(line))
oldStderr.WriteString(line + "\n")
}
}()
}

View file

@ -88,7 +88,6 @@ func init() {
utils.BootnodesFlag, utils.BootnodesFlag,
utils.DataDirFlag, utils.DataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
utils.OlympicFlag,
utils.FastSyncFlag, utils.FastSyncFlag,
utils.LightModeFlag, utils.LightModeFlag,
utils.LightServFlag, utils.LightServFlag,
@ -168,7 +167,6 @@ func init() {
} }
app.After = func(ctx *cli.Context) error { app.After = func(ctx *cli.Context) error {
logger.Flush()
debug.Exit() debug.Exit()
console.Stdin.Close() // Resets terminal mode. console.Stdin.Close() // Resets terminal mode.
return nil return nil

View file

@ -236,8 +236,9 @@ func expandMetrics(metrics map[string]interface{}, path string) []string {
// fetchMetric iterates over the metrics map and retrieves a specific one. // fetchMetric iterates over the metrics map and retrieves a specific one.
func fetchMetric(metrics map[string]interface{}, metric string) float64 { func fetchMetric(metrics map[string]interface{}, metric string) float64 {
parts, found := strings.Split(metric, "/"), true parts := strings.Split(metric, "/")
for _, part := range parts[:len(parts)-1] { for _, part := range parts[:len(parts)-1] {
var found bool
metrics, found = metrics[part].(map[string]interface{}) metrics, found = metrics[part].(map[string]interface{})
if !found { if !found {
return 0 return 0

View file

@ -67,7 +67,6 @@ var AppHelpFlagGroups = []flagGroup{
utils.DataDirFlag, utils.DataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
utils.NetworkIdFlag, utils.NetworkIdFlag,
utils.OlympicFlag,
utils.TestNetFlag, utils.TestNetFlag,
utils.DevModeFlag, utils.DevModeFlag,
utils.IdentityFlag, utils.IdentityFlag,

View file

@ -19,22 +19,21 @@ package main
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"runtime"
"github.com/ubiq/go-ubiq/swarm/storage" "github.com/ubiq/go-ubiq/swarm/storage"
"gopkg.in/urfave/cli.v1"
) )
func main() { func hash(ctx *cli.Context) {
runtime.GOMAXPROCS(runtime.NumCPU()) args := ctx.Args()
if len(args) < 1 {
if len(os.Args) < 2 { log.Fatal("Usage: swarm hash <file name>")
fmt.Println("Usage: bzzhash <file name>")
os.Exit(0)
} }
f, err := os.Open(os.Args[1]) f, err := os.Open(args[0])
if err != nil { if err != nil {
fmt.Println("Error opening file " + os.Args[1]) fmt.Println("Error opening file " + args[1])
os.Exit(1) os.Exit(1)
} }
@ -42,7 +41,7 @@ func main() {
chunker := storage.NewTreeChunker(storage.NewChunkerParams()) chunker := storage.NewTreeChunker(storage.NewChunkerParams())
key, err := chunker.Split(f, stat.Size(), nil, nil, nil) key, err := chunker.Split(f, stat.Size(), nil, nil, nil)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err) log.Fatalf("%v\n", err)
} else { } else {
fmt.Printf("%v\n", key) fmt.Printf("%v\n", key)
} }

View file

@ -43,11 +43,15 @@ import (
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
const clientIdentifier = "bzzd" const (
clientIdentifier = "swarm"
versionString = "0.2"
)
var ( var (
gitCommit string // Git SHA1 commit hash of the release (set via linker flags) gitCommit string // Git SHA1 commit hash of the release (set via linker flags)
app = utils.NewApp(gitCommit, "Ubiq Swarm server daemon") app = utils.NewApp(gitCommit, "Ubiq Swarm")
testbetBootNodes = []string{}
) )
var ( var (
@ -65,30 +69,49 @@ var (
} }
SwarmNetworkIdFlag = cli.IntFlag{ SwarmNetworkIdFlag = cli.IntFlag{
Name: "bzznetworkid", Name: "bzznetworkid",
Usage: "Network identifier (integer, default 322=swarm testnet)", Usage: "Network identifier (integer, default 3=swarm testnet)",
Value: network.NetworkId, Value: network.NetworkId,
} }
SwarmConfigPathFlag = cli.StringFlag{ SwarmConfigPathFlag = cli.StringFlag{
Name: "bzzconfig", Name: "bzzconfig",
Usage: "Swarm config file path (datadir/bzz)", Usage: "Swarm config file path (datadir/bzz)",
} }
SwarmSwapEnabled = cli.BoolFlag{ SwarmSwapEnabledFlag = cli.BoolFlag{
Name: "swap", Name: "swap",
Usage: "Swarm SWAP enabled (default false)", Usage: "Swarm SWAP enabled (default false)",
} }
SwarmSyncEnabled = cli.BoolTFlag{ SwarmSyncEnabledFlag = cli.BoolTFlag{
Name: "sync", Name: "sync",
Usage: "Swarm Syncing enabled (default true)", Usage: "Swarm Syncing enabled (default true)",
} }
EthAPI = cli.StringFlag{ EthAPIFlag = cli.StringFlag{
Name: "ethapi", Name: "ethapi",
Usage: "URL of the Ethereum API provider", Usage: "URL of the Ethereum API provider",
Value: node.DefaultIPCEndpoint("gubiq"), Value: node.DefaultIPCEndpoint("gubiq"),
} }
SwarmApiFlag = cli.StringFlag{
Name: "bzzapi",
Usage: "Swarm HTTP endpoint",
Value: "http://127.0.0.1:8500",
}
SwarmRecursiveUploadFlag = cli.BoolFlag{
Name: "recursive",
Usage: "Upload directories recursively",
}
SwarmWantManifestFlag = cli.BoolTFlag{
Name: "manifest",
Usage: "Automatic manifest upload",
}
SwarmUploadDefaultPath = cli.StringFlag{
Name: "defaultpath",
Usage: "path to file served for empty url path (none)",
}
CorsStringFlag = cli.StringFlag{
Name: "corsdomain",
Usage: "Domain on which to send Access-Control-Allow-Origin header (multiple domains can be supplied separated by a ',')",
}
) )
var defaultBootnodes = []string{}
func init() { func init() {
// Override flag defaults so bzzd can run alongside gubiq. // Override flag defaults so bzzd can run alongside gubiq.
utils.ListenPortFlag.Value = 30399 utils.ListenPortFlag.Value = 30399
@ -96,8 +119,39 @@ func init() {
utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3" utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3"
// Set up the cli app. // Set up the cli app.
app.Commands = nil
app.Action = bzzd app.Action = bzzd
app.HideVersion = true // we have a command to print the version
app.Copyright = "Copyright 2013-2016 The go-ethereum Authors"
app.Commands = []cli.Command{
{
Action: version,
Name: "version",
Usage: "Print version numbers",
ArgsUsage: " ",
Description: `
The output of this command is supposed to be machine-readable.
`,
},
{
Action: upload,
Name: "up",
Usage: "upload a file or directory to swarm using the HTTP API",
ArgsUsage: " <file>",
Description: `
"upload a file or directory to swarm using the HTTP API and prints the root hash",
`,
},
{
Action: hash,
Name: "hash",
Usage: "print the swarm hash of a file or directory",
ArgsUsage: " <file>",
Description: `
Prints the swarm hash of file or directory.
`,
},
}
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
utils.IdentityFlag, utils.IdentityFlag,
utils.DataDirFlag, utils.DataDirFlag,
@ -115,14 +169,20 @@ func init() {
utils.IPCApiFlag, utils.IPCApiFlag,
utils.IPCPathFlag, utils.IPCPathFlag,
// bzzd-specific flags // bzzd-specific flags
EthAPI, CorsStringFlag,
EthAPIFlag,
SwarmConfigPathFlag, SwarmConfigPathFlag,
SwarmSwapEnabled, SwarmSwapEnabledFlag,
SwarmSyncEnabled, SwarmSyncEnabledFlag,
SwarmPortFlag, SwarmPortFlag,
SwarmAccountFlag, SwarmAccountFlag,
SwarmNetworkIdFlag, SwarmNetworkIdFlag,
ChequebookAddrFlag, ChequebookAddrFlag,
// upload flags
SwarmApiFlag,
SwarmRecursiveUploadFlag,
SwarmWantManifestFlag,
SwarmUploadDefaultPath,
} }
app.Flags = append(app.Flags, debug.Flags...) app.Flags = append(app.Flags, debug.Flags...)
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
@ -142,17 +202,33 @@ func main() {
} }
} }
func version(ctx *cli.Context) error {
fmt.Println(strings.Title(clientIdentifier))
fmt.Println("Version:", versionString)
if gitCommit != "" {
fmt.Println("Git Commit:", gitCommit)
}
fmt.Println("Network Id:", ctx.GlobalInt(utils.NetworkIdFlag.Name))
fmt.Println("Go Version:", runtime.Version())
fmt.Println("OS:", runtime.GOOS)
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
return nil
}
func bzzd(ctx *cli.Context) error { func bzzd(ctx *cli.Context) error {
stack := utils.MakeNode(ctx, clientIdentifier, gitCommit) stack := utils.MakeNode(ctx, clientIdentifier, gitCommit)
registerBzzService(ctx, stack) registerBzzService(ctx, stack)
utils.StartNode(stack) utils.StartNode(stack)
networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name)
// Add bootnodes as initial peers. // Add bootnodes as initial peers.
if ctx.GlobalIsSet(utils.BootnodesFlag.Name) { if ctx.GlobalIsSet(utils.BootnodesFlag.Name) {
bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",") bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",")
injectBootnodes(stack.Server(), bootnodes) injectBootnodes(stack.Server(), bootnodes)
} else { } else {
injectBootnodes(stack.Server(), defaultBootnodes) if networkId == 3 {
injectBootnodes(stack.Server(), testbetBootNodes)
}
} }
stack.Wait() stack.Wait()
@ -175,22 +251,21 @@ func registerBzzService(ctx *cli.Context, stack *node.Node) {
if len(bzzport) > 0 { if len(bzzport) > 0 {
bzzconfig.Port = bzzport bzzconfig.Port = bzzport
} }
swapEnabled := ctx.GlobalBool(SwarmSwapEnabled.Name) swapEnabled := ctx.GlobalBool(SwarmSwapEnabledFlag.Name)
syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabled.Name) syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabledFlag.Name)
ethapi := ctx.GlobalString(EthAPI.Name) ethapi := ctx.GlobalString(EthAPIFlag.Name)
cors := ctx.GlobalString(CorsStringFlag.Name)
boot := func(ctx *node.ServiceContext) (node.Service, error) { boot := func(ctx *node.ServiceContext) (node.Service, error) {
var client *ethclient.Client var client *ethclient.Client
if ethapi == "" { if len(ethapi) > 0 {
err = fmt.Errorf("use ethapi flag to connect to a an eth client and talk to the blockchain")
} else {
client, err = ethclient.Dial(ethapi) client, err = ethclient.Dial(ethapi)
}
if err != nil { if err != nil {
utils.Fatalf("Can't connect: %v", err) utils.Fatalf("Can't connect: %v", err)
} }
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled) }
return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled, cors)
} }
if err := stack.Register(boot); err != nil { if err := stack.Register(boot); err != nil {
utils.Fatalf("Failed to register the Swarm service: %v", err) utils.Fatalf("Failed to register the Swarm service: %v", err)

231
cmd/swarm/upload.go Normal file
View 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
}

View file

@ -18,12 +18,14 @@
package utils package utils
import ( import (
"compress/gzip"
"fmt" "fmt"
"io" "io"
"os" "os"
"os/signal" "os/signal"
"regexp" "regexp"
"runtime" "runtime"
"strings"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core" "github.com/ubiq/go-ubiq/core"
@ -65,7 +67,6 @@ func Fatalf(format string, args ...interface{}) {
} }
} }
fmt.Fprintf(w, "Fatal: "+format+"\n", args...) fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
logger.Flush()
os.Exit(1) os.Exit(1)
} }
@ -93,7 +94,7 @@ func StartNode(stack *node.Node) {
func FormatTransactionData(data string) []byte { func FormatTransactionData(data string) []byte {
d := common.StringToByteFunc(data, func(s string) (ret []byte) { d := common.StringToByteFunc(data, func(s string) (ret []byte) {
slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000) slice := regexp.MustCompile(`\n|\s`).Split(s, 1000000000)
for _, dataItem := range slice { for _, dataItem := range slice {
d := common.FormatData(dataItem) d := common.FormatData(dataItem)
ret = append(ret, d...) ret = append(ret, d...)
@ -133,7 +134,15 @@ func ImportChain(chain *core.BlockChain, fn string) error {
return err return err
} }
defer fh.Close() defer fh.Close()
stream := rlp.NewStream(fh, 0)
var reader io.Reader = fh
if strings.HasSuffix(fn, ".gz") {
if reader, err = gzip.NewReader(reader); err != nil {
return err
}
}
stream := rlp.NewStream(reader, 0)
// Run actual the import. // Run actual the import.
blocks := make(types.Blocks, importBatchSize) blocks := make(types.Blocks, importBatchSize)
@ -195,10 +204,18 @@ func ExportChain(blockchain *core.BlockChain, fn string) error {
return err return err
} }
defer fh.Close() defer fh.Close()
if err := blockchain.Export(fh); err != nil {
var writer io.Writer = fh
if strings.HasSuffix(fn, ".gz") {
writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close()
}
if err := blockchain.Export(writer); err != nil {
return err return err
} }
glog.Infoln("Exported blockchain to ", fn) glog.Infoln("Exported blockchain to ", fn)
return nil return nil
} }
@ -210,7 +227,14 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
return err return err
} }
defer fh.Close() defer fh.Close()
if err := blockchain.ExportN(fh, first, last); err != nil {
var writer io.Writer = fh
if strings.HasSuffix(fn, ".gz") {
writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close()
}
if err := blockchain.ExportN(writer, first, last); err != nil {
return err return err
} }
glog.Infoln("Exported blockchain to ", fn) glog.Infoln("Exported blockchain to ", fn)

View file

@ -23,8 +23,6 @@ import (
"os/user" "os/user"
"path" "path"
"strings" "strings"
"gopkg.in/urfave/cli.v1"
) )
// Custom type which is registered in the flags library which cli uses for // Custom type which is registered in the flags library which cli uses for
@ -46,7 +44,6 @@ func (self *DirectoryString) Set(value string) error {
// Custom cli.Flag type which expand the received string to an absolute path. // Custom cli.Flag type which expand the received string to an absolute path.
// e.g. ~/.ubiq -> /home/username/.ubiq // e.g. ~/.ubiq -> /home/username/.ubiq
type DirectoryFlag struct { type DirectoryFlag struct {
cli.GenericFlag
Name string Name string
Value DirectoryString Value DirectoryString
Usage string Usage string
@ -54,15 +51,10 @@ type DirectoryFlag struct {
} }
func (self DirectoryFlag) String() string { func (self DirectoryFlag) String() string {
var fmtString string fmtString := "%s %v\t%v"
fmtString = "%s %v\t%v"
if len(self.Value.Value) > 0 { if len(self.Value.Value) > 0 {
fmtString = "%s \"%v\"\t%v" fmtString = "%s \"%v\"\t%v"
} else {
fmtString = "%s %v\t%v"
} }
return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage)) return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage))
} }
@ -122,7 +114,7 @@ func withEnvHint(envVar, str string) string {
return str + envText return str + envText
} }
func (self DirectoryFlag) getName() string { func (self DirectoryFlag) GetName() string {
return self.Name return self.Name
} }

View file

@ -21,7 +21,6 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math"
"math/big" "math/big"
"os" "os"
"path/filepath" "path/filepath"
@ -116,13 +115,9 @@ var (
} }
NetworkIdFlag = cli.IntFlag{ NetworkIdFlag = cli.IntFlag{
Name: "networkid", Name: "networkid",
Usage: "Network identifier (integer, 0=Olympic (disused), 1=Frontier, 2=Morden (disused), 3=Ropsten)", Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)",
Value: eth.NetworkId, Value: eth.NetworkId,
} }
OlympicFlag = cli.BoolFlag{
Name: "olympic",
Usage: "Olympic network: pre-configured pre-release test network",
}
TestNetFlag = cli.BoolFlag{ TestNetFlag = cli.BoolFlag{
Name: "testnet", Name: "testnet",
Usage: "Ropsten network: pre-configured test network", Usage: "Ropsten network: pre-configured test network",
@ -485,17 +480,15 @@ func makeNodeUserIdent(ctx *cli.Context) string {
// MakeBootstrapNodes creates a list of bootstrap nodes from the command line // MakeBootstrapNodes creates a list of bootstrap nodes from the command line
// flags, reverting to pre-configured ones if none have been specified. // flags, reverting to pre-configured ones if none have been specified.
func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node { func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
// Return pre-configured nodes if none were manually requested urls := params.MainnetBootnodes
if !ctx.GlobalIsSet(BootnodesFlag.Name) { if ctx.GlobalIsSet(BootnodesFlag.Name) {
if ctx.GlobalBool(TestNetFlag.Name) { urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
return params.TestnetBootnodes } else if ctx.GlobalBool(TestNetFlag.Name) {
urls = params.TestnetBootnodes
} }
return params.MainnetBootnodes
}
// Otherwise parse and use the CLI bootstrap nodes
bootnodes := []*discover.Node{}
for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") { bootnodes := make([]*discover.Node, 0, len(urls))
for _, url := range urls {
node, err := discover.ParseNode(url) node, err := discover.ParseNode(url)
if err != nil { if err != nil {
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err) glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
@ -509,14 +502,13 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
// MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line // MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line
// flags, reverting to pre-configured ones if none have been specified. // flags, reverting to pre-configured ones if none have been specified.
func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node { func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
// Return pre-configured nodes if none were manually requested urls := params.DiscoveryV5Bootnodes
if !ctx.GlobalIsSet(BootnodesFlag.Name) { if ctx.GlobalIsSet(BootnodesFlag.Name) {
return params.DiscoveryV5Bootnodes urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
} }
// Otherwise parse and use the CLI bootstrap nodes
bootnodes := []*discv5.Node{}
for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") { bootnodes := make([]*discv5.Node, 0, len(urls))
for _, url := range urls {
node, err := discv5.ParseNode(url) node, err := discv5.ParseNode(url)
if err != nil { if err != nil {
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err) glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
@ -715,7 +707,7 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
// given node. // given node.
func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) { func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
// Avoid conflicting network flags // Avoid conflicting network flags
networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag} networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag}
for _, flag := range netFlags { for _, flag := range netFlags {
if ctx.GlobalBool(flag.Name) { if ctx.GlobalBool(flag.Name) {
networks++ networks++
@ -753,12 +745,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
// Override any default configs in dev mode or the test net // Override any default configs in dev mode or the test net
switch { switch {
case ctx.GlobalBool(OlympicFlag.Name):
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
ethConf.NetworkId = 88
}
ethConf.Genesis = core.OlympicGenesisBlock()
case ctx.GlobalBool(TestNetFlag.Name): case ctx.GlobalBool(TestNetFlag.Name):
if !ctx.GlobalIsSet(NetworkIdFlag.Name) { if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
ethConf.NetworkId = 3 ethConf.NetworkId = 3
@ -766,7 +752,7 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
ethConf.Genesis = core.DefaultTestnetGenesisBlock() ethConf.Genesis = core.DefaultTestnetGenesisBlock()
case ctx.GlobalBool(DevModeFlag.Name): case ctx.GlobalBool(DevModeFlag.Name):
ethConf.Genesis = core.OlympicGenesisBlock() ethConf.Genesis = core.DevGenesisBlock()
if !ctx.GlobalIsSet(GasPriceFlag.Name) { if !ctx.GlobalIsSet(GasPriceFlag.Name) {
ethConf.GasPrice = new(big.Int) ethConf.GasPrice = new(big.Int)
} }
@ -823,16 +809,6 @@ func RegisterEthStatsService(stack *node.Node, url string) {
// SetupNetwork configures the system for either the main net or some test network. // SetupNetwork configures the system for either the main net or some test network.
func SetupNetwork(ctx *cli.Context) { func SetupNetwork(ctx *cli.Context) {
switch {
case ctx.GlobalBool(OlympicFlag.Name):
params.DurationLimit = big.NewInt(8)
params.GenesisGasLimit = big.NewInt(3141592)
params.MinGasLimit = big.NewInt(125000)
params.MaximumExtraDataSize = big.NewInt(1024)
NetworkIdFlag.Value = 0
core.BlockReward = big.NewInt(1.5e+18)
core.ExpDiffPeriod = big.NewInt(math.MaxInt64)
}
params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name)) params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name))
} }
@ -920,12 +896,13 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
var err error var err error
chainDb = MakeChainDatabase(ctx, stack) chainDb = MakeChainDatabase(ctx, stack)
if ctx.GlobalBool(OlympicFlag.Name) { if ctx.GlobalBool(TestNetFlag.Name) {
_, err := core.WriteTestNetGenesisBlock(chainDb) _, err := core.WriteTestNetGenesisBlock(chainDb)
if err != nil { if err != nil {
glog.Fatalln(err) glog.Fatalln(err)
} }
} }
chainConfig := MakeChainConfigFromDb(ctx, chainDb) chainConfig := MakeChainConfigFromDb(ctx, chainDb)
pow := pow.PoW(core.FakePow{}) pow := pow.PoW(core.FakePow{})

View file

@ -27,7 +27,7 @@ func TestMisc(t *testing.T) {
c := []byte{1, 2, 3, 4} c := []byte{1, 2, 3, 4}
z := BitTest(a, 1) z := BitTest(a, 1)
if z != true { if !z {
t.Error("Expected true got", z) t.Error("Expected true got", z)
} }
@ -79,11 +79,11 @@ func TestBigCopy(t *testing.T) {
z := BigToBytes(c, 16) z := BigToBytes(c, 16)
zbytes := []byte{232, 212, 165, 16, 0} zbytes := []byte{232, 212, 165, 16, 0}
if bytes.Compare(y, ybytes) != 0 { if !bytes.Equal(y, ybytes) {
t.Error("Got", ybytes) t.Error("Got", ybytes)
} }
if bytes.Compare(z, zbytes) != 0 { if !bytes.Equal(z, zbytes) {
t.Error("Got", zbytes) t.Error("Got", zbytes)
} }
} }

View file

@ -143,7 +143,7 @@ func Hex2BytesFixed(str string, flen int) []byte {
return h return h
} else { } else {
if len(h) > flen { if len(h) > flen {
return h[len(h)-flen : len(h)] return h[len(h)-flen:]
} else { } else {
hh := make([]byte, flen) hh := make([]byte, flen)
copy(hh[flen-len(h):flen], h[:]) copy(hh[flen-len(h):flen], h[:])

View file

@ -181,7 +181,7 @@ func TestFromHex(t *testing.T) {
input := "0x01" input := "0x01"
expected := []byte{1} expected := []byte{1}
result := FromHex(input) result := FromHex(input)
if bytes.Compare(expected, result) != 0 { if !bytes.Equal(expected, result) {
t.Errorf("Expected % x got % x", expected, result) t.Errorf("Expected % x got % x", expected, result)
} }
} }
@ -190,7 +190,7 @@ func TestFromHexOddLength(t *testing.T) {
input := "0x1" input := "0x1"
expected := []byte{1} expected := []byte{1}
result := FromHex(input) result := FromHex(input)
if bytes.Compare(expected, result) != 0 { if !bytes.Equal(expected, result) {
t.Errorf("Expected % x got % x", expected, result) t.Errorf("Expected % x got % x", expected, result)
} }
} }

View file

@ -22,9 +22,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"os"
"os/exec" "os/exec"
"regexp" "regexp"
"strings" "strings"
@ -34,7 +32,7 @@ import (
) )
var ( var (
versionRegexp = regexp.MustCompile("[0-9]+\\.[0-9]+\\.[0-9]+") versionRegexp = regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`)
solcParams = []string{ solcParams = []string{
"--combined-json", "bin,abi,userdoc,devdoc", "--combined-json", "bin,abi,userdoc,devdoc",
"--add-std", // include standard lib contracts "--add-std", // include standard lib contracts
@ -96,27 +94,16 @@ func CompileSolidityString(solc, source string) (map[string]*Contract, error) {
if solc == "" { if solc == "" {
solc = "solc" solc = "solc"
} }
// Write source to a temporary file. Compiling stdin used to be supported args := append(solcParams, "--")
// but seems to produce an exception with solc 0.3.5. cmd := exec.Command(solc, append(args, "-")...)
infile, err := ioutil.TempFile("", "gubiq-compile-solidity") cmd.Stdin = strings.NewReader(source)
if err != nil { return runsolc(cmd, source)
return nil, err
}
defer os.Remove(infile.Name())
if _, err := io.WriteString(infile, source); err != nil {
return nil, err
}
if err := infile.Close(); err != nil {
return nil, err
}
return CompileSolidity(solc, infile.Name())
} }
// CompileSolidity compiles all given Solidity source files. // CompileSolidity compiles all given Solidity source files.
func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) { func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
if len(sourcefiles) == 0 { if len(sourcefiles) == 0 {
return nil, errors.New("solc: no source ") return nil, errors.New("solc: no source files")
} }
source, err := slurpFiles(sourcefiles) source, err := slurpFiles(sourcefiles)
if err != nil { if err != nil {
@ -125,10 +112,13 @@ func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract,
if solc == "" { if solc == "" {
solc = "solc" solc = "solc"
} }
var stderr, stdout bytes.Buffer
args := append(solcParams, "--") args := append(solcParams, "--")
cmd := exec.Command(solc, append(args, sourcefiles...)...) cmd := exec.Command(solc, append(args, sourcefiles...)...)
return runsolc(cmd, source)
}
func runsolc(cmd *exec.Cmd, source string) (map[string]*Contract, error) {
var stderr, stdout bytes.Buffer
cmd.Stderr = &stderr cmd.Stderr = &stderr
cmd.Stdout = &stdout cmd.Stdout = &stdout
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {

View file

@ -20,6 +20,7 @@ import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec"
"path" "path"
"testing" "testing"
@ -27,7 +28,6 @@ import (
) )
const ( const (
supportedSolcVersion = "0.3.5"
testSource = ` testSource = `
contract test { contract test {
/// @notice Will multiply ` + "`a`" + ` by 7. /// @notice Will multiply ` + "`a`" + ` by 7.
@ -36,23 +36,18 @@ contract test {
} }
} }
` `
testCode = "0x6060604052602a8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b6007600435026060908152602090f3"
testInfo = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}` testInfo = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}`
) )
func skipUnsupported(t *testing.T) { func skipWithoutSolc(t *testing.T) {
sol, err := SolidityVersion("") if _, err := exec.LookPath("solc"); err != nil {
if err != nil {
t.Skip(err) t.Skip(err)
return
}
if sol.Version != supportedSolcVersion {
t.Skipf("unsupported version of solc found (%v, expect %v)", sol.Version, supportedSolcVersion)
} }
} }
func TestCompiler(t *testing.T) { func TestCompiler(t *testing.T) {
skipUnsupported(t) skipWithoutSolc(t)
contracts, err := CompileSolidityString("", testSource) contracts, err := CompileSolidityString("", testSource)
if err != nil { if err != nil {
t.Fatalf("error compiling source. result %v: %v", contracts, err) t.Fatalf("error compiling source. result %v: %v", contracts, err)
@ -64,19 +59,20 @@ func TestCompiler(t *testing.T) {
if !ok { if !ok {
t.Fatal("info for contract 'test' not present in result") t.Fatal("info for contract 'test' not present in result")
} }
if c.Code != testCode { if c.Code == "" {
t.Errorf("wrong code: expected\n%s, got\n%s", testCode, c.Code) t.Error("empty code")
} }
if c.Info.Source != testSource { if c.Info.Source != testSource {
t.Error("wrong source") t.Error("wrong source")
} }
if c.Info.CompilerVersion != supportedSolcVersion { if c.Info.CompilerVersion == "" {
t.Errorf("wrong version: expected %q, got %q", supportedSolcVersion, c.Info.CompilerVersion) t.Error("empty version")
} }
} }
func TestCompileError(t *testing.T) { func TestCompileError(t *testing.T) {
skipUnsupported(t) skipWithoutSolc(t)
contracts, err := CompileSolidityString("", testSource[4:]) contracts, err := CompileSolidityString("", testSource[4:])
if err == nil { if err == nil {
t.Errorf("error expected compiling source. got none. result %v", contracts) t.Errorf("error expected compiling source. got none. result %v", contracts)

View file

@ -27,7 +27,7 @@ import (
// the unnecessary precision off from the formatted textual representation. // the unnecessary precision off from the formatted textual representation.
type PrettyDuration time.Duration type PrettyDuration time.Duration
var prettyDurationRe = regexp.MustCompile("\\.[0-9]+") var prettyDurationRe = regexp.MustCompile(`\.[0-9]+`)
// String implements the Stringer interface, allowing pretty printing of duration // String implements the Stringer interface, allowing pretty printing of duration
// values rounded to three decimals. // values rounded to three decimals.

View file

@ -237,7 +237,7 @@ func checkJSON(input []byte) (raw []byte, err error) {
return nil, errNonString return nil, errNonString
} }
if len(input) == 2 { if len(input) == 2 {
return nil, ErrEmptyString return nil, nil // empty strings are allowed
} }
if !bytesHave0xPrefix(input[1:]) { if !bytesHave0xPrefix(input[1:]) {
return nil, ErrMissingPrefix return nil, ErrMissingPrefix
@ -255,7 +255,7 @@ func checkNumberJSON(input []byte) (raw []byte, err error) {
} }
input = input[1 : len(input)-1] input = input[1 : len(input)-1]
if len(input) == 0 { if len(input) == 0 {
return nil, ErrEmptyString return nil, nil // empty strings are allowed
} }
if !bytesHave0xPrefix(input) { if !bytesHave0xPrefix(input) {
return nil, ErrMissingPrefix return nil, ErrMissingPrefix

View file

@ -60,13 +60,13 @@ var unmarshalBytesTests = []unmarshalTest{
{input: "", wantErr: errNonString}, {input: "", wantErr: errNonString},
{input: "null", wantErr: errNonString}, {input: "null", wantErr: errNonString},
{input: "10", wantErr: errNonString}, {input: "10", wantErr: errNonString},
{input: `""`, wantErr: ErrEmptyString},
{input: `"0"`, wantErr: ErrMissingPrefix}, {input: `"0"`, wantErr: ErrMissingPrefix},
{input: `"0x0"`, wantErr: ErrOddLength}, {input: `"0x0"`, wantErr: ErrOddLength},
{input: `"0xxx"`, wantErr: ErrSyntax}, {input: `"0xxx"`, wantErr: ErrSyntax},
{input: `"0x01zz01"`, wantErr: ErrSyntax}, {input: `"0x01zz01"`, wantErr: ErrSyntax},
// valid encoding // valid encoding
{input: `""`, want: referenceBytes("")},
{input: `"0x"`, want: referenceBytes("")}, {input: `"0x"`, want: referenceBytes("")},
{input: `"0x02"`, want: referenceBytes("02")}, {input: `"0x02"`, want: referenceBytes("02")},
{input: `"0X02"`, want: referenceBytes("02")}, {input: `"0X02"`, want: referenceBytes("02")},
@ -125,7 +125,6 @@ var unmarshalBigTests = []unmarshalTest{
{input: "", wantErr: errNonString}, {input: "", wantErr: errNonString},
{input: "null", wantErr: errNonString}, {input: "null", wantErr: errNonString},
{input: "10", wantErr: errNonString}, {input: "10", wantErr: errNonString},
{input: `""`, wantErr: ErrEmptyString},
{input: `"0"`, wantErr: ErrMissingPrefix}, {input: `"0"`, wantErr: ErrMissingPrefix},
{input: `"0x"`, wantErr: ErrEmptyNumber}, {input: `"0x"`, wantErr: ErrEmptyNumber},
{input: `"0x01"`, wantErr: ErrLeadingZero}, {input: `"0x01"`, wantErr: ErrLeadingZero},
@ -133,6 +132,7 @@ var unmarshalBigTests = []unmarshalTest{
{input: `"0x1zz01"`, wantErr: ErrSyntax}, {input: `"0x1zz01"`, wantErr: ErrSyntax},
// valid encoding // valid encoding
{input: `""`, want: big.NewInt(0)},
{input: `"0x0"`, want: big.NewInt(0)}, {input: `"0x0"`, want: big.NewInt(0)},
{input: `"0x2"`, want: big.NewInt(0x2)}, {input: `"0x2"`, want: big.NewInt(0x2)},
{input: `"0x2F2"`, want: big.NewInt(0x2f2)}, {input: `"0x2F2"`, want: big.NewInt(0x2f2)},
@ -198,7 +198,6 @@ var unmarshalUint64Tests = []unmarshalTest{
{input: "", wantErr: errNonString}, {input: "", wantErr: errNonString},
{input: "null", wantErr: errNonString}, {input: "null", wantErr: errNonString},
{input: "10", wantErr: errNonString}, {input: "10", wantErr: errNonString},
{input: `""`, wantErr: ErrEmptyString},
{input: `"0"`, wantErr: ErrMissingPrefix}, {input: `"0"`, wantErr: ErrMissingPrefix},
{input: `"0x"`, wantErr: ErrEmptyNumber}, {input: `"0x"`, wantErr: ErrEmptyNumber},
{input: `"0x01"`, wantErr: ErrLeadingZero}, {input: `"0x01"`, wantErr: ErrLeadingZero},
@ -207,6 +206,7 @@ var unmarshalUint64Tests = []unmarshalTest{
{input: `"0x1zz01"`, wantErr: ErrSyntax}, {input: `"0x1zz01"`, wantErr: ErrSyntax},
// valid encoding // valid encoding
{input: `""`, want: uint64(0)},
{input: `"0x0"`, want: uint64(0)}, {input: `"0x0"`, want: uint64(0)},
{input: `"0x2"`, want: uint64(0x2)}, {input: `"0x2"`, want: uint64(0x2)},
{input: `"0x2F2"`, want: uint64(0x2f2)}, {input: `"0x2F2"`, want: uint64(0x2f2)},

View file

@ -41,24 +41,24 @@ func TestSum(t *testing.T) {
func TestDist(t *testing.T) { func TestDist(t *testing.T) {
var vectors = []Vector{ var vectors = []Vector{
Vector{big.NewInt(1000), big.NewInt(1234)}, {big.NewInt(1000), big.NewInt(1234)},
Vector{big.NewInt(500), big.NewInt(10023)}, {big.NewInt(500), big.NewInt(10023)},
Vector{big.NewInt(1034), big.NewInt(1987)}, {big.NewInt(1034), big.NewInt(1987)},
Vector{big.NewInt(1034), big.NewInt(1987)}, {big.NewInt(1034), big.NewInt(1987)},
Vector{big.NewInt(8983), big.NewInt(1977)}, {big.NewInt(8983), big.NewInt(1977)},
Vector{big.NewInt(98382), big.NewInt(1887)}, {big.NewInt(98382), big.NewInt(1887)},
Vector{big.NewInt(12398), big.NewInt(1287)}, {big.NewInt(12398), big.NewInt(1287)},
Vector{big.NewInt(12398), big.NewInt(1487)}, {big.NewInt(12398), big.NewInt(1487)},
Vector{big.NewInt(12398), big.NewInt(1987)}, {big.NewInt(12398), big.NewInt(1987)},
Vector{big.NewInt(12398), big.NewInt(128)}, {big.NewInt(12398), big.NewInt(128)},
Vector{big.NewInt(12398), big.NewInt(1987)}, {big.NewInt(12398), big.NewInt(1987)},
Vector{big.NewInt(1398), big.NewInt(187)}, {big.NewInt(1398), big.NewInt(187)},
Vector{big.NewInt(12328), big.NewInt(1927)}, {big.NewInt(12328), big.NewInt(1927)},
Vector{big.NewInt(12398), big.NewInt(1987)}, {big.NewInt(12398), big.NewInt(1987)},
Vector{big.NewInt(22398), big.NewInt(1287)}, {big.NewInt(22398), big.NewInt(1287)},
Vector{big.NewInt(1370), big.NewInt(1981)}, {big.NewInt(1370), big.NewInt(1981)},
Vector{big.NewInt(12398), big.NewInt(1957)}, {big.NewInt(12398), big.NewInt(1957)},
Vector{big.NewInt(42198), big.NewInt(1987)}, {big.NewInt(42198), big.NewInt(1987)},
} }
VectorsBy(GasSort).Sort(vectors) VectorsBy(GasSort).Sort(vectors)

View file

@ -76,9 +76,9 @@ func compressChunk(dat []byte) (ret []byte, n int) {
} }
return []byte{token, byte(j + 2)}, j return []byte{token, byte(j + 2)}, j
case len(dat) >= 32: case len(dat) >= 32:
if dat[0] == empty[0] && bytes.Compare(dat[:32], empty) == 0 { if dat[0] == empty[0] && bytes.Equal(dat[:32], empty) {
return []byte{token, emptyShaToken}, 32 return []byte{token, emptyShaToken}, 32
} else if dat[0] == emptyList[0] && bytes.Compare(dat[:32], emptyList) == 0 { } else if dat[0] == emptyList[0] && bytes.Equal(dat[:32], emptyList) {
return []byte{token, emptyListShaToken}, 32 return []byte{token, emptyListShaToken}, 32
} }
fallthrough fallthrough

View file

@ -46,7 +46,7 @@ func newBridge(client *rpc.Client, prompter UserPrompter, printer io.Writer) *br
} }
// NewAccount is a wrapper around the personal.newAccount RPC method that uses a // NewAccount is a wrapper around the personal.newAccount RPC method that uses a
// non-echoing password prompt to aquire the passphrase and executes the original // non-echoing password prompt to acquire the passphrase and executes the original
// RPC method (saved in jeth.newAccount) with it to actually execute the RPC call. // RPC method (saved in jeth.newAccount) with it to actually execute the RPC call.
func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) { func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
var ( var (
@ -75,7 +75,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
default: default:
throwJSException("expected 0 or 1 string argument") throwJSException("expected 0 or 1 string argument")
} }
// Password aquired, execute the call and return // Password acquired, execute the call and return
ret, err := call.Otto.Call("jeth.newAccount", nil, password) ret, err := call.Otto.Call("jeth.newAccount", nil, password)
if err != nil { if err != nil {
throwJSException(err.Error()) throwJSException(err.Error())
@ -84,7 +84,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) {
} }
// UnlockAccount is a wrapper around the personal.unlockAccount RPC method that // UnlockAccount is a wrapper around the personal.unlockAccount RPC method that
// uses a non-echoing password prompt to aquire the passphrase and executes the // uses a non-echoing password prompt to acquire the passphrase and executes the
// original RPC method (saved in jeth.unlockAccount) with it to actually execute // original RPC method (saved in jeth.unlockAccount) with it to actually execute
// the RPC call. // the RPC call.
func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) { func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
@ -127,7 +127,7 @@ func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) {
} }
// Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password // Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password
// prompt to aquire the passphrase and executes the original RPC method (saved in // prompt to acquire the passphrase and executes the original RPC method (saved in
// jeth.sign) with it to actually execute the RPC call. // jeth.sign) with it to actually execute the RPC call.
func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) { func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) {
var ( var (
@ -270,18 +270,15 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
} else { } else {
resultVal, err := JSON.Call("parse", string(result)) resultVal, err := JSON.Call("parse", string(result))
if err != nil { if err != nil {
resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object() setError(resp, -32603, err.Error())
} else { } else {
resp.Set("result", resultVal) resp.Set("result", resultVal)
} }
} }
case rpc.Error: case rpc.Error:
resp.Set("error", map[string]interface{}{ setError(resp, err.ErrorCode(), err.Error())
"code": err.ErrorCode(),
"message": err.Error(),
})
default: default:
resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object() setError(resp, -32603, err.Error())
} }
resps.Call("push", resp) resps.Call("push", resp)
} }
@ -300,12 +297,8 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
return response return response
} }
func newErrorResponse(call otto.FunctionCall, code int, msg string, id interface{}) otto.Value { func setError(resp *otto.Object, code int, msg string) {
// Bundle the error into a JSON RPC call response resp.Set("error", map[string]interface{}{"code": code, "message": msg})
m := map[string]interface{}{"version": "2.0", "id": id, "error": map[string]interface{}{"code": code, msg: msg}}
res, _ := json.Marshal(m)
val, _ := call.Otto.Run("(" + string(res) + ")")
return val
} }
// throwJSException panics on an otto.Value. The Otto VM will recover from the // throwJSException panics on an otto.Value. The Otto VM will recover from the

View file

@ -36,9 +36,9 @@ import (
) )
var ( var (
passwordRegexp = regexp.MustCompile("personal.[nus]") passwordRegexp = regexp.MustCompile(`personal.[nus]`)
onlyWhitespace = regexp.MustCompile("^\\s*$") onlyWhitespace = regexp.MustCompile(`^\s*$`)
exit = regexp.MustCompile("^\\s*exit\\s*;*\\s*$") exit = regexp.MustCompile(`^\s*exit\s*;*\s*$`)
) )
// HistoryFile is the file within the data directory to store input scrollback. // HistoryFile is the file within the data directory to store input scrollback.
@ -226,8 +226,8 @@ func (c *Console) AutoCompleteInput(line string, pos int) (string, []string, str
} }
// Chunck data to relevant part for autocompletion // Chunck data to relevant part for autocompletion
// E.g. in case of nested lines eth.getBalance(eth.coinb<tab><tab> // E.g. in case of nested lines eth.getBalance(eth.coinb<tab><tab>
start := 0 start := pos - 1
for start = pos - 1; start > 0; start-- { for ; start > 0; start-- {
// Skip all methods and namespaces (i.e. including te dot) // Skip all methods and namespaces (i.e. including te dot)
if line[start] == '.' || (line[start] >= 'a' && line[start] <= 'z') || (line[start] >= 'A' && line[start] <= 'Z') { if line[start] == '.' || (line[start] >= 'a' && line[start] <= 'z') || (line[start] >= 'A' && line[start] <= 'Z') {
continue continue
@ -275,10 +275,7 @@ func (c *Console) Evaluate(statement string) error {
fmt.Fprintf(c.printer, "[native] error: %v\n", r) fmt.Fprintf(c.printer, "[native] error: %v\n", r)
} }
}() }()
if err := c.jsre.Evaluate(statement, c.printer); err != nil { return c.jsre.Evaluate(statement, c.printer)
return err
}
return nil
} }
// Interactive starts an interactive user session, where input is propted from // Interactive starts an interactive user session, where input is propted from

View file

@ -44,7 +44,7 @@ type UserPrompter interface {
PromptConfirm(prompt string) (bool, error) PromptConfirm(prompt string) (bool, error)
// SetHistory sets the the input scrollback history that the prompter will allow // SetHistory sets the the input scrollback history that the prompter will allow
// the user to scoll back to. // the user to scroll back to.
SetHistory(history []string) SetHistory(history []string)
// AppendHistory appends an entry to the scrollback history. It should be called // AppendHistory appends an entry to the scrollback history. It should be called
@ -147,7 +147,7 @@ func (p *terminalPrompter) PromptConfirm(prompt string) (bool, error) {
} }
// SetHistory sets the the input scrollback history that the prompter will allow // SetHistory sets the the input scrollback history that the prompter will allow
// the user to scoll back to. // the user to scroll back to.
func (p *terminalPrompter) SetHistory(history []string) { func (p *terminalPrompter) SetHistory(history []string) {
p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n"))) p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n")))
} }

View file

@ -252,7 +252,7 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *
return nil, fmt.Errorf("amount must be greater than zero (%v)", amount) return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
} }
if self.balance.Cmp(amount) < 0 { if self.balance.Cmp(amount) < 0 {
err = fmt.Errorf("insufficent funds to issue cheque for amount: %v. balance: %v", amount, self.balance) err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, self.balance)
} else { } else {
var sig []byte var sig []byte
sent, found := self.sent[beneficiary] sent, found := self.sent[beneficiary]
@ -277,7 +277,7 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *
} }
// auto deposit if threshold is set and balance is less then threshold // auto deposit if threshold is set and balance is less then threshold
// note this is called even if issueing cheque fails // note this is called even if issuing cheque fails
// so we reattempt depositing // so we reattempt depositing
if self.threshold != nil { if self.threshold != nil {
if self.balance.Cmp(self.threshold) < 0 { if self.balance.Cmp(self.threshold) < 0 {

View file

@ -73,8 +73,8 @@ func TestIssueAndReceive(t *testing.T) {
} }
chbook.sent[addr1] = new(big.Int).SetUint64(42) chbook.sent[addr1] = new(big.Int).SetUint64(42)
amount := common.Big1 amount := common.Big1
ch, err := chbook.Issue(addr1, amount)
if err == nil { if _, err = chbook.Issue(addr1, amount); err == nil {
t.Fatalf("expected insufficient funds error, got none") t.Fatalf("expected insufficient funds error, got none")
} }
@ -83,7 +83,7 @@ func TestIssueAndReceive(t *testing.T) {
t.Fatalf("expected: %v, got %v", "0", chbook.Balance()) t.Fatalf("expected: %v, got %v", "0", chbook.Balance())
} }
ch, err = chbook.Issue(addr1, amount) ch, err := chbook.Issue(addr1, amount)
if err != nil { if err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
@ -128,8 +128,8 @@ func TestCheckbookFile(t *testing.T) {
t.Errorf("expected: %v, got %v", "0", chbook.Balance()) t.Errorf("expected: %v, got %v", "0", chbook.Balance())
} }
ch, err := chbook.Issue(addr1, common.Big1) var ch *Cheque
if err != nil { if ch, err = chbook.Issue(addr1, common.Big1); err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 { if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 {
@ -155,7 +155,7 @@ func TestVerifyErrors(t *testing.T) {
} }
path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json") path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json")
contr1, err := deploy(key1, common.Big2, backend) contr1, _ := deploy(key1, common.Big2, backend)
chbook1, err := NewChequebook(path1, contr1, key1, backend) chbook1, err := NewChequebook(path1, contr1, key1, backend)
if err != nil { if err != nil {
t.Errorf("expected no error, got %v", err) t.Errorf("expected no error, got %v", err)
@ -223,7 +223,8 @@ func TestVerifyErrors(t *testing.T) {
func TestDeposit(t *testing.T) { func TestDeposit(t *testing.T) {
path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json") path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
backend := newTestBackend() backend := newTestBackend()
contr0, err := deploy(key0, new(big.Int), backend) contr0, _ := deploy(key0, new(big.Int), backend)
chbook, err := NewChequebook(path0, contr0, key0, backend) chbook, err := NewChequebook(path0, contr0, key0, backend)
if err != nil { if err != nil {
t.Errorf("expected no error, got %v", err) t.Errorf("expected no error, got %v", err)
@ -361,7 +362,8 @@ func TestDeposit(t *testing.T) {
func TestCash(t *testing.T) { func TestCash(t *testing.T) {
path := filepath.Join(os.TempDir(), "chequebook-test.json") path := filepath.Join(os.TempDir(), "chequebook-test.json")
backend := newTestBackend() backend := newTestBackend()
contr0, err := deploy(key0, common.Big2, backend) contr0, _ := deploy(key0, common.Big2, backend)
chbook, err := NewChequebook(path, contr0, key0, backend) chbook, err := NewChequebook(path, contr0, key0, backend)
if err != nil { if err != nil {
t.Errorf("expected no error, got %v", err) t.Errorf("expected no error, got %v", err)
@ -380,11 +382,12 @@ func TestCash(t *testing.T) {
} }
// cashing latest cheque // cashing latest cheque
_, err = chbox.Receive(ch) if _, err = chbox.Receive(ch); err != nil {
if err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
_, err = ch.Cash(chbook.session) if _, err = ch.Cash(chbook.session); err != nil {
t.Fatal("Cash failed:", err)
}
backend.Commit() backend.Commit()
chbook.balance = new(big.Int).Set(common.Big3) chbook.balance = new(big.Int).Set(common.Big3)

View file

@ -29,7 +29,7 @@ import (
var ( var (
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
name = "my name on ENS" name = "my name on ENS"
hash = crypto.Sha3Hash([]byte("my content")) hash = crypto.Keccak256Hash([]byte("my content"))
addr = crypto.PubkeyToAddress(key.PublicKey) addr = crypto.PubkeyToAddress(key.PublicKey)
) )

View file

@ -78,7 +78,7 @@ contract ReleaseOracle {
} }
// signers is an accessor method to retrieve all te signers (public accessor // signers is an accessor method to retrieve all te signers (public accessor
// generates an indexed one, not a retreive-all version). // generates an indexed one, not a retrieve-all version).
function signers() constant returns(address[]) { function signers() constant returns(address[]) {
return voters; return voters;
} }
@ -178,7 +178,7 @@ contract ReleaseOracle {
voters[i] = voters[voters.length - 1]; voters[i] = voters[voters.length - 1];
voters.length--; voters.length--;
delete verProp; // Nuke any version proposal (no suprise releases!) delete verProp; // Nuke any version proposal (no surprise releases!)
break; break;
} }
} }

View file

@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
toaddr := common.Address{} toaddr := common.Address{}
data := make([]byte, nbytes) data := make([]byte, nbytes)
gas := IntrinsicGas(data, false, false) gas := IntrinsicGas(data, false, false)
tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(types.HomesteadSigner{}, benchRootKey) tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
gen.AddTx(tx) gen.AddTx(tx)
} }
} }
@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
nil, nil,
nil, nil,
) )
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from]) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from])
gen.AddTx(tx) gen.AddTx(tx)
from = to from = to
} }

View file

@ -24,11 +24,9 @@ import (
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/state" "github.com/ubiq/go-ubiq/core/state"
"github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/core/vm"
"github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/ethdb"
"github.com/ubiq/go-ubiq/event" "github.com/ubiq/go-ubiq/event"
"github.com/ubiq/go-ubiq/params" "github.com/ubiq/go-ubiq/params"
"github.com/ubiq/go-ubiq/pow/ezp"
) )
func testChainConfig() *params.ChainConfig { func testChainConfig() *params.ChainConfig {
@ -49,20 +47,19 @@ func proc() (Validator, *BlockChain) {
} }
func TestNumber(t *testing.T) { func TestNumber(t *testing.T) {
pow := ezp.New()
_, chain := proc() _, chain := proc()
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb) statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
cfg := testChainConfig() cfg := testChainConfig()
header := makeHeader(cfg, chain.Genesis(), statedb) header := makeHeader(cfg, chain.Genesis(), statedb)
header.Number = big.NewInt(3) header.Number = big.NewInt(3)
err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false) err := ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false)
if err != BlockNumberErr { if err != BlockNumberErr {
t.Errorf("expected block number error, got %q", err) t.Errorf("expected block number error, got %q", err)
} }
header = makeHeader(cfg, chain.Genesis(), statedb) header = makeHeader(cfg, chain.Genesis(), statedb)
err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false) err = ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false)
if err == BlockNumberErr { if err == BlockNumberErr {
t.Errorf("didn't expect block number error") t.Errorf("didn't expect block number error")
} }
@ -77,7 +74,7 @@ func TestPutReceipt(t *testing.T) {
hash[0] = 2 hash[0] = 2
receipt := new(types.Receipt) receipt := new(types.Receipt)
receipt.Logs = vm.Logs{&vm.Log{ receipt.Logs = []*types.Log{{
Address: addr, Address: addr,
Topics: []common.Hash{hash}, Topics: []common.Hash{hash},
Data: []byte("hi"), Data: []byte("hi"),

View file

@ -29,7 +29,9 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/hashicorp/golang-lru"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/common/mclock"
"github.com/ubiq/go-ubiq/core/state" "github.com/ubiq/go-ubiq/core/state"
"github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/core/vm"
@ -43,13 +45,9 @@ import (
"github.com/ubiq/go-ubiq/pow" "github.com/ubiq/go-ubiq/pow"
"github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/rlp"
"github.com/ubiq/go-ubiq/trie" "github.com/ubiq/go-ubiq/trie"
"github.com/hashicorp/golang-lru"
) )
var ( var (
chainlogger = logger.NewLogger("CHAIN")
jsonlogger = logger.NewJsonLogger()
blockInsertTimer = metrics.NewTimer("chain/inserts") blockInsertTimer = metrics.NewTimer("chain/inserts")
ErrNoGenesis = errors.New("Genesis not found in chain") ErrNoGenesis = errors.New("Genesis not found in chain")
@ -152,7 +150,7 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.P
return nil, err return nil, err
} }
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
for hash, _ := range BadHashes { for hash := range BadHashes {
if header := bc.GetHeaderByHash(hash); header != nil { if header := bc.GetHeaderByHash(hash); header != nil {
// get the canonical block corresponding to the offending header's number // get the canonical block corresponding to the offending header's number
headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64()) headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
@ -404,10 +402,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) {
// Export writes the active chain to the given writer. // Export writes the active chain to the given writer.
func (self *BlockChain) Export(w io.Writer) error { func (self *BlockChain) Export(w io.Writer) error {
if err := self.ExportN(w, uint64(0), self.currentBlock.NumberU64()); err != nil { return self.ExportN(w, uint64(0), self.currentBlock.NumberU64())
return err
}
return nil
} }
// ExportN writes a subset of the active chain to the given writer. // ExportN writes a subset of the active chain to the given writer.
@ -634,7 +629,11 @@ func (self *BlockChain) procFutureBlocks() {
} }
if len(blocks) > 0 { if len(blocks) > 0 {
types.BlockBy(types.Number).Sort(blocks) types.BlockBy(types.Number).Sort(blocks)
self.InsertChain(blocks)
// Insert one by one as chain insertion needs contiguous ancestry between blocks
for i := range blocks {
self.InsertChain(blocks[i : i+1])
}
} }
} }
@ -708,6 +707,18 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty
// transaction and receipt data. // transaction and receipt data.
// XXX should this be moved to the test? // XXX should this be moved to the test?
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
// Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(blockChain); i++ {
if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() {
// Chain broke ancestry, log a messge (programming error) and skip insertion
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, blockChain[i-1].NumberU64(),
blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4])
glog.V(logger.Error).Info(failure.Error())
return 0, failure
}
}
// Pre-checks passed, start the block body and receipt imports
self.wg.Add(1) self.wg.Add(1)
defer self.wg.Done() defer self.wg.Done()
@ -822,7 +833,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
if stats.ignored > 0 { if stats.ignored > 0 {
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored) ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
} }
glog.V(logger.Info).Infof("imported %d receipts in %9v. #%d [%x… / %x…]%s", stats.processed, common.PrettyDuration(time.Since(start)), last.Number(), first.Hash().Bytes()[:4], last.Hash().Bytes()[:4], ignored) glog.V(logger.Info).Infof("imported %4d receipts in %9v. #%d [%x… / %x…]%s", stats.processed, common.PrettyDuration(time.Since(start)), last.Number(), first.Hash().Bytes()[:4], last.Hash().Bytes()[:4], ignored)
return 0, nil return 0, nil
} }
@ -876,6 +887,18 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err
// InsertChain will attempt to insert the given chain in to the canonical chain or, otherwise, create a fork. It an error is returned // InsertChain will attempt to insert the given chain in to the canonical chain or, otherwise, create a fork. It an error is returned
// it will return the index number of the failing block as well an error describing what went wrong (for possible errors see core/errors.go). // it will return the index number of the failing block as well an error describing what went wrong (for possible errors see core/errors.go).
func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(chain); i++ {
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {
// Chain broke ancestry, log a messge (programming error) and skip insertion
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])",
i-1, chain[i-1].NumberU64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4])
glog.V(logger.Error).Info(failure.Error())
return 0, failure
}
}
// Pre-checks passed, start the full block imports
self.wg.Add(1) self.wg.Add(1)
defer self.wg.Done() defer self.wg.Done()
@ -886,9 +909,9 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// faster than direct delivery and requires much less mutex // faster than direct delivery and requires much less mutex
// acquiring. // acquiring.
var ( var (
stats = insertStats{startTime: time.Now()} stats = insertStats{startTime: mclock.Now()}
events = make([]interface{}, 0, len(chain)) events = make([]interface{}, 0, len(chain))
coalescedLogs vm.Logs coalescedLogs []*types.Log
nonceChecked = make([]bool, len(chain)) nonceChecked = make([]bool, len(chain))
) )
@ -949,10 +972,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
} }
self.reportBlock(block, nil, err) self.reportBlock(block, nil, err)
return i, err return i, err
} }
// Create a new statedb using the parent block and report an // Create a new statedb using the parent block and report an
// error if it fails. // error if it fails.
switch { switch {
@ -1021,7 +1042,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
glog.Infof("inserted forked block #%d [%x…] (TD=%v) in %9v: %3d txs %d uncles.", block.Number(), block.Hash().Bytes()[0:4], block.Difficulty(), common.PrettyDuration(time.Since(bstart)), len(block.Transactions()), len(block.Uncles())) glog.Infof("inserted forked block #%d [%x…] (TD=%v) in %9v: %3d txs %d uncles.", block.Number(), block.Hash().Bytes()[0:4], block.Difficulty(), common.PrettyDuration(time.Since(bstart)), len(block.Transactions()), len(block.Uncles()))
} }
blockInsertTimer.UpdateSince(bstart) blockInsertTimer.UpdateSince(bstart)
events = append(events, ChainSideEvent{block, logs}) events = append(events, ChainSideEvent{block})
case SplitStatTy: case SplitStatTy:
events = append(events, ChainSplitEvent{block, logs}) events = append(events, ChainSplitEvent{block, logs})
@ -1044,7 +1065,7 @@ type insertStats struct {
queued, processed, ignored int queued, processed, ignored int
usedGas uint64 usedGas uint64
lastIndex int lastIndex int
startTime time.Time startTime mclock.AbsTime
} }
// statsReportLimit is the time limit during import after which we always print // statsReportLimit is the time limit during import after which we always print
@ -1056,28 +1077,24 @@ const statsReportLimit = 8 * time.Second
func (st *insertStats) report(chain []*types.Block, index int) { func (st *insertStats) report(chain []*types.Block, index int) {
// Fetch the timings for the batch // Fetch the timings for the batch
var ( var (
now = time.Now() now = mclock.Now()
elapsed = now.Sub(st.startTime) elapsed = time.Duration(now) - time.Duration(st.startTime)
) )
if elapsed == 0 { // Yes Windows, I'm looking at you
elapsed = 1
}
// If we're at the last block of the batch or report period reached, log // If we're at the last block of the batch or report period reached, log
if index == len(chain)-1 || elapsed >= statsReportLimit { if index == len(chain)-1 || elapsed >= statsReportLimit {
start, end := chain[st.lastIndex], chain[index] start, end := chain[st.lastIndex], chain[index]
txcount := countTransactions(chain[st.lastIndex : index+1]) txcount := countTransactions(chain[st.lastIndex : index+1])
extra := "" var hashes, extra string
if st.queued > 0 || st.ignored > 0 { if st.queued > 0 || st.ignored > 0 {
extra = fmt.Sprintf(" (%d queued %d ignored)", st.queued, st.ignored) extra = fmt.Sprintf(" (%d queued %d ignored)", st.queued, st.ignored)
} }
hashes := ""
if st.processed > 1 { if st.processed > 1 {
hashes = fmt.Sprintf("%x… / %x…", start.Hash().Bytes()[:4], end.Hash().Bytes()[:4]) hashes = fmt.Sprintf("%x… / %x…", start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
} else { } else {
hashes = fmt.Sprintf("%x…", end.Hash().Bytes()[:4]) hashes = fmt.Sprintf("%x…", end.Hash().Bytes()[:4])
} }
glog.Infof("imported %d blocks, %5d txs (%7.3f Mg) in %9v (%6.3f Mg/s). #%v [%s]%s", st.processed, txcount, float64(st.usedGas)/1000000, common.PrettyDuration(elapsed), float64(st.usedGas)*1000/float64(elapsed), end.Number(), hashes, extra) glog.Infof("imported %4d blocks, %5d txs (%7.3f Mg) in %9v (%6.3f Mg/s). #%v [%s]%s", st.processed, txcount, float64(st.usedGas)/1000000, common.PrettyDuration(elapsed), float64(st.usedGas)*1000/float64(elapsed), end.Number(), hashes, extra)
*st = insertStats{startTime: now, lastIndex: index} *st = insertStats{startTime: now, lastIndex: index}
} }
@ -1101,18 +1118,19 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
oldStart = oldBlock oldStart = oldBlock
newStart = newBlock newStart = newBlock
deletedTxs types.Transactions deletedTxs types.Transactions
deletedLogs vm.Logs deletedLogs []*types.Log
deletedLogsByHash = make(map[common.Hash]vm.Logs)
// collectLogs collects the logs that were generated during the // collectLogs collects the logs that were generated during the
// processing of the block that corresponds with the given hash. // processing of the block that corresponds with the given hash.
// These logs are later announced as deleted. // These logs are later announced as deleted.
collectLogs = func(h common.Hash) { collectLogs = func(h common.Hash) {
// Coalesce logs // Coalesce logs and set 'Removed'.
receipts := GetBlockReceipts(self.chainDb, h, self.hc.GetBlockNumber(h)) receipts := GetBlockReceipts(self.chainDb, h, self.hc.GetBlockNumber(h))
for _, receipt := range receipts { for _, receipt := range receipts {
deletedLogs = append(deletedLogs, receipt.Logs...) for _, log := range receipt.Logs {
del := *log
deletedLogsByHash[h] = receipt.Logs del.Removed = true
deletedLogs = append(deletedLogs, &del)
}
} }
} }
) )
@ -1206,7 +1224,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
if len(oldChain) > 0 { if len(oldChain) > 0 {
go func() { go func() {
for _, block := range oldChain { for _, block := range oldChain {
self.eventMux.Post(ChainSideEvent{Block: block, Logs: deletedLogsByHash[block.Hash()]}) self.eventMux.Post(ChainSideEvent{Block: block})
} }
}() }()
} }
@ -1216,7 +1234,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
// postChainEvents iterates over the events generated by a chain insertion and // postChainEvents iterates over the events generated by a chain insertion and
// posts them into the event mux. // posts them into the event mux.
func (self *BlockChain) postChainEvents(events []interface{}, logs vm.Logs) { func (self *BlockChain) postChainEvents(events []interface{}, logs []*types.Log) {
// post event logs for further processing // post event logs for further processing
self.eventMux.Post(logs) self.eventMux.Post(logs)
for _, event := range events { for _, event := range events {

View file

@ -435,7 +435,7 @@ func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return n
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error { func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
return nil return nil
} }
func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {
return nil, nil, new(big.Int), nil return nil, nil, new(big.Int), nil
} }
@ -719,7 +719,7 @@ func TestFastVsFullChains(t *testing.T) {
// If the block number is multiple of 3, send a few bonus transactions to the miner // If the block number is multiple of 3, send a few bonus transactions to the miner
if i%3 == 2 { if i%3 == 2 {
for j := 0; j < i%4+1; j++ { for j := 0; j < i%4+1; j++ {
tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key) tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -883,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
// Create two transactions shared between the chains: // Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain // - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number in the forked chain // - swapped: transaction included at the same block number in the forked chain
postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
// Create two transactions that will be dropped by the forked chain: // Create two transactions that will be dropped by the forked chain:
// - pastDrop: transaction dropped retroactively from a past block // - pastDrop: transaction dropped retroactively from a past block
@ -900,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2) pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
case 2: case 2:
freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2) freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
gen.AddTx(swapped) // This transaction will be swapped out at the exact height gen.AddTx(swapped) // This transaction will be swapped out at the exact height
@ -925,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) {
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) { chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3) pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
case 2: case 2:
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3) freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
case 3: case 3:
futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3) futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3)
gen.AddTx(futureAdd) // This transaction will be added after a full reorg gen.AddTx(futureAdd) // This transaction will be added after a full reorg
} }
}) })
@ -995,7 +995,7 @@ func TestLogReorgs(t *testing.T) {
subs := evmux.Subscribe(RemovedLogsEvent{}) subs := evmux.Subscribe(RemovedLogsEvent{})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
if i == 1 { if i == 1 {
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(signer, key1) tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code), signer, key1)
if err != nil { if err != nil {
t.Fatalf("failed to create tx: %v", err) t.Fatalf("failed to create tx: %v", err)
} }
@ -1035,7 +1035,7 @@ func TestReorgSideEvent(t *testing.T) {
} }
replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) { replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(signer, key1) tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
if i == 2 { if i == 2 {
gen.OffsetTime(-1) gen.OffsetTime(-1)
} }
@ -1107,7 +1107,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
for i, _ := range chain { for i := range chain {
go func(block *types.Block) { go func(block *types.Block) {
// try to retrieve a block by its canonical hash and see if the block data can be retrieved. // try to retrieve a block by its canonical hash and see if the block data can be retrieved.
for { for {
@ -1152,7 +1152,7 @@ func TestEIP155Transition(t *testing.T) {
tx *types.Transaction tx *types.Transaction
err error err error
basicTx = func(signer types.Signer) (*types.Transaction, error) { basicTx = func(signer types.Signer) (*types.Transaction, error) {
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
} }
) )
switch i { switch i {
@ -1215,7 +1215,7 @@ func TestEIP155Transition(t *testing.T) {
tx *types.Transaction tx *types.Transaction
err error err error
basicTx = func(signer types.Signer) (*types.Transaction, error) { basicTx = func(signer types.Signer) (*types.Transaction, error) {
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
} }
) )
switch i { switch i {
@ -1260,11 +1260,11 @@ func TestEIP161AccountRemoval(t *testing.T) {
) )
switch i { switch i {
case 0: case 0:
tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
case 1: case 1:
tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
case 2: case 2:
tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key)
} }
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -106,7 +106,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
b.SetCoinbase(common.Address{}) b.SetCoinbase(common.Address{})
} }
b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs)) b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
receipt, _, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) receipt, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -55,13 +55,13 @@ func ExampleGenerateChain() {
switch i { switch i {
case 0: case 0:
// In block 1, addr1 sends addr2 some ether. // In block 1, addr1 sends addr2 some ether.
tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, key1) tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
gen.AddTx(tx) gen.AddTx(tx)
case 1: case 1:
// In block 2, addr1 sends some more ether to addr2. // In block 2, addr1 sends some more ether to addr2.
// addr2 passes it on to addr3. // addr2 passes it on to addr3.
tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2) tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
gen.AddTx(tx1) gen.AddTx(tx1)
gen.AddTx(tx2) gen.AddTx(tx2)
case 2: case 2:

View file

@ -23,6 +23,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"sync"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/core/types"
@ -63,6 +64,8 @@ var (
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually] oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
mipmapBloomMu sync.Mutex // protect against race condition when updating mipmap blooms
) )
// encodeBlockNumber encodes a block number as big endian uint64 // encodeBlockNumber encodes a block number as big endian uint64
@ -564,6 +567,9 @@ func mipmapKey(num, level uint64) []byte {
// WriteMapmapBloom writes each address included in the receipts' logs to the // WriteMapmapBloom writes each address included in the receipts' logs to the
// MIP bloom bin. // MIP bloom bin.
func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts) error { func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts) error {
mipmapBloomMu.Lock()
defer mipmapBloomMu.Unlock()
batch := db.NewBatch() batch := db.NewBatch()
for _, level := range MIPMapLevels { for _, level := range MIPMapLevels {
key := mipmapKey(number, level) key := mipmapKey(number, level)

View file

@ -26,7 +26,6 @@ import (
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/core/vm"
"github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/crypto"
"github.com/ubiq/go-ubiq/crypto/sha3" "github.com/ubiq/go-ubiq/crypto/sha3"
"github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/ethdb"
@ -393,9 +392,9 @@ func TestReceiptStorage(t *testing.T) {
receipt1 := &types.Receipt{ receipt1 := &types.Receipt{
PostState: []byte{0x01}, PostState: []byte{0x01},
CumulativeGasUsed: big.NewInt(1), CumulativeGasUsed: big.NewInt(1),
Logs: vm.Logs{ Logs: []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte{0x11})}, {Address: common.BytesToAddress([]byte{0x11})},
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, {Address: common.BytesToAddress([]byte{0x01, 0x11})},
}, },
TxHash: common.BytesToHash([]byte{0x11, 0x11}), TxHash: common.BytesToHash([]byte{0x11, 0x11}),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
@ -404,9 +403,9 @@ func TestReceiptStorage(t *testing.T) {
receipt2 := &types.Receipt{ receipt2 := &types.Receipt{
PostState: []byte{0x02}, PostState: []byte{0x02},
CumulativeGasUsed: big.NewInt(2), CumulativeGasUsed: big.NewInt(2),
Logs: vm.Logs{ Logs: []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte{0x22})}, {Address: common.BytesToAddress([]byte{0x22})},
&vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})}, {Address: common.BytesToAddress([]byte{0x02, 0x22})},
}, },
TxHash: common.BytesToHash([]byte{0x22, 0x22}), TxHash: common.BytesToHash([]byte{0x22, 0x22}),
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
@ -431,7 +430,7 @@ func TestReceiptStorage(t *testing.T) {
rlpHave, _ := rlp.EncodeToBytes(r) rlpHave, _ := rlp.EncodeToBytes(r)
rlpWant, _ := rlp.EncodeToBytes(receipt) rlpWant, _ := rlp.EncodeToBytes(receipt)
if bytes.Compare(rlpHave, rlpWant) != 0 { if !bytes.Equal(rlpHave, rlpWant) {
t.Fatalf("receipt #%d [%x]: receipt mismatch: have %v, want %v", i, receipt.TxHash, r, receipt) t.Fatalf("receipt #%d [%x]: receipt mismatch: have %v, want %v", i, receipt.TxHash, r, receipt)
} }
} }
@ -452,9 +451,9 @@ func TestBlockReceiptStorage(t *testing.T) {
receipt1 := &types.Receipt{ receipt1 := &types.Receipt{
PostState: []byte{0x01}, PostState: []byte{0x01},
CumulativeGasUsed: big.NewInt(1), CumulativeGasUsed: big.NewInt(1),
Logs: vm.Logs{ Logs: []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte{0x11})}, {Address: common.BytesToAddress([]byte{0x11})},
&vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, {Address: common.BytesToAddress([]byte{0x01, 0x11})},
}, },
TxHash: common.BytesToHash([]byte{0x11, 0x11}), TxHash: common.BytesToHash([]byte{0x11, 0x11}),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
@ -463,9 +462,9 @@ func TestBlockReceiptStorage(t *testing.T) {
receipt2 := &types.Receipt{ receipt2 := &types.Receipt{
PostState: []byte{0x02}, PostState: []byte{0x02},
CumulativeGasUsed: big.NewInt(2), CumulativeGasUsed: big.NewInt(2),
Logs: vm.Logs{ Logs: []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte{0x22})}, {Address: common.BytesToAddress([]byte{0x22})},
&vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})}, {Address: common.BytesToAddress([]byte{0x02, 0x22})},
}, },
TxHash: common.BytesToHash([]byte{0x22, 0x22}), TxHash: common.BytesToHash([]byte{0x22, 0x22}),
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
@ -489,7 +488,7 @@ func TestBlockReceiptStorage(t *testing.T) {
rlpHave, _ := rlp.EncodeToBytes(rs[i]) rlpHave, _ := rlp.EncodeToBytes(rs[i])
rlpWant, _ := rlp.EncodeToBytes(receipts[i]) rlpWant, _ := rlp.EncodeToBytes(receipts[i])
if bytes.Compare(rlpHave, rlpWant) != 0 { if !bytes.Equal(rlpHave, rlpWant) {
t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i]) t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i])
} }
} }
@ -505,14 +504,14 @@ func TestMipmapBloom(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
receipt1 := new(types.Receipt) receipt1 := new(types.Receipt)
receipt1.Logs = vm.Logs{ receipt1.Logs = []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte("test"))}, {Address: common.BytesToAddress([]byte("test"))},
&vm.Log{Address: common.BytesToAddress([]byte("address"))}, {Address: common.BytesToAddress([]byte("address"))},
} }
receipt2 := new(types.Receipt) receipt2 := new(types.Receipt)
receipt2.Logs = vm.Logs{ receipt2.Logs = []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte("test"))}, {Address: common.BytesToAddress([]byte("test"))},
&vm.Log{Address: common.BytesToAddress([]byte("address1"))}, {Address: common.BytesToAddress([]byte("address1"))},
} }
WriteMipmapBloom(db, 1, types.Receipts{receipt1}) WriteMipmapBloom(db, 1, types.Receipts{receipt1})
@ -528,14 +527,14 @@ func TestMipmapBloom(t *testing.T) {
// reset // reset
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
receipt := new(types.Receipt) receipt := new(types.Receipt)
receipt.Logs = vm.Logs{ receipt.Logs = []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte("test"))}, {Address: common.BytesToAddress([]byte("test"))},
} }
WriteMipmapBloom(db, 999, types.Receipts{receipt1}) WriteMipmapBloom(db, 999, types.Receipts{receipt1})
receipt = new(types.Receipt) receipt = new(types.Receipt)
receipt.Logs = vm.Logs{ receipt.Logs = []*types.Log{
&vm.Log{Address: common.BytesToAddress([]byte("test 1"))}, {Address: common.BytesToAddress([]byte("test 1"))},
} }
WriteMipmapBloom(db, 1000, types.Receipts{receipt}) WriteMipmapBloom(db, 1000, types.Receipts{receipt})
@ -568,17 +567,12 @@ func TestMipmapChain(t *testing.T) {
switch i { switch i {
case 1: case 1:
receipt := types.NewReceipt(nil, new(big.Int)) receipt := types.NewReceipt(nil, new(big.Int))
receipt.Logs = vm.Logs{ receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}}
&vm.Log{
Address: addr,
Topics: []common.Hash{hash1},
},
}
gen.AddUncheckedReceipt(receipt) gen.AddUncheckedReceipt(receipt)
receipts = types.Receipts{receipt} receipts = types.Receipts{receipt}
case 1000: case 1000:
receipt := types.NewReceipt(nil, new(big.Int)) receipt := types.NewReceipt(nil, new(big.Int))
receipt.Logs = vm.Logs{&vm.Log{Address: addr2}} receipt.Logs = []*types.Log{{Address: addr2}}
gen.AddUncheckedReceipt(receipt) gen.AddUncheckedReceipt(receipt)
receipts = types.Receipts{receipt} receipts = types.Receipts{receipt}

View file

@ -20,4 +20,9 @@ package core
// genesis block. // genesis block.
const defaultGenesisBlock = "H4sIACZxSlgAA61Sy24bMQy8+ysMn3OgKJKiegvQQw/9CerBZgE/gngLuAjy75XjGEiRtnAX5UHAUuTMzoyeV+tRm/1hX/vm03oDJ3hfqrq5u4zM064fZ9s9XsZY6T4Bpev1oz31/fzFjg+/gVlQV9x+mp/ss832Bnvtf7Pj12k3zZe2/rrUJvepft/OPy7X/hdEssTSBMcZpaRITLy5O09exnfT6eG/q6qHaV/s+GZ5vLGu27bdHupYfX79fG0NHUm8xZ65t2ih556EsqbiHjFCGVEyeKN23ltvim3tLfLw579dv9y9p0ACtCJSA9YaqAg7YE2eWonmWaBCZaT4gYJvJOhiA7drYiIs7JkVWs0NzopsHA3RM5TFBOCdJRQ0RHMD6hW4uFZXwVZjGQ4lz+GjSbcScNco4iODTBULuVPSyooKgcgNBUIQDosJQiXmDmZlOM4t5NKFyZR7IfQhpKfQe11uUQSLKedm7EKgXc4UQTlWSnVwaonKQfNyBRIpAvL5RZbhR1JOBo4gjUNHHXJi0bjcIiQE1/HisWGuGag0hhiGLizqaNWrFMnLQ3Zz6S7ckqJpD1IoSBUzAiEeIacgiv9G8Ir/snpZ/QSJtNFBkgUAAA==" const defaultGenesisBlock = "H4sIACZxSlgAA61Sy24bMQy8+ysMn3OgKJKiegvQQw/9CerBZgE/gngLuAjy75XjGEiRtnAX5UHAUuTMzoyeV+tRm/1hX/vm03oDJ3hfqrq5u4zM064fZ9s9XsZY6T4Bpev1oz31/fzFjg+/gVlQV9x+mp/ss832Bnvtf7Pj12k3zZe2/rrUJvepft/OPy7X/hdEssTSBMcZpaRITLy5O09exnfT6eG/q6qHaV/s+GZ5vLGu27bdHupYfX79fG0NHUm8xZ65t2ih556EsqbiHjFCGVEyeKN23ltvim3tLfLw579dv9y9p0ACtCJSA9YaqAg7YE2eWonmWaBCZaT4gYJvJOhiA7drYiIs7JkVWs0NzopsHA3RM5TFBOCdJRQ0RHMD6hW4uFZXwVZjGQ4lz+GjSbcScNco4iODTBULuVPSyooKgcgNBUIQDosJQiXmDmZlOM4t5NKFyZR7IfQhpKfQe11uUQSLKedm7EKgXc4UQTlWSnVwaonKQfNyBRIpAvL5RZbhR1JOBo4gjUNHHXJi0bjcIiQE1/HisWGuGag0hhiGLizqaNWrFMnLQ3Zz6S7ckqJpD1IoSBUzAiEeIacgiv9G8Ir/snpZ/QSJtNFBkgUAAA=="
// defaultTestnetGenesisBlock is a gzip compressed dump of the official default Ethereum
// test network genesis block (currently Ropsten).
const defaultTestnetGenesisBlock = "QlpoOTFBWSZTWezl5v8AGI59gHRQABBcBH/0FGQ/795qUAN+PcGHAoQMVIwm0zCSp+ihiAANB6gqp+mmp6eMmqo0AADRpoABgAGjTQBk0BoMgNAbSqNAyDQyaBoNAyAGBUkhNNNA0JGmgD0g0AekxJtVIgTtRupd52vqSSSVfG2ALQBhhdbCIgmAgUiIJnEQTviQF8kkN1IOKiRVVFVSVXHT1cHLHdiSQBlAAG2JtCtNgCS5IEB6dNtP782Z729Tbt3Z6+uFr7u3w79widyYSMAhtlL5XeGZWdwEBNdFm+Hh5gVRBoslgksAMkUKmYlSJRTxBsQAAKKlnd3WjPWrNd66NR7WAu6AQL40vqlny1We+p3l1QThy4gRd2lSVjEKISLDFrVJ1UtjPEPctVSZGjBTJWRzpdgRmCCprJWGe3DK9wvz4eGvdv1ZZcMvxGgdakeMAVEeFywVQWLWCrUWg60Y9ZLoAuZ0uSJJUELb8N2e7j05d3Tlz7vRwgk+LisedJALLVUgFjLGzfv5SEGPLlhhjpx2aaO8T87whcYDmgPLVDBI3RF1TLnzvymWtN732u93GiAGiBdm5s1q9Haru7+yCLJAk3wBDTtrGeMVh3iJmXHo+OBAsqoDOZwjKM3d3mZmcHdBJiSVouSKVkDg+L4vSzNRqs7u6NEaIiUKoYxERGfTWIhoiHwQFESGzta21qu1qtZ3cAXQshVAUybTLbWttWh3iHLoDJEgkACRVCzbeX774Z6558+mfDTdz058efTpDbXai+tddbQBbn/YA9fwxy8/Pq3HFW7deL8W447duuyI2RGqIAAA9SOqHeXzbRtGiXeHiYBMggAAIyQh/f5vW96Xvvu7b7777yMURRHFE6EkEnxRIiOlY2ijs7RV4gYIB0R4LmgB49xg0Oz0bVr2a95u4AZE6rTjl2w58Cntu1ZV6e3Lw3ne2RegHw7R58NdbtVlJEkuqRV2WKa/hpbPIx3bIyX43aNWmezrCBry2ePzkA8reSwB/xdyRThQkOzl5v8=" const defaultTestnetGenesisBlock = "QlpoOTFBWSZTWezl5v8AGI59gHRQABBcBH/0FGQ/795qUAN+PcGHAoQMVIwm0zCSp+ihiAANB6gqp+mmp6eMmqo0AADRpoABgAGjTQBk0BoMgNAbSqNAyDQyaBoNAyAGBUkhNNNA0JGmgD0g0AekxJtVIgTtRupd52vqSSSVfG2ALQBhhdbCIgmAgUiIJnEQTviQF8kkN1IOKiRVVFVSVXHT1cHLHdiSQBlAAG2JtCtNgCS5IEB6dNtP782Z729Tbt3Z6+uFr7u3w79widyYSMAhtlL5XeGZWdwEBNdFm+Hh5gVRBoslgksAMkUKmYlSJRTxBsQAAKKlnd3WjPWrNd66NR7WAu6AQL40vqlny1We+p3l1QThy4gRd2lSVjEKISLDFrVJ1UtjPEPctVSZGjBTJWRzpdgRmCCprJWGe3DK9wvz4eGvdv1ZZcMvxGgdakeMAVEeFywVQWLWCrUWg60Y9ZLoAuZ0uSJJUELb8N2e7j05d3Tlz7vRwgk+LisedJALLVUgFjLGzfv5SEGPLlhhjpx2aaO8T87whcYDmgPLVDBI3RF1TLnzvymWtN732u93GiAGiBdm5s1q9Haru7+yCLJAk3wBDTtrGeMVh3iJmXHo+OBAsqoDOZwjKM3d3mZmcHdBJiSVouSKVkDg+L4vSzNRqs7u6NEaIiUKoYxERGfTWIhoiHwQFESGzta21qu1qtZ3cAXQshVAUybTLbWttWh3iHLoDJEgkACRVCzbeX774Z6558+mfDTdz058efTpDbXai+tddbQBbn/YA9fwxy8/Pq3HFW7deL8W447duuyI2RGqIAAA9SOqHeXzbRtGiXeHiYBMggAAIyQh/f5vW96Xvvu7b7777yMURRHFE6EkEnxRIiOlY2ijs7RV4gYIB0R4LmgB49xg0Oz0bVr2a95u4AZE6rTjl2w58Cntu1ZV6e3Lw3ne2RegHw7R58NdbtVlJEkuqRV2WKa/hpbPIx3bIyX43aNWmezrCBry2ePzkA8reSwB/xdyRThQkOzl5v8="
// defaultDevnetGenesisBlockis a gzip compressed dump of a dev Ethereum network genesis block.
const defaultDevnetGenesisBlock = "QlpoOTFBWSZTWb66siUAAmldgEERWAR/8AAEP6eOakACGu6ULVwyRNGKeBCbUaAGIJUDJpT2lP1BQAAANqp6jTUxMIxGmAJgFVTAp4mjSaoAxAB4cLqQ6aBgTRPcAECErBIZ9PyZJw5IYvQPWlcXDXnhaC9buNtJaAFApAgwkUIRBmBY6EhTY8/6ZXse6lLD1Eh3sfas7VHnxse2LZeXpME9fADujvYB4Wr9cgQA+Wq0gRnrfVmgVwIiIrgfON+c4EhrApvQT2LjUh6y3x41XXOxriA89W52MDId9R7vasE3pfWWATQF7nAEAWRb861EU6M9SmBTET1UUGuBmgxzewhmUe4Rj4jSvgRFRTYgI8WzzcQn3nNr6x3GW94Yp1xG4kOoC/MxDhbF8uMahuMTmKyEep0SwLaxquoT3F9X0NxmouMWhxTAlxHQoN872vbYJS/Wrls2LuptmbKr4R6BJ/oJfPNpq+H362F5ZyhNQBxXep4ZOr94ylFM6UfOeUq37kFeGzXOle3LKItkvJ70OKqEqzujic72rnpZHym6b3xSONoWjYzRzIUbOKSUgdVtEhtvUg24asA2cy1zFzsfnj8CXe0Bdi7kinChIX11ZEo="

View file

@ -21,7 +21,6 @@ import (
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/core/vm"
) )
// TxPreEvent is posted when a transaction enters the transaction pool. // TxPreEvent is posted when a transaction enters the transaction pool.
@ -32,7 +31,7 @@ type TxPostEvent struct{ Tx *types.Transaction }
// PendingLogsEvent is posted pre mining and notifies of pending logs. // PendingLogsEvent is posted pre mining and notifies of pending logs.
type PendingLogsEvent struct { type PendingLogsEvent struct {
Logs vm.Logs Logs []*types.Log
} }
// PendingStateEvent is posted pre mining and notifies of pending state changes. // PendingStateEvent is posted pre mining and notifies of pending state changes.
@ -45,28 +44,27 @@ type NewMinedBlockEvent struct{ Block *types.Block }
type RemovedTransactionEvent struct{ Txs types.Transactions } type RemovedTransactionEvent struct{ Txs types.Transactions }
// RemovedLogEvent is posted when a reorg happens // RemovedLogEvent is posted when a reorg happens
type RemovedLogsEvent struct{ Logs vm.Logs } type RemovedLogsEvent struct{ Logs []*types.Log }
// ChainSplit is posted when a new head is detected // ChainSplit is posted when a new head is detected
type ChainSplitEvent struct { type ChainSplitEvent struct {
Block *types.Block Block *types.Block
Logs vm.Logs Logs []*types.Log
} }
type ChainEvent struct { type ChainEvent struct {
Block *types.Block Block *types.Block
Hash common.Hash Hash common.Hash
Logs vm.Logs Logs []*types.Log
} }
type ChainSideEvent struct { type ChainSideEvent struct {
Block *types.Block Block *types.Block
Logs vm.Logs
} }
type PendingBlockEvent struct { type PendingBlockEvent struct {
Block *types.Block Block *types.Block
Logs vm.Logs Logs []*types.Log
} }
type ChainUncleEvent struct { type ChainUncleEvent struct {

73
core/evm.go Normal file
View file

@ -0,0 +1,73 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"math/big"
"github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/core/vm"
)
// BlockFetcher retrieves headers by their hash
type HeaderFetcher interface {
// GetHeader returns the hash corresponding to their hash
GetHeader(common.Hash, uint64) *types.Header
}
// NewEVMContext creates a new context for use in the EVM.
func NewEVMContext(msg Message, header *types.Header, chain HeaderFetcher) vm.Context {
return vm.Context{
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
Origin: msg.From(),
Coinbase: header.Coinbase,
BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).Set(header.Time),
Difficulty: new(big.Int).Set(header.Difficulty),
GasLimit: new(big.Int).Set(header.GasLimit),
GasPrice: new(big.Int).Set(msg.GasPrice()),
}
}
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain HeaderFetcher) func(n uint64) common.Hash {
return func(n uint64) common.Hash {
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
if header.Number.Uint64() == n {
return header.Hash()
}
}
return common.Hash{}
}
}
// CanTransfer checks wether there are enough funds in the address' account to make a transfer.
// This does not take the necessary gas in to account to make the transfer valid.
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
return db.GetBalance(addr).Cmp(amount) >= 0
}
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
db.SubBalance(sender, amount)
db.AddBalance(recipient, amount)
}

View file

@ -1,217 +0,0 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"math/big"
"github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/vm"
"github.com/ubiq/go-ubiq/crypto"
"github.com/ubiq/go-ubiq/params"
)
// Call executes within the given contract
func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice)
return nil, vm.DepthError
}
if !env.CanTransfer(caller.Address(), value) {
caller.ReturnGas(gas, gasPrice)
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
}
snapshotPreTransfer := env.SnapshotDatabase()
var (
from = env.Db().GetAccount(caller.Address())
to vm.Account
)
if !env.Db().Exist(addr) {
if vm.Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber()) && value.BitLen() == 0 {
caller.ReturnGas(gas, gasPrice)
return nil, nil
}
to = env.Db().CreateAccount(addr)
} else {
to = env.Db().GetAccount(addr)
}
env.Transfer(from, to, value)
// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
defer contract.Finalise()
ret, err = env.Vm().Run(contract, input)
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
if err != nil {
contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshotPreTransfer)
}
return ret, err
}
// CallCode executes the given address' code as the given contract address
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice)
return nil, vm.DepthError
}
if !env.CanTransfer(caller.Address(), value) {
caller.ReturnGas(gas, gasPrice)
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
}
var (
snapshotPreTransfer = env.SnapshotDatabase()
to = env.Db().GetAccount(caller.Address())
)
// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
defer contract.Finalise()
ret, err = env.Vm().Run(contract, input)
if err != nil {
contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshotPreTransfer)
}
return ret, err
}
// Create creates a new contract with the given code
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, vm.DepthError
}
if !env.CanTransfer(caller.Address(), value) {
caller.ReturnGas(gas, gasPrice)
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
}
// Create a new account on the state
nonce := env.Db().GetNonce(caller.Address())
env.Db().SetNonce(caller.Address(), nonce+1)
snapshotPreTransfer := env.SnapshotDatabase()
var (
addr = crypto.CreateAddress(caller.Address(), nonce)
from = env.Db().GetAccount(caller.Address())
to = env.Db().CreateAccount(addr)
)
if env.ChainConfig().IsEIP158(env.BlockNumber()) {
env.Db().SetNonce(addr, 1)
}
env.Transfer(from, to, value)
// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := vm.NewContract(caller, to, value, gas, gasPrice)
contract.SetCallCode(&addr, crypto.Keccak256Hash(code), code)
defer contract.Finalise()
ret, err = env.Vm().Run(contract, nil)
// check whether the max code size has been exceeded
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
// if the contract creation ran successfully and no errors were returned
// calculate the gas required to store the code. If the code could not
// be stored due to not enough gas set an error and let it be handled
// by the error checking condition below.
if err == nil && !maxCodeSizeExceeded {
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, params.CreateDataGas)
if contract.UseGas(dataGas) {
env.Db().SetCode(addr, ret)
} else {
err = vm.CodeStoreOutOfGasError
}
}
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
if maxCodeSizeExceeded ||
(err != nil && (env.ChainConfig().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError)) {
contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshotPreTransfer)
// Nothing should be returned when an error is thrown.
return nil, addr, err
}
return ret, addr, err
}
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
// Depth check execution. Fail if we're trying to execute above the
// limit.
if env.Depth() > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas, gasPrice)
return nil, vm.DepthError
}
var (
snapshot = env.SnapshotDatabase()
to = env.Db().GetAccount(caller.Address())
)
// Iinitialise a new contract and make initialise the delegate values
contract := vm.NewContract(caller, to, caller.Value(), gas, gasPrice).AsDelegate()
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
defer contract.Finalise()
ret, err = env.Vm().Run(contract, input)
if err != nil {
contract.UseGas(contract.Gas)
env.RevertToSnapshot(snapshot)
}
return ret, err
}
// generic transfer method
func Transfer(from, to vm.Account, amount *big.Int) {
from.SubBalance(amount)
to.AddBalance(amount)
}

View file

@ -172,18 +172,12 @@ func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock())) return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock()))
} }
// WriteTestNetGenesisBlock assembles the Morden test network genesis block and // WriteTestNetGenesisBlock assembles the test network genesis block and
// writes it - along with all associated state - into a chain database. // writes it - along with all associated state - into a chain database.
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) { func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) {
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock())) return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock()))
} }
// WriteOlympicGenesisBlock assembles the Olympic genesis block and writes it
// along with all associated state into a chain database.
func WriteOlympicGenesisBlock(db ethdb.Database) (*types.Block, error) {
return WriteGenesisBlock(db, strings.NewReader(OlympicGenesisBlock()))
}
// DefaultGenesisBlock assembles a JSON string representing the default Ethereum // DefaultGenesisBlock assembles a JSON string representing the default Ethereum
// genesis block. // genesis block.
func DefaultGenesisBlock() string { func DefaultGenesisBlock() string {
@ -198,6 +192,8 @@ func DefaultGenesisBlock() string {
return string(blob) return string(blob)
} }
// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum
// test network genesis block.
func DefaultTestnetGenesisBlock() string { func DefaultTestnetGenesisBlock() string {
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock))) reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock)))
blob, err := ioutil.ReadAll(reader) blob, err := ioutil.ReadAll(reader)
@ -207,26 +203,12 @@ func DefaultTestnetGenesisBlock() string {
return string(blob) return string(blob)
} }
// OlympicGenesisBlock assembles a JSON string representing the Olympic genesis // DevGenesisBlock assembles a JSON string representing a local dev genesis block.
// block. func DevGenesisBlock() string {
func OlympicGenesisBlock() string { reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock)))
return fmt.Sprintf(`{ blob, err := ioutil.ReadAll(reader)
"nonce":"0x%x", if err != nil {
"gasLimit":"0x%x", panic(fmt.Sprintf("failed to load dev genesis: %v", err))
"difficulty":"0x%x",
"alloc": {
"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()) return string(blob)
} }

View file

@ -225,6 +225,17 @@ type WhCallback func(*types.Header) error
// of the header retrieval mechanisms already need to verfy nonces, as well as // of the header retrieval mechanisms already need to verfy nonces, as well as
// because nonces can be verified sparsely, not needing to check each. // because nonces can be verified sparsely, not needing to check each.
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, writeHeader WhCallback) (int, error) { func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, writeHeader WhCallback) (int, error) {
// Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(chain); i++ {
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() {
// Chain broke ancestry, log a messge (programming error) and skip insertion
failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])",
i-1, chain[i-1].Number.Uint64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].Number.Uint64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash.Bytes()[:4])
glog.V(logger.Error).Info(failure.Error())
return 0, failure
}
}
// Collect some import statistics to report on // Collect some import statistics to report on
stats := struct{ processed, ignored int }{} stats := struct{ processed, ignored int }{}
start := time.Now() start := time.Now()
@ -329,7 +340,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w
if stats.ignored > 0 { if stats.ignored > 0 {
ignored = fmt.Sprintf(" (%d ignored)", stats.ignored) ignored = fmt.Sprintf(" (%d ignored)", stats.ignored)
} }
glog.V(logger.Info).Infof("imported %d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4]) glog.V(logger.Info).Infof("imported %4d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4])
return 0, nil return 0, nil
} }

View file

@ -123,7 +123,7 @@ func (it *NodeIterator) step() error {
if !it.dataIt.Next() { if !it.dataIt.Next() {
it.dataIt = nil it.dataIt = nil
} }
if bytes.Compare(account.CodeHash, emptyCodeHash) != 0 { if !bytes.Equal(account.CodeHash, emptyCodeHash) {
it.codeHash = common.BytesToHash(account.CodeHash) it.codeHash = common.BytesToHash(account.CodeHash)
it.code, err = it.state.db.Get(account.CodeHash) it.code, err = it.state.db.Get(account.CodeHash)
if err != nil { if err != nil {

View file

@ -41,7 +41,7 @@ func TestNodeIteratorCoverage(t *testing.T) {
} }
} }
// Cross check the hashes and the database itself // Cross check the hashes and the database itself
for hash, _ := range hashes { for hash := range hashes {
if _, err := db.Get(hash.Bytes()); err != nil { if _, err := db.Get(hash.Bytes()); err != nil {
t.Errorf("failed to retrieve reported node %x: %v", hash, err) t.Errorf("failed to retrieve reported node %x: %v", hash, err)
} }

View file

@ -52,7 +52,7 @@ func TestRemove(t *testing.T) {
ms, account := create() ms, account := create()
nn := make([]bool, 10) nn := make([]bool, 10)
for i, _ := range nn { for i := range nn {
nn[i] = true nn[i] = true
} }
account.nonces = append(account.nonces, nn...) account.nonces = append(account.nonces, nn...)
@ -68,7 +68,7 @@ func TestReuse(t *testing.T) {
ms, account := create() ms, account := create()
nn := make([]bool, 10) nn := make([]bool, 10)
for i, _ := range nn { for i := range nn {
nn[i] = true nn[i] = true
} }
account.nonces = append(account.nonces, nn...) account.nonces = append(account.nonces, nn...)
@ -84,16 +84,16 @@ func TestReuse(t *testing.T) {
func TestRemoteNonceChange(t *testing.T) { func TestRemoteNonceChange(t *testing.T) {
ms, account := create() ms, account := create()
nn := make([]bool, 10) nn := make([]bool, 10)
for i, _ := range nn { for i := range nn {
nn[i] = true nn[i] = true
} }
account.nonces = append(account.nonces, nn...) account.nonces = append(account.nonces, nn...)
nonce := ms.NewNonce(addr) ms.NewNonce(addr)
ms.StateDB.stateObjects[addr].data.Nonce = 200 ms.StateDB.stateObjects[addr].data.Nonce = 200
nonce = ms.NewNonce(addr) nonce := ms.NewNonce(addr)
if nonce != 200 { if nonce != 200 {
t.Error("expected nonce after remote update to be", 201, "got", nonce) t.Error("expected nonce after remote update to be", 200, "got", nonce)
} }
ms.NewNonce(addr) ms.NewNonce(addr)
ms.NewNonce(addr) ms.NewNonce(addr)
@ -101,7 +101,7 @@ func TestRemoteNonceChange(t *testing.T) {
ms.StateDB.stateObjects[addr].data.Nonce = 200 ms.StateDB.stateObjects[addr].data.Nonce = 200
nonce = ms.NewNonce(addr) nonce = ms.NewNonce(addr)
if nonce != 204 { if nonce != 204 {
t.Error("expected nonce after remote update to be", 201, "got", nonce) t.Error("expected nonce after remote update to be", 204, "got", nonce)
} }
} }

View file

@ -288,7 +288,7 @@ func (self *StateObject) setBalance(amount *big.Int) {
} }
// Return the gas back to the origin. Used by the Virtual machine or Closures // Return the gas back to the origin. Used by the Virtual machine or Closures
func (c *StateObject) ReturnGas(gas, price *big.Int) {} func (c *StateObject) ReturnGas(gas *big.Int) {}
func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject { func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject {
stateObject := newObject(db, self.address, self.data, onDirty) stateObject := newObject(db, self.address, self.data, onDirty)

View file

@ -23,7 +23,9 @@ import (
"sort" "sort"
"sync" "sync"
lru "github.com/hashicorp/golang-lru"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/core/vm"
"github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/crypto"
"github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/ethdb"
@ -31,7 +33,6 @@ import (
"github.com/ubiq/go-ubiq/logger/glog" "github.com/ubiq/go-ubiq/logger/glog"
"github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/rlp"
"github.com/ubiq/go-ubiq/trie" "github.com/ubiq/go-ubiq/trie"
lru "github.com/hashicorp/golang-lru"
) )
// Trie cache generation limit after which to evic trie nodes from memory. // Trie cache generation limit after which to evic trie nodes from memory.
@ -71,7 +72,7 @@ type StateDB struct {
thash, bhash common.Hash thash, bhash common.Hash
txIndex int txIndex int
logs map[common.Hash]vm.Logs logs map[common.Hash][]*types.Log
logSize uint logSize uint
// Journal of state modifications. This is the backbone of // Journal of state modifications. This is the backbone of
@ -97,7 +98,7 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
stateObjects: make(map[common.Address]*StateObject), stateObjects: make(map[common.Address]*StateObject),
stateObjectsDirty: make(map[common.Address]struct{}), stateObjectsDirty: make(map[common.Address]struct{}),
refund: new(big.Int), refund: new(big.Int),
logs: make(map[common.Hash]vm.Logs), logs: make(map[common.Hash][]*types.Log),
}, nil }, nil
} }
@ -118,7 +119,7 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) {
stateObjects: make(map[common.Address]*StateObject), stateObjects: make(map[common.Address]*StateObject),
stateObjectsDirty: make(map[common.Address]struct{}), stateObjectsDirty: make(map[common.Address]struct{}),
refund: new(big.Int), refund: new(big.Int),
logs: make(map[common.Hash]vm.Logs), logs: make(map[common.Hash][]*types.Log),
}, nil }, nil
} }
@ -138,7 +139,7 @@ func (self *StateDB) Reset(root common.Hash) error {
self.thash = common.Hash{} self.thash = common.Hash{}
self.bhash = common.Hash{} self.bhash = common.Hash{}
self.txIndex = 0 self.txIndex = 0
self.logs = make(map[common.Hash]vm.Logs) self.logs = make(map[common.Hash][]*types.Log)
self.logSize = 0 self.logSize = 0
self.clearJournalAndRefund() self.clearJournalAndRefund()
@ -175,7 +176,7 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
self.txIndex = ti self.txIndex = ti
} }
func (self *StateDB) AddLog(log *vm.Log) { func (self *StateDB) AddLog(log *types.Log) {
self.journal = append(self.journal, addLogChange{txhash: self.thash}) self.journal = append(self.journal, addLogChange{txhash: self.thash})
log.TxHash = self.thash log.TxHash = self.thash
@ -186,12 +187,12 @@ func (self *StateDB) AddLog(log *vm.Log) {
self.logSize++ self.logSize++
} }
func (self *StateDB) GetLogs(hash common.Hash) vm.Logs { func (self *StateDB) GetLogs(hash common.Hash) []*types.Log {
return self.logs[hash] return self.logs[hash]
} }
func (self *StateDB) Logs() vm.Logs { func (self *StateDB) Logs() []*types.Log {
var logs vm.Logs var logs []*types.Log
for _, lgs := range self.logs { for _, lgs := range self.logs {
logs = append(logs, lgs...) logs = append(logs, lgs...)
} }
@ -209,7 +210,7 @@ func (self *StateDB) Exist(addr common.Address) bool {
return self.GetStateObject(addr) != nil return self.GetStateObject(addr) != nil
} }
// Empty returns whether the state object is either non-existant // Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0) // or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *StateDB) Empty(addr common.Address) bool { func (self *StateDB) Empty(addr common.Address) bool {
so := self.GetStateObject(addr) so := self.GetStateObject(addr)
@ -293,6 +294,7 @@ func (self *StateDB) HasSuicided(addr common.Address) bool {
* SETTERS * SETTERS
*/ */
// AddBalance adds amount to the account associated with addr
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetOrNewStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
@ -300,6 +302,14 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
} }
} }
// SubBalance subtracts amount from the account associated with addr
func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SubBalance(amount)
}
}
func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) { func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetOrNewStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
@ -465,16 +475,16 @@ func (self *StateDB) Copy() *StateDB {
stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)), stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
refund: new(big.Int).Set(self.refund), refund: new(big.Int).Set(self.refund),
logs: make(map[common.Hash]vm.Logs, len(self.logs)), logs: make(map[common.Hash][]*types.Log, len(self.logs)),
logSize: self.logSize, logSize: self.logSize,
} }
// Copy the dirty states and logs // Copy the dirty states and logs
for addr, _ := range self.stateObjectsDirty { for addr := range self.stateObjectsDirty {
state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty) state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty)
state.stateObjectsDirty[addr] = struct{}{} state.stateObjectsDirty[addr] = struct{}{}
} }
for hash, logs := range self.logs { for hash, logs := range self.logs {
state.logs[hash] = make(vm.Logs, len(logs)) state.logs[hash] = make([]*types.Log, len(logs))
copy(state.logs[hash], logs) copy(state.logs[hash], logs)
} }
return state return state
@ -520,7 +530,7 @@ func (self *StateDB) GetRefund() *big.Int {
// It is called in between transactions to get the root hash that // It is called in between transactions to get the root hash that
// goes into transaction receipts. // goes into transaction receipts.
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
for addr, _ := range s.stateObjectsDirty { for addr := range s.stateObjectsDirty {
stateObject := s.stateObjects[addr] stateObject := s.stateObjects[addr]
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) { if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
s.deleteStateObject(stateObject) s.deleteStateObject(stateObject)
@ -543,7 +553,7 @@ func (s *StateDB) DeleteSuicides() {
// Reset refund so that any used-gas calculations can use this method. // Reset refund so that any used-gas calculations can use this method.
s.clearJournalAndRefund() s.clearJournalAndRefund()
for addr, _ := range s.stateObjectsDirty { for addr := range s.stateObjectsDirty {
stateObject := s.stateObjects[addr] stateObject := s.stateObjects[addr]
// If the object has been removed by a suicide // If the object has been removed by a suicide

View file

@ -29,7 +29,7 @@ import (
"testing/quick" "testing/quick"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/core/types"
"github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/ethdb"
) )
@ -221,7 +221,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
fn: func(a testAction, s *StateDB) { fn: func(a testAction, s *StateDB) {
data := make([]byte, 2) data := make([]byte, 2)
binary.BigEndian.PutUint16(data, uint16(a.args[0])) binary.BigEndian.PutUint16(data, uint16(a.args[0]))
s.AddLog(&vm.Log{Address: addr, Data: data}) s.AddLog(&types.Log{Address: addr, Data: data})
}, },
args: make([]int64, 1), args: make([]int64, 1),
}, },

View file

@ -21,7 +21,6 @@ import (
"math/big" "math/big"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/ethdb"
"github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/rlp"
"github.com/ubiq/go-ubiq/trie" "github.com/ubiq/go-ubiq/trie"
) )
@ -32,7 +31,7 @@ import (
type StateSync trie.TrieSync type StateSync trie.TrieSync
// NewStateSync create a new state trie download scheduler. // NewStateSync create a new state trie download scheduler.
func NewStateSync(root common.Hash, database ethdb.Database) *StateSync { func NewStateSync(root common.Hash, database trie.DatabaseReader) *StateSync {
var syncer *trie.TrieSync var syncer *trie.TrieSync
callback := func(leaf []byte, parent common.Hash) error { callback := func(leaf []byte, parent common.Hash) error {
@ -62,8 +61,8 @@ func (s *StateSync) Missing(max int) []common.Hash {
// Process injects a batch of retrieved trie nodes data, returning if something // Process injects a batch of retrieved trie nodes data, returning if something
// was committed to the database and also the index of an entry if processing of // was committed to the database and also the index of an entry if processing of
// it failed. // it failed.
func (s *StateSync) Process(list []trie.SyncResult) (bool, int, error) { func (s *StateSync) Process(list []trie.SyncResult, dbw trie.DatabaseWriter) (bool, int, error) {
return (*trie.TrieSync)(s).Process(list) return (*trie.TrieSync)(s).Process(list, dbw)
} }
// Pending returns the number of state entries currently pending for download. // Pending returns the number of state entries currently pending for download.

View file

@ -84,7 +84,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou
if nonce := state.GetNonce(acc.address); nonce != acc.nonce { if nonce := state.GetNonce(acc.address); nonce != acc.nonce {
t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce) t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce)
} }
if code := state.GetCode(acc.address); bytes.Compare(code, acc.code) != 0 { if code := state.GetCode(acc.address); !bytes.Equal(code, acc.code) {
t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code) t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code)
} }
} }
@ -138,7 +138,7 @@ func testIterativeStateSync(t *testing.T, batch int) {
} }
results[i] = trie.SyncResult{Hash: hash, Data: data} results[i] = trie.SyncResult{Hash: hash, Data: data}
} }
if _, index, err := sched.Process(results); err != nil { if _, index, err := sched.Process(results, dstDb); err != nil {
t.Fatalf("failed to process result #%d: %v", index, err) t.Fatalf("failed to process result #%d: %v", index, err)
} }
queue = append(queue[:0], sched.Missing(batch)...) queue = append(queue[:0], sched.Missing(batch)...)
@ -168,7 +168,7 @@ func TestIterativeDelayedStateSync(t *testing.T) {
} }
results[i] = trie.SyncResult{Hash: hash, Data: data} results[i] = trie.SyncResult{Hash: hash, Data: data}
} }
if _, index, err := sched.Process(results); err != nil { if _, index, err := sched.Process(results, dstDb); err != nil {
t.Fatalf("failed to process result #%d: %v", index, err) t.Fatalf("failed to process result #%d: %v", index, err)
} }
queue = append(queue[len(results):], sched.Missing(0)...) queue = append(queue[len(results):], sched.Missing(0)...)
@ -198,7 +198,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
for len(queue) > 0 { for len(queue) > 0 {
// Fetch all the queued nodes in a random order // Fetch all the queued nodes in a random order
results := make([]trie.SyncResult, 0, len(queue)) results := make([]trie.SyncResult, 0, len(queue))
for hash, _ := range queue { for hash := range queue {
data, err := srcDb.Get(hash.Bytes()) data, err := srcDb.Get(hash.Bytes())
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for %x: %v", hash, err) t.Fatalf("failed to retrieve node data for %x: %v", hash, err)
@ -206,7 +206,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
results = append(results, trie.SyncResult{Hash: hash, Data: data}) results = append(results, trie.SyncResult{Hash: hash, Data: data})
} }
// Feed the retrieved results back and queue new tasks // Feed the retrieved results back and queue new tasks
if _, index, err := sched.Process(results); err != nil { if _, index, err := sched.Process(results, dstDb); err != nil {
t.Fatalf("failed to process result #%d: %v", index, err) t.Fatalf("failed to process result #%d: %v", index, err)
} }
queue = make(map[common.Hash]struct{}) queue = make(map[common.Hash]struct{})
@ -235,7 +235,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
for len(queue) > 0 { for len(queue) > 0 {
// Sync only half of the scheduled nodes, even those in random order // Sync only half of the scheduled nodes, even those in random order
results := make([]trie.SyncResult, 0, len(queue)/2+1) results := make([]trie.SyncResult, 0, len(queue)/2+1)
for hash, _ := range queue { for hash := range queue {
delete(queue, hash) delete(queue, hash)
data, err := srcDb.Get(hash.Bytes()) data, err := srcDb.Get(hash.Bytes())
@ -249,7 +249,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
} }
} }
// Feed the retrieved results back and queue new tasks // Feed the retrieved results back and queue new tasks
if _, index, err := sched.Process(results); err != nil { if _, index, err := sched.Process(results, dstDb); err != nil {
t.Fatalf("failed to process result #%d: %v", index, err) t.Fatalf("failed to process result #%d: %v", index, err)
} }
for _, hash := range sched.Missing(0) { for _, hash := range sched.Missing(0) {
@ -283,7 +283,7 @@ func TestIncompleteStateSync(t *testing.T) {
results[i] = trie.SyncResult{Hash: hash, Data: data} results[i] = trie.SyncResult{Hash: hash, Data: data}
} }
// Process each of the state nodes // Process each of the state nodes
if _, index, err := sched.Process(results); err != nil { if _, index, err := sched.Process(results, dstDb); err != nil {
t.Fatalf("failed to process result #%d: %v", index, err) t.Fatalf("failed to process result #%d: %v", index, err)
} }
for _, result := range results { for _, result := range results {
@ -294,7 +294,7 @@ func TestIncompleteStateSync(t *testing.T) {
// Skim through the accounts and make sure the root hash is not a code node // Skim through the accounts and make sure the root hash is not a code node
codeHash := false codeHash := false
for _, acc := range srcAccounts { for _, acc := range srcAccounts {
if bytes.Compare(root.Bytes(), crypto.Sha3(acc.code)) == 0 { if root == crypto.Keccak256Hash(acc.code) {
codeHash = true codeHash = true
break break
} }

View file

@ -57,25 +57,25 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcess
// Process returns the receipts and logs accumulated during the process and // Process returns the receipts and logs accumulated during the process and
// returns the amount of gas that was used in the process. If any of the // returns the amount of gas that was used in the process. If any of the
// transactions failed to execute due to insufficient gas it will return an error. // transactions failed to execute due to insufficient gas it will return an error.
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {
var ( var (
receipts types.Receipts receipts types.Receipts
totalUsedGas = big.NewInt(0) totalUsedGas = big.NewInt(0)
err error err error
header = block.Header() header = block.Header()
allLogs vm.Logs allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit()) gp = new(GasPool).AddGas(block.GasLimit())
) )
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
//fmt.Println("tx:", i) //fmt.Println("tx:", i)
statedb.StartRecord(tx.Hash(), block.Hash(), i) statedb.StartRecord(tx.Hash(), block.Hash(), i)
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
allLogs = append(allLogs, logs...) allLogs = append(allLogs, receipt.Logs...)
} }
AccumulateRewards(statedb, header, block.Uncles()) AccumulateRewards(statedb, header, block.Uncles())
@ -83,37 +83,44 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
// ApplyTransaction attempts to apply a transaction to the given state database // ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. // and uses the input parameters for its environment. It returns the receipt
// // for the transaction, gas used and an error if the transaction failed,
// ApplyTransactions returns the generated receipts and vm logs during the // indicating the block was invalid.
// execution of the state transition phase. func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, *big.Int, error) {
func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, err
} }
// Create a new context to be used in the EVM environment
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, msg, header, cfg), msg, gp) context := NewEVMContext(msg, header, bc)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
// Apply the transaction to the current state (included in the env)
_, gas, err := ApplyMessage(vmenv, msg, gp)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, err
} }
// Update the state with pending changes // Update the state with pending changes
usedGas.Add(usedGas, gas) usedGas.Add(usedGas, gas)
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
// based on the eip phase, we're passing wether the root touch-delete accounts.
receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas) receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas)
receipt.TxHash = tx.Hash() receipt.TxHash = tx.Hash()
receipt.GasUsed = new(big.Int).Set(gas) receipt.GasUsed = new(big.Int).Set(gas)
if MessageCreatesContract(msg) { // if the transaction created a contract, store the creation address in the receipt.
receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce()) if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
} }
logs := statedb.GetLogs(tx.Hash()) // Set the receipt logs and create a bloom for filtering
receipt.Logs = logs receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
glog.V(logger.Debug).Infoln(receipt) glog.V(logger.Debug).Infoln(receipt)
return receipt, logs, gas, err return receipt, gas, err
} }
// AccumulateRewards credits the coinbase of the given block with the // AccumulateRewards credits the coinbase of the given block with the

View file

@ -55,9 +55,9 @@ type StateTransition struct {
initialGas *big.Int initialGas *big.Int
value *big.Int value *big.Int
data []byte data []byte
state vm.Database state vm.StateDB
env vm.Environment env *vm.EVM
} }
// Message represents a message sent to a contract. // Message represents a message sent to a contract.
@ -106,7 +106,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int {
} }
// NewStateTransition initialises and returns a new state transition object. // NewStateTransition initialises and returns a new state transition object.
func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTransition { func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition {
return &StateTransition{ return &StateTransition{
gp: gp, gp: gp,
env: env, env: env,
@ -116,7 +116,7 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran
initialGas: new(big.Int), initialGas: new(big.Int),
value: msg.Value(), value: msg.Value(),
data: msg.Data(), data: msg.Data(),
state: env.Db(), state: env.StateDB,
} }
} }
@ -127,7 +127,7 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran
// the gas used (which includes gas refunds) and an error if it failed. An error always // the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular // indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block. // state and would never be accepted within a block.
func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, error) { func ApplyMessage(env *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
st := NewStateTransition(env, msg, gp) st := NewStateTransition(env, msg, gp)
ret, _, gasUsed, err := st.TransitionDb() ret, _, gasUsed, err := st.TransitionDb()
@ -159,7 +159,7 @@ func (self *StateTransition) to() vm.Account {
func (self *StateTransition) useGas(amount *big.Int) error { func (self *StateTransition) useGas(amount *big.Int) error {
if self.gas.Cmp(amount) < 0 { if self.gas.Cmp(amount) < 0 {
return vm.OutOfGasError return vm.ErrOutOfGas
} }
self.gas.Sub(self.gas, amount) self.gas.Sub(self.gas, amount)
@ -217,47 +217,44 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
msg := self.msg msg := self.msg
sender := self.from() // err checked in preCheck sender := self.from() // err checked in preCheck
homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber()) homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber)
contractCreation := MessageCreatesContract(msg) contractCreation := MessageCreatesContract(msg)
// Pay intrinsic gas // Pay intrinsic gas
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil { if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
return nil, nil, nil, InvalidTxError(err) return nil, nil, nil, InvalidTxError(err)
} }
vmenv := self.env var (
//var addr common.Address vmenv = self.env
// vm errors do not effect consensus and are therefor
// not assigned to err, except for insufficient balance
// error.
vmerr error
)
if contractCreation { if contractCreation {
ret, _, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value) ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value)
if homestead && err == vm.CodeStoreOutOfGasError { if homestead && err == vm.ErrCodeStoreOutOfGas {
self.gas = Big0 self.gas = Big0
} }
if err != nil {
ret = nil
glog.V(logger.Core).Infoln("VM create err:", err)
}
} else { } else {
// Increment the nonce for the next transaction // Increment the nonce for the next transaction
self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1) self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1)
ret, err = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.gasPrice, self.value) ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.value)
if err != nil {
glog.V(logger.Core).Infoln("VM call err:", err)
} }
if vmerr != nil {
glog.V(logger.Core).Infoln("vm returned with error:", err)
// The only possible consensus-error would be if there wasn't
// sufficient balance to make the transfer happen. The first
// balance transfer may never fail.
if vmerr == vm.ErrInsufficientBalance {
return nil, nil, nil, InvalidTxError(vmerr)
} }
if err != nil && IsValueTransferErr(err) {
return nil, nil, nil, InvalidTxError(err)
}
// We aren't interested in errors here. Errors returned by the VM are non-consensus errors and therefor shouldn't bubble up
if err != nil {
err = nil
} }
requiredGas = new(big.Int).Set(self.gasUsed()) requiredGas = new(big.Int).Set(self.gasUsed())
self.refundGas() self.refundGas()
self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice)) self.state.AddBalance(self.env.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
return ret, requiredGas, self.gasUsed(), err return ret, requiredGas, self.gasUsed(), err
} }

View file

@ -110,7 +110,7 @@ func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transac
// If transactions were removed, the heap and cache are ruined // If transactions were removed, the heap and cache are ruined
if len(removed) > 0 { if len(removed) > 0 {
*m.index = make([]uint64, 0, len(m.items)) *m.index = make([]uint64, 0, len(m.items))
for nonce, _ := range m.items { for nonce := range m.items {
*m.index = append(*m.index, nonce) *m.index = append(*m.index, nonce)
} }
heap.Init(m.index) heap.Init(m.index)
@ -216,7 +216,7 @@ func (m *txSortedMap) Flatten() types.Transactions {
// txList is a "list" of transactions belonging to an account, sorted by account // txList is a "list" of transactions belonging to an account, sorted by account
// nonce. The same type can be used both for storing contiguous transactions for // nonce. The same type can be used both for storing contiguous transactions for
// the executable/pending queue; and for storing gapped transactions for the non- // the executable/pending queue; and for storing gapped transactions for the non-
// executable/future queue, with minor behavoiral changes. // executable/future queue, with minor behavioral changes.
type txList struct { type txList struct {
strict bool // Whether nonces are strictly continuous or not strict bool // Whether nonces are strictly continuous or not
txs *txSortedMap // Heap indexed sorted hash map of the transactions txs *txSortedMap // Heap indexed sorted hash map of the transactions

View file

@ -41,7 +41,6 @@ var (
ErrNonce = errors.New("Nonce too low") ErrNonce = errors.New("Nonce too low")
ErrCheap = errors.New("Gas price too low for acceptance") ErrCheap = errors.New("Gas price too low for acceptance")
ErrBalance = errors.New("Insufficient balance") ErrBalance = errors.New("Insufficient balance")
ErrNonExistentAccount = errors.New("Account does not exist or account balance too low")
ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value") ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value")
ErrIntrinsicGas = errors.New("Intrinsic gas too low") ErrIntrinsicGas = errors.New("Intrinsic gas too low")
ErrGasLimit = errors.New("Exceeds block gas limit") ErrGasLimit = errors.New("Exceeds block gas limit")
@ -124,6 +123,8 @@ func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentState
quit: make(chan struct{}), quit: make(chan struct{}),
} }
pool.resetState()
pool.wg.Add(2) pool.wg.Add(2)
go pool.eventLoop() go pool.eventLoop()
go pool.expirationLoop() go pool.expirationLoop()
@ -176,7 +177,7 @@ func (pool *TxPool) resetState() {
// any transactions that have been included in the block or // any transactions that have been included in the block or
// have been invalidated because of another transaction (e.g. // have been invalidated because of another transaction (e.g.
// higher gas price) // higher gas price)
pool.demoteUnexecutables() pool.demoteUnexecutables(currentState)
// Update all accounts to the latest known pending nonce // Update all accounts to the latest known pending nonce
for addr, list := range pool.pending { for addr, list := range pool.pending {
@ -185,7 +186,7 @@ func (pool *TxPool) resetState() {
} }
// Check the queue and move transactions over to the pending if possible // Check the queue and move transactions over to the pending if possible
// or remove those that have become invalid // or remove those that have become invalid
pool.promoteExecutables() pool.promoteExecutables(currentState)
} }
func (pool *TxPool) Stop() { func (pool *TxPool) Stop() {
@ -237,21 +238,26 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common
// Pending retrieves all currently processable transactions, groupped by origin // Pending retrieves all currently processable transactions, groupped by origin
// account and sorted by nonce. The returned transaction set is a copy and can be // account and sorted by nonce. The returned transaction set is a copy and can be
// freely modified by calling code. // freely modified by calling code.
func (pool *TxPool) Pending() map[common.Address]types.Transactions { func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) {
pool.mu.Lock() pool.mu.Lock()
defer pool.mu.Unlock() defer pool.mu.Unlock()
state, err := pool.currentState()
if err != nil {
return nil, err
}
// check queue first // check queue first
pool.promoteExecutables() pool.promoteExecutables(state)
// invalidate any txs // invalidate any txs
pool.demoteUnexecutables() pool.demoteUnexecutables(state)
pending := make(map[common.Address]types.Transactions) pending := make(map[common.Address]types.Transactions)
for addr, list := range pool.pending { for addr, list := range pool.pending {
pending[addr] = list.Flatten() pending[addr] = list.Flatten()
} }
return pending return pending, nil
} }
// SetLocal marks a transaction as local, skipping gas price // SetLocal marks a transaction as local, skipping gas price
@ -280,13 +286,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
if err != nil { if err != nil {
return ErrInvalidSender return ErrInvalidSender
} }
// Make sure the account exist. Non existent accounts
// haven't got funds and well therefor never pass.
if !currentState.Exist(from) {
return ErrNonExistentAccount
}
// Last but not least check for nonce errors // Last but not least check for nonce errors
if currentState.GetNonce(from) > tx.Nonce() { if currentState.GetNonce(from) > tx.Nonce() {
return ErrNonce return ErrNonce
@ -322,7 +321,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
// add validates a transaction and inserts it into the non-executable queue for // add validates a transaction and inserts it into the non-executable queue for
// later pending promotion and execution. // later pending promotion and execution.
func (pool *TxPool) add(tx *types.Transaction) error { func (pool *TxPool) add(tx *types.Transaction) error {
// If the transaction is alreayd known, discard it // If the transaction is already known, discard it
hash := tx.Hash() hash := tx.Hash()
if pool.all[hash] != nil { if pool.all[hash] != nil {
return fmt.Errorf("Known transaction: %x", hash[:4]) return fmt.Errorf("Known transaction: %x", hash[:4])
@ -372,10 +371,6 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
// //
// Note, this method assumes the pool lock is held! // Note, this method assumes the pool lock is held!
func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) {
// Init delayed since tx pool could have been started before any state sync
if pool.pendingState == nil {
pool.resetState()
}
// Try to insert the transaction into the pending queue // Try to insert the transaction into the pending queue
if pool.pending[addr] == nil { if pool.pending[addr] == nil {
pool.pending[addr] = newTxList(true) pool.pending[addr] = newTxList(true)
@ -410,13 +405,19 @@ func (pool *TxPool) Add(tx *types.Transaction) error {
if err := pool.add(tx); err != nil { if err := pool.add(tx); err != nil {
return err return err
} }
pool.promoteExecutables()
state, err := pool.currentState()
if err != nil {
return err
}
pool.promoteExecutables(state)
return nil return nil
} }
// AddBatch attempts to queue a batch of transactions. // AddBatch attempts to queue a batch of transactions.
func (pool *TxPool) AddBatch(txs []*types.Transaction) { func (pool *TxPool) AddBatch(txs []*types.Transaction) error {
pool.mu.Lock() pool.mu.Lock()
defer pool.mu.Unlock() defer pool.mu.Unlock()
@ -425,7 +426,15 @@ func (pool *TxPool) AddBatch(txs []*types.Transaction) {
glog.V(logger.Debug).Infoln("tx error:", err) glog.V(logger.Debug).Infoln("tx error:", err)
} }
} }
pool.promoteExecutables()
state, err := pool.currentState()
if err != nil {
return err
}
pool.promoteExecutables(state)
return nil
} }
// Get returns a transaction if it is contained in the pool // Get returns a transaction if it is contained in the pool
@ -499,17 +508,7 @@ func (pool *TxPool) removeTx(hash common.Hash) {
// promoteExecutables moves transactions that have become processable from the // promoteExecutables moves transactions that have become processable from the
// future queue to the set of pending transactions. During this process, all // future queue to the set of pending transactions. During this process, all
// invalidated transactions (low nonce, low balance) are deleted. // invalidated transactions (low nonce, low balance) are deleted.
func (pool *TxPool) promoteExecutables() { func (pool *TxPool) promoteExecutables(state *state.StateDB) {
// Init delayed since tx pool could have been started before any state sync
if pool.pendingState == nil {
pool.resetState()
}
// Retrieve the current state to allow nonce and balance checking
state, err := pool.currentState()
if err != nil {
glog.Errorf("Could not get current state: %v", err)
return
}
// Iterate over all accounts and promote any executable transactions // Iterate over all accounts and promote any executable transactions
queued := uint64(0) queued := uint64(0)
for addr, list := range pool.queue { for addr, list := range pool.queue {
@ -610,7 +609,7 @@ func (pool *TxPool) promoteExecutables() {
if queued > maxQueuedInTotal { if queued > maxQueuedInTotal {
// Sort all accounts with queued transactions by heartbeat // Sort all accounts with queued transactions by heartbeat
addresses := make(addresssByHeartbeat, 0, len(pool.queue)) addresses := make(addresssByHeartbeat, 0, len(pool.queue))
for addr, _ := range pool.queue { for addr := range pool.queue {
addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]})
} }
sort.Sort(addresses) sort.Sort(addresses)
@ -645,13 +644,7 @@ func (pool *TxPool) promoteExecutables() {
// demoteUnexecutables removes invalid and processed transactions from the pools // demoteUnexecutables removes invalid and processed transactions from the pools
// executable/pending queue and any subsequent transactions that become unexecutable // executable/pending queue and any subsequent transactions that become unexecutable
// are moved back into the future queue. // are moved back into the future queue.
func (pool *TxPool) demoteUnexecutables() { func (pool *TxPool) demoteUnexecutables(state *state.StateDB) {
// Retrieve the current state to allow nonce and balance checking
state, err := pool.currentState()
if err != nil {
glog.V(logger.Info).Infoln("failed to get current state: %v", err)
return
}
// Iterate over all accounts and demote any non-executable transactions // Iterate over all accounts and demote any non-executable transactions
for addr, list := range pool.pending { for addr, list := range pool.pending {
nonce := state.GetNonce(addr) nonce := state.GetNonce(addr)

View file

@ -32,7 +32,7 @@ import (
) )
func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key) tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil), types.HomesteadSigner{}, key)
return tx return tx
} }
@ -51,14 +51,84 @@ func deriveSender(tx *types.Transaction) (common.Address, error) {
return types.Sender(types.HomesteadSigner{}, tx) return types.Sender(types.HomesteadSigner{}, tx)
} }
// This test simulates a scenario where a new block is imported during a
// state reset and tests whether the pending state is in sync with the
// block head event that initiated the resetState().
func TestStateChangeDuringPoolReset(t *testing.T) {
var (
db, _ = ethdb.NewMemDatabase()
key, _ = crypto.GenerateKey()
address = crypto.PubkeyToAddress(key.PublicKey)
mux = new(event.TypeMux)
statedb, _ = state.New(common.Hash{}, db)
trigger = false
)
// setup pool with 2 transaction in it
statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether))
tx0 := transaction(0, big.NewInt(100000), key)
tx1 := transaction(1, big.NewInt(100000), key)
// stateFunc is used multiple times to reset the pending state.
// when simulate is true it will create a state that indicates
// that tx0 and tx1 are included in the chain.
stateFunc := func() (*state.StateDB, error) {
// delay "state change" by one. The tx pool fetches the
// state multiple times and by delaying it a bit we simulate
// a state change between those fetches.
stdb := statedb
if trigger {
statedb, _ = state.New(common.Hash{}, db)
// simulate that the new head block included tx0 and tx1
statedb.SetNonce(address, 2)
statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether))
trigger = false
}
return stdb, nil
}
gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc)
txpool.resetState()
nonce := txpool.State().GetNonce(address)
if nonce != 0 {
t.Fatalf("Invalid nonce, want 0, got %d", nonce)
}
txpool.AddBatch(types.Transactions{tx0, tx1})
nonce = txpool.State().GetNonce(address)
if nonce != 2 {
t.Fatalf("Invalid nonce, want 2, got %d", nonce)
}
// trigger state change in the background
trigger = true
txpool.resetState()
pendingTx, err := txpool.Pending()
if err != nil {
t.Fatalf("Could not fetch pending transactions: %v", err)
}
for addr, txs := range pendingTx {
t.Logf("%0x: %d\n", addr, len(txs))
}
nonce = txpool.State().GetNonce(address)
if nonce != 2 {
t.Fatalf("Invalid nonce, want 2, got %d", nonce)
}
}
func TestInvalidTransactions(t *testing.T) { func TestInvalidTransactions(t *testing.T) {
pool, key := setupTxPool() pool, key := setupTxPool()
tx := transaction(0, big.NewInt(100), key) tx := transaction(0, big.NewInt(100), key)
if err := pool.Add(tx); err != ErrNonExistentAccount {
t.Error("expected", ErrNonExistentAccount)
}
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1)) currentState.AddBalance(from, big.NewInt(1))
@ -97,9 +167,10 @@ func TestTransactionQueue(t *testing.T) {
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1000)) currentState.AddBalance(from, big.NewInt(1000))
pool.resetState()
pool.enqueueTx(tx.Hash(), tx) pool.enqueueTx(tx.Hash(), tx)
pool.promoteExecutables() pool.promoteExecutables(currentState)
if len(pool.pending) != 1 { if len(pool.pending) != 1 {
t.Error("expected valid txs to be 1 is", len(pool.pending)) t.Error("expected valid txs to be 1 is", len(pool.pending))
} }
@ -108,7 +179,7 @@ func TestTransactionQueue(t *testing.T) {
from, _ = deriveSender(tx) from, _ = deriveSender(tx)
currentState.SetNonce(from, 2) currentState.SetNonce(from, 2)
pool.enqueueTx(tx.Hash(), tx) pool.enqueueTx(tx.Hash(), tx)
pool.promoteExecutables() pool.promoteExecutables(currentState)
if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok { if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok {
t.Error("expected transaction to be in tx pool") t.Error("expected transaction to be in tx pool")
} }
@ -124,11 +195,13 @@ func TestTransactionQueue(t *testing.T) {
from, _ = deriveSender(tx1) from, _ = deriveSender(tx1)
currentState, _ = pool.currentState() currentState, _ = pool.currentState()
currentState.AddBalance(from, big.NewInt(1000)) currentState.AddBalance(from, big.NewInt(1000))
pool.resetState()
pool.enqueueTx(tx1.Hash(), tx1) pool.enqueueTx(tx1.Hash(), tx1)
pool.enqueueTx(tx2.Hash(), tx2) pool.enqueueTx(tx2.Hash(), tx2)
pool.enqueueTx(tx3.Hash(), tx3) pool.enqueueTx(tx3.Hash(), tx3)
pool.promoteExecutables() pool.promoteExecutables(currentState)
if len(pool.pending) != 1 { if len(pool.pending) != 1 {
t.Error("expected tx pool to be 1, got", len(pool.pending)) t.Error("expected tx pool to be 1, got", len(pool.pending))
@ -165,7 +238,7 @@ func TestRemoveTx(t *testing.T) {
func TestNegativeValue(t *testing.T) { func TestNegativeValue(t *testing.T) {
pool, key := setupTxPool() pool, key := setupTxPool()
tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key) tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil), types.HomesteadSigner{}, key)
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1)) currentState.AddBalance(from, big.NewInt(1))
@ -214,9 +287,9 @@ func TestTransactionDoubleNonce(t *testing.T) {
resetState() resetState()
signer := types.HomesteadSigner{} signer := types.HomesteadSigner{}
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, key) tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil), signer, key)
tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(signer, key) tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil), signer, key)
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(signer, key) tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil), signer, key)
// Add the first two transaction, ensure higher priced stays only // Add the first two transaction, ensure higher priced stays only
if err := pool.add(tx1); err != nil { if err := pool.add(tx1); err != nil {
@ -225,7 +298,8 @@ func TestTransactionDoubleNonce(t *testing.T) {
if err := pool.add(tx2); err != nil { if err := pool.add(tx2); err != nil {
t.Error("didn't expect error", err) t.Error("didn't expect error", err)
} }
pool.promoteExecutables() state, _ := pool.currentState()
pool.promoteExecutables(state)
if pool.pending[addr].Len() != 1 { if pool.pending[addr].Len() != 1 {
t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) t.Error("expected 1 pending transactions, got", pool.pending[addr].Len())
} }
@ -236,7 +310,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
if err := pool.add(tx3); err != nil { if err := pool.add(tx3); err != nil {
t.Error("didn't expect error", err) t.Error("didn't expect error", err)
} }
pool.promoteExecutables() pool.promoteExecutables(state)
if pool.pending[addr].Len() != 1 { if pool.pending[addr].Len() != 1 {
t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) t.Error("expected 1 pending transactions, got", pool.pending[addr].Len())
} }
@ -295,6 +369,7 @@ func TestRemovedTxEvent(t *testing.T) {
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
currentState, _ := pool.currentState() currentState, _ := pool.currentState()
currentState.AddBalance(from, big.NewInt(1000000000000)) currentState.AddBalance(from, big.NewInt(1000000000000))
pool.resetState()
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
pool.eventMux.Post(ChainHeadEvent{nil}) pool.eventMux.Post(ChainHeadEvent{nil})
if pool.pending[from].Len() != 1 { if pool.pending[from].Len() != 1 {
@ -452,6 +527,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
pool.resetState()
// Keep queuing up transactions and make sure all above a limit are dropped // Keep queuing up transactions and make sure all above a limit are dropped
for i := uint64(1); i <= maxQueuedPerAccount+5; i++ { for i := uint64(1); i <= maxQueuedPerAccount+5; i++ {
@ -564,6 +640,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
state, _ := pool.currentState() state, _ := pool.currentState()
state.AddBalance(account, big.NewInt(1000000)) state.AddBalance(account, big.NewInt(1000000))
pool.resetState()
// Keep queuing up transactions and make sure all above a limit are dropped // Keep queuing up transactions and make sure all above a limit are dropped
for i := uint64(0); i < maxQueuedPerAccount+5; i++ { for i := uint64(0); i < maxQueuedPerAccount+5; i++ {
@ -733,7 +810,7 @@ func benchmarkPendingDemotion(b *testing.B, size int) {
// Benchmark the speed of pool validation // Benchmark the speed of pool validation
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
pool.demoteUnexecutables() pool.demoteUnexecutables(state)
} }
} }
@ -757,7 +834,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
// Benchmark the speed of pool validation // Benchmark the speed of pool validation
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
pool.promoteExecutables() pool.promoteExecutables(state)
} }
} }

View file

@ -58,5 +58,5 @@ type HeaderValidator interface {
// of gas used in the process and return an error if any of the internal rules // of gas used in the process and return an error if any of the internal rules
// failed. // failed.
type Processor interface { type Processor interface {
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error)
} }

View file

@ -423,9 +423,9 @@ func CalcUncleHash(uncles []*Header) common.Hash {
// WithMiningResult returns a new block with the data from b // WithMiningResult returns a new block with the data from b
// where nonce and mix digest are set to the provided values. // where nonce and mix digest are set to the provided values.
func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block { func (b *Block) WithMiningResult(nonce BlockNonce, mixDigest common.Hash) *Block {
cpy := *b.header cpy := *b.header
binary.BigEndian.PutUint64(cpy.Nonce[:], nonce) cpy.Nonce = nonce
cpy.MixDigest = mixDigest cpy.MixDigest = mixDigest
return &Block{ return &Block{
header: &cpy, header: &cpy,

View file

@ -53,7 +53,7 @@ func TestBlockEncoding(t *testing.T) {
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil) tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b")) tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100"))
fmt.Println(block.Transactions()[0].Hash()) fmt.Println(block.Transactions()[0].Hash())
fmt.Println(tx1.data) fmt.Println(tx1.data)
fmt.Println(tx1.Hash()) fmt.Println(tx1.Hash())

View file

@ -22,7 +22,6 @@ import (
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/common/hexutil"
"github.com/ubiq/go-ubiq/core/vm"
"github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/crypto"
) )
@ -95,17 +94,11 @@ func CreateBloom(receipts Receipts) Bloom {
return BytesToBloom(bin.Bytes()) return BytesToBloom(bin.Bytes())
} }
func LogsBloom(logs vm.Logs) *big.Int { func LogsBloom(logs []*Log) *big.Int {
bin := new(big.Int) bin := new(big.Int)
for _, log := range logs { for _, log := range logs {
data := make([]common.Hash, len(log.Topics))
bin.Or(bin, bloom9(log.Address.Bytes())) bin.Or(bin, bloom9(log.Address.Bytes()))
for _, b := range log.Topics {
for i, topic := range log.Topics {
data[i] = topic
}
for _, b := range data {
bin.Or(bin, bloom9(b[:])) bin.Or(bin, bloom9(b[:]))
} }
} }

184
core/types/log.go Normal file
View file

@ -0,0 +1,184 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"encoding/json"
"errors"
"fmt"
"io"
"github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/common/hexutil"
"github.com/ubiq/go-ubiq/rlp"
)
var errMissingLogFields = errors.New("missing required JSON log fields")
// Log represents a contract log event. These events are generated by the LOG opcode and
// stored/indexed by the node.
type Log struct {
// Consensus fields.
Address common.Address // address of the contract that generated the event
Topics []common.Hash // list of topics provided by the contract.
Data []byte // supplied by the contract, usually ABI-encoded
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
BlockNumber uint64 // block in which the transaction was included
TxHash common.Hash // hash of the transaction
TxIndex uint // index of the transaction in the block
BlockHash common.Hash // hash of the block in which the transaction was included
Index uint // index of the log in the receipt
// The Removed field is true if this log was reverted due to a chain reorganisation.
// You must pay attention to this field if you receive logs through a filter query.
Removed bool
}
type rlpLog struct {
Address common.Address
Topics []common.Hash
Data []byte
}
type rlpStorageLog struct {
Address common.Address
Topics []common.Hash
Data []byte
BlockNumber uint64
TxHash common.Hash
TxIndex uint
BlockHash common.Hash
Index uint
}
type jsonLog struct {
Address *common.Address `json:"address"`
Topics *[]common.Hash `json:"topics"`
Data *hexutil.Bytes `json:"data"`
BlockNumber *hexutil.Uint64 `json:"blockNumber"`
TxIndex *hexutil.Uint `json:"transactionIndex"`
TxHash *common.Hash `json:"transactionHash"`
BlockHash *common.Hash `json:"blockHash"`
Index *hexutil.Uint `json:"logIndex"`
Removed bool `json:"removed"`
}
// EncodeRLP implements rlp.Encoder.
func (l *Log) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
}
// DecodeRLP implements rlp.Decoder.
func (l *Log) DecodeRLP(s *rlp.Stream) error {
var dec rlpLog
err := s.Decode(&dec)
if err == nil {
l.Address, l.Topics, l.Data = dec.Address, dec.Topics, dec.Data
}
return err
}
func (l *Log) String() string {
return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index)
}
// MarshalJSON implements json.Marshaler.
func (l *Log) MarshalJSON() ([]byte, error) {
jslog := &jsonLog{
Address: &l.Address,
Topics: &l.Topics,
Data: (*hexutil.Bytes)(&l.Data),
TxIndex: (*hexutil.Uint)(&l.TxIndex),
TxHash: &l.TxHash,
Index: (*hexutil.Uint)(&l.Index),
Removed: l.Removed,
}
// Set block information for mined logs.
if (l.BlockHash != common.Hash{}) {
jslog.BlockHash = &l.BlockHash
jslog.BlockNumber = (*hexutil.Uint64)(&l.BlockNumber)
}
return json.Marshal(jslog)
}
// UnmarshalJSON implements json.Umarshaler.
func (l *Log) UnmarshalJSON(input []byte) error {
var dec jsonLog
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Address == nil || dec.Topics == nil || dec.Data == nil ||
dec.TxIndex == nil || dec.TxHash == nil || dec.Index == nil {
return errMissingLogFields
}
declog := Log{
Address: *dec.Address,
Topics: *dec.Topics,
Data: *dec.Data,
TxHash: *dec.TxHash,
TxIndex: uint(*dec.TxIndex),
Index: uint(*dec.Index),
Removed: dec.Removed,
}
// Block information may be missing if the log is received through
// the pending log filter, so it's handled specially here.
if dec.BlockHash != nil && dec.BlockNumber != nil {
declog.BlockHash = *dec.BlockHash
declog.BlockNumber = uint64(*dec.BlockNumber)
}
*l = declog
return nil
}
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
// a log including non-consensus fields.
type LogForStorage Log
// EncodeRLP implements rlp.Encoder.
func (l *LogForStorage) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, rlpStorageLog{
Address: l.Address,
Topics: l.Topics,
Data: l.Data,
BlockNumber: l.BlockNumber,
TxHash: l.TxHash,
TxIndex: l.TxIndex,
BlockHash: l.BlockHash,
Index: l.Index,
})
}
// DecodeRLP implements rlp.Decoder.
func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error {
var dec rlpStorageLog
err := s.Decode(&dec)
if err == nil {
*l = LogForStorage{
Address: dec.Address,
Topics: dec.Topics,
Data: dec.Data,
BlockNumber: dec.BlockNumber,
TxHash: dec.TxHash,
TxIndex: dec.TxIndex,
BlockHash: dec.BlockHash,
Index: dec.Index,
}
}
return err
}

131
core/types/log_test.go Normal file
View file

@ -0,0 +1,131 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"encoding/json"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/common/hexutil"
)
var unmarshalLogTests = map[string]struct {
input string
want *Log
wantError error
}{
"ok": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
want: &Log{
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
BlockNumber: 2019236,
Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000001a055690d9db80000"),
Index: 2,
TxIndex: 3,
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
Topics: []common.Hash{
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"),
},
},
},
"empty data": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
want: &Log{
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
BlockNumber: 2019236,
Data: []byte{},
Index: 2,
TxIndex: 3,
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
Topics: []common.Hash{
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"),
},
},
},
"missing block fields (pending logs)": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","data":"0x","logIndex":"0x0","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
want: &Log{
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
BlockHash: common.Hash{},
BlockNumber: 0,
Data: []byte{},
Index: 0,
TxIndex: 3,
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
Topics: []common.Hash{
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
},
},
},
"Removed: true": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3","removed":true}`,
want: &Log{
Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"),
BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"),
BlockNumber: 2019236,
Data: []byte{},
Index: 2,
TxIndex: 3,
TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"),
Topics: []common.Hash{
common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"),
},
Removed: true,
},
},
"missing data": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
wantError: errMissingLogFields,
},
}
func TestUnmarshalLog(t *testing.T) {
dumper := spew.ConfigState{DisableMethods: true, Indent: " "}
for name, test := range unmarshalLogTests {
var log *Log
err := json.Unmarshal([]byte(test.input), &log)
checkError(t, name, err, test.wantError)
if test.wantError == nil && err == nil {
if !reflect.DeepEqual(log, test.want) {
t.Errorf("test %q:\nGOT %sWANT %s", name, dumper.Sdump(log), dumper.Sdump(test.want))
}
}
}
}
func checkError(t *testing.T, testname string, got, want error) bool {
if got == nil {
if want != nil {
t.Errorf("test %q: got no error, want %q", testname, want)
return false
}
return true
}
if want == nil {
t.Errorf("test %q: unexpected error %q", testname, got)
} else if got.Error() != want.Error() {
t.Errorf("test %q: got error %q, want %q", testname, got, want)
}
return false
}

View file

@ -25,7 +25,6 @@ import (
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/common/hexutil"
"github.com/ubiq/go-ubiq/core/vm"
"github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/rlp"
) )
@ -40,7 +39,7 @@ type Receipt struct {
PostState []byte PostState []byte
CumulativeGasUsed *big.Int CumulativeGasUsed *big.Int
Bloom Bloom Bloom Bloom
Logs vm.Logs Logs []*Log
// Implementation fields (don't reorder!) // Implementation fields (don't reorder!)
TxHash common.Hash TxHash common.Hash
@ -52,7 +51,7 @@ type jsonReceipt struct {
PostState *common.Hash `json:"root"` PostState *common.Hash `json:"root"`
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
Bloom *Bloom `json:"logsBloom"` Bloom *Bloom `json:"logsBloom"`
Logs *vm.Logs `json:"logs"` Logs []*Log `json:"logs"`
TxHash *common.Hash `json:"transactionHash"` TxHash *common.Hash `json:"transactionHash"`
ContractAddress *common.Address `json:"contractAddress"` ContractAddress *common.Address `json:"contractAddress"`
GasUsed *hexutil.Big `json:"gasUsed"` GasUsed *hexutil.Big `json:"gasUsed"`
@ -76,7 +75,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
PostState []byte PostState []byte
CumulativeGasUsed *big.Int CumulativeGasUsed *big.Int
Bloom Bloom Bloom Bloom
Logs vm.Logs Logs []*Log
} }
if err := s.Decode(&receipt); err != nil { if err := s.Decode(&receipt); err != nil {
return err return err
@ -93,7 +92,7 @@ func (r *Receipt) MarshalJSON() ([]byte, error) {
PostState: &root, PostState: &root,
CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed), CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed),
Bloom: &r.Bloom, Bloom: &r.Bloom,
Logs: &r.Logs, Logs: r.Logs,
TxHash: &r.TxHash, TxHash: &r.TxHash,
ContractAddress: &r.ContractAddress, ContractAddress: &r.ContractAddress,
GasUsed: (*hexutil.Big)(r.GasUsed), GasUsed: (*hexutil.Big)(r.GasUsed),
@ -120,7 +119,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
PostState: (*dec.PostState)[:], PostState: (*dec.PostState)[:],
CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed), CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed),
Bloom: *dec.Bloom, Bloom: *dec.Bloom,
Logs: *dec.Logs, Logs: dec.Logs,
TxHash: *dec.TxHash, TxHash: *dec.TxHash,
GasUsed: (*big.Int)(dec.GasUsed), GasUsed: (*big.Int)(dec.GasUsed),
} }
@ -142,9 +141,9 @@ type ReceiptForStorage Receipt
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
// into an RLP stream. // into an RLP stream.
func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
logs := make([]*vm.LogForStorage, len(r.Logs)) logs := make([]*LogForStorage, len(r.Logs))
for i, log := range r.Logs { for i, log := range r.Logs {
logs[i] = (*vm.LogForStorage)(log) logs[i] = (*LogForStorage)(log)
} }
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed}) return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
} }
@ -158,7 +157,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
Bloom Bloom Bloom Bloom
TxHash common.Hash TxHash common.Hash
ContractAddress common.Address ContractAddress common.Address
Logs []*vm.LogForStorage Logs []*LogForStorage
GasUsed *big.Int GasUsed *big.Int
} }
if err := s.Decode(&receipt); err != nil { if err := s.Decode(&receipt); err != nil {
@ -166,9 +165,9 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
} }
// Assign the consensus fields // Assign the consensus fields
r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom
r.Logs = make(vm.Logs, len(receipt.Logs)) r.Logs = make([]*Log, len(receipt.Logs))
for i, log := range receipt.Logs { for i, log := range receipt.Logs {
r.Logs[i] = (*vm.Log)(log) r.Logs[i] = (*Log)(log)
} }
// Assign the implementation fields // Assign the implementation fields
r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed

View file

@ -18,7 +18,6 @@ package types
import ( import (
"container/heap" "container/heap"
"crypto/ecdsa"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -199,9 +198,9 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
var V byte var V byte
if isProtectedV((*big.Int)(dec.V)) { if isProtectedV((*big.Int)(dec.V)) {
V = normaliseV(NewEIP155Signer(deriveChainId((*big.Int)(dec.V))), (*big.Int)(dec.V)) V = byte((new(big.Int).Sub((*big.Int)(dec.V), deriveChainId((*big.Int)(dec.V))).Uint64()) - 35)
} else { } else {
V = byte(((*big.Int)(dec.V)).Uint64()) V = byte(((*big.Int)(dec.V)).Uint64() - 27)
} }
if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) { if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
return ErrInvalidSig return ErrInvalidSig
@ -272,51 +271,6 @@ func (tx *Transaction) Size() common.StorageSize {
return common.StorageSize(c) return common.StorageSize(c)
} }
/*
// From returns the address derived from the signature (V, R, S) using secp256k1
// elliptic curve and an error if it failed deriving or upon an incorrect
// signature.
//
// From Uses the homestead consensus rules to determine whether the signature is
// valid.
//
// From caches the address, allowing it to be used regardless of
// Frontier / Homestead. however, the first time called it runs
// signature validations, so we need two versions. This makes it
// easier to ensure backwards compatibility of things like package rpc
// where eth_getblockbynumber uses tx.From() and needs to work for
// both txs before and after the first homestead block. Signatures
// valid in homestead are a subset of valid ones in Frontier)
func (tx *Transaction) From() (common.Address, error) {
if tx.signer == nil {
return common.Address{}, errNoSigner
}
if from := tx.from.Load(); from != nil {
return from.(common.Address), nil
}
pubkey, err := tx.signer.PublicKey(tx)
if err != nil {
return common.Address{}, err
}
var addr common.Address
copy(addr[:], crypto.Keccak256(pubkey[1:])[12:])
tx.from.Store(addr)
return addr, nil
}
// SignatureValues returns the ECDSA signature values contained in the transaction.
func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int, err error) {
if tx.signer == nil {
return 0, nil, nil,errNoSigner
}
return normaliseV(tx.signer, tx.data.V), new(big.Int).Set(tx.data.R),new(big.Int).Set(tx.data.S), nil
}
*/
// AsMessage returns the transaction as a core.Message. // AsMessage returns the transaction as a core.Message.
// //
// AsMessage requires a signer to derive the sender. // AsMessage requires a signer to derive the sender.
@ -338,14 +292,6 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
return msg, err return msg, err
} }
// SignECDSA signs the transaction using the given signer and private key
//
// XXX This only makes for a nice API: NewTx(...).SignECDSA(signer, prv). Should
// we keep this?
func (tx *Transaction) SignECDSA(signer Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
return signer.SignECDSA(tx, prv)
}
// WithSignature returns a new transaction with the given signature. // WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27). // This signature needs to be formatted as described in the yellow paper (v+27).
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) { func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {

View file

@ -50,10 +50,10 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
return signer return signer
} }
// SignECDSA signs the transaction using the given signer and private key // SignTx signs the transaction using the given signer and private key
func SignECDSA(s Signer, tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) { func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := s.Hash(tx) h := s.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv) sig, err := crypto.Sign(h[:], prv)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -91,19 +91,13 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
return addr, nil return addr, nil
} }
// SignatureValues returns the ECDSA signature values contained in the transaction.
func SignatureValues(signer Signer, tx *Transaction) (v byte, r *big.Int, s *big.Int) {
return normaliseV(signer, tx.data.V), new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
}
type Signer interface { type Signer interface {
// Hash returns the rlp encoded hash for signatures // Hash returns the rlp encoded hash for signatures
Hash(tx *Transaction) common.Hash Hash(tx *Transaction) common.Hash
// PubilcKey returns the public key derived from the signature // PubilcKey returns the public key derived from the signature
PublicKey(tx *Transaction) ([]byte, error) PublicKey(tx *Transaction) ([]byte, error)
// SignECDSA signs the transaction with the given and returns a copy of the tx // WithSignature returns a copy of the transaction with the given signature.
SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) // The signature must be encoded in [R || S || V] format where V is 0 or 1.
// WithSignature returns a copy of the transaction with the given signature
WithSignature(tx *Transaction, sig []byte) (*Transaction, error) WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
// Checks for equality on the signers // Checks for equality on the signers
Equal(Signer) bool Equal(Signer) bool
@ -129,10 +123,6 @@ func (s EIP155Signer) Equal(s2 Signer) bool {
return ok && eip155.chainId.Cmp(s.chainId) == 0 return ok && eip155.chainId.Cmp(s.chainId) == 0
} }
func (s EIP155Signer) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
return SignECDSA(s, tx, prv)
}
func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) { func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
// if the transaction is not protected fall back to homestead signer // if the transaction is not protected fall back to homestead signer
if !tx.Protected() { if !tx.Protected() {
@ -143,17 +133,16 @@ func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
return nil, ErrInvalidChainId return nil, ErrInvalidChainId
} }
V := normaliseV(s, tx.data.V) V := byte(new(big.Int).Sub(tx.data.V, s.chainIdMul).Uint64() - 35)
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) { if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
return nil, ErrInvalidSig return nil, ErrInvalidSig
} }
// encode the signature in uncompressed format // encode the signature in uncompressed format
R, S := tx.data.R.Bytes(), tx.data.S.Bytes() R, S := tx.data.R.Bytes(), tx.data.S.Bytes()
sig := make([]byte, 65) sig := make([]byte, 65)
copy(sig[32-len(R):32], R) copy(sig[32-len(R):32], R)
copy(sig[64-len(S):64], S) copy(sig[64-len(S):64], S)
sig[64] = V - 27 sig[64] = V
// recover the public key from the signature // recover the public key from the signature
hash := s.Hash(tx) hash := s.Hash(tx)
@ -167,8 +156,8 @@ func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
return pub, nil return pub, nil
} }
// WithSignature returns a new transaction with the given signature. // WithSignature returns a new transaction with the given signature. This signature
// This signature needs to be formatted as described in the yellow paper (v+27). // needs to be in the [R || S || V] format where V is 0 or 1.
func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) { func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
if len(sig) != 65 { if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig))) panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
@ -179,7 +168,7 @@ func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction,
cpy.data.S = new(big.Int).SetBytes(sig[32:64]) cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]}) cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
if s.chainId.BitLen() > 0 { if s.chainId.BitLen() > 0 {
cpy.data.V = big.NewInt(int64(sig[64] - 27 + 35)) cpy.data.V = big.NewInt(int64(sig[64] + 35))
cpy.data.V.Add(cpy.data.V, s.chainIdMul) cpy.data.V.Add(cpy.data.V, s.chainIdMul)
} }
return cpy, nil return cpy, nil
@ -199,15 +188,6 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
}) })
} }
func (s EIP155Signer) SigECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := s.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return s.WithSignature(tx, sig)
}
// HomesteadTransaction implements TransactionInterface using the // HomesteadTransaction implements TransactionInterface using the
// homestead rules. // homestead rules.
type HomesteadSigner struct{ FrontierSigner } type HomesteadSigner struct{ FrontierSigner }
@ -217,8 +197,8 @@ func (s HomesteadSigner) Equal(s2 Signer) bool {
return ok return ok
} }
// WithSignature returns a new transaction with the given snature. // WithSignature returns a new transaction with the given signature. This signature
// This snature needs to be formatted as described in the yellow paper (v+27). // needs to be in the [R || S || V] format where V is 0 or 1.
func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) { func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
if len(sig) != 65 { if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig))) panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
@ -226,24 +206,15 @@ func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transacti
cpy := &Transaction{data: tx.data} cpy := &Transaction{data: tx.data}
cpy.data.R = new(big.Int).SetBytes(sig[:32]) cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64]) cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]}) cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
return cpy, nil return cpy, nil
} }
func (hs HomesteadSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := hs.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return hs.WithSignature(tx, sig)
}
func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) { func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
if tx.data.V.BitLen() > 8 { if tx.data.V.BitLen() > 8 {
return nil, ErrInvalidSig return nil, ErrInvalidSig
} }
V := byte(tx.data.V.Uint64()) V := byte(tx.data.V.Uint64() - 27)
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) { if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
return nil, ErrInvalidSig return nil, ErrInvalidSig
} }
@ -252,7 +223,7 @@ func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
sig := make([]byte, 65) sig := make([]byte, 65)
copy(sig[32-len(r):32], r) copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s) copy(sig[64-len(s):64], s)
sig[64] = V - 27 sig[64] = V
// recover the public key from the snature // recover the public key from the snature
hash := hs.Hash(tx) hash := hs.Hash(tx)
@ -273,8 +244,8 @@ func (s FrontierSigner) Equal(s2 Signer) bool {
return ok return ok
} }
// WithSignature returns a new transaction with the given snature. // WithSignature returns a new transaction with the given signature. This signature
// This snature needs to be formatted as described in the yellow paper (v+27). // needs to be in the [R || S || V] format where V is 0 or 1.
func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) { func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
if len(sig) != 65 { if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig))) panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
@ -282,19 +253,10 @@ func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transactio
cpy := &Transaction{data: tx.data} cpy := &Transaction{data: tx.data}
cpy.data.R = new(big.Int).SetBytes(sig[:32]) cpy.data.R = new(big.Int).SetBytes(sig[:32])
cpy.data.S = new(big.Int).SetBytes(sig[32:64]) cpy.data.S = new(big.Int).SetBytes(sig[32:64])
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]}) cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
return cpy, nil return cpy, nil
} }
func (fs FrontierSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := fs.Hash(tx)
sig, err := crypto.SignEthereum(h[:], prv)
if err != nil {
return nil, err
}
return fs.WithSignature(tx, sig)
}
// Hash returns the hash to be sned by the sender. // Hash returns the hash to be sned by the sender.
// It does not uniquely identify the transaction. // It does not uniquely identify the transaction.
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash { func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
@ -313,7 +275,7 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
return nil, ErrInvalidSig return nil, ErrInvalidSig
} }
V := byte(tx.data.V.Uint64()) V := byte(tx.data.V.Uint64() - 27)
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) { if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) {
return nil, ErrInvalidSig return nil, ErrInvalidSig
} }
@ -322,7 +284,7 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
sig := make([]byte, 65) sig := make([]byte, 65)
copy(sig[32-len(r):32], r) copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s) copy(sig[64-len(s):64], s)
sig[64] = V - 27 sig[64] = V
// recover the public key from the snature // recover the public key from the snature
hash := fs.Hash(tx) hash := fs.Hash(tx)
@ -336,18 +298,6 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
return pub, nil return pub, nil
} }
// normaliseV returns the Ethereum version of the V parameter
func normaliseV(s Signer, v *big.Int) byte {
if s, ok := s.(EIP155Signer); ok {
stdV := v.BitLen() <= 8 && (v.Uint64() == 27 || v.Uint64() == 28)
if s.chainId.BitLen() > 0 && !stdV {
nv := byte((new(big.Int).Sub(v, s.chainIdMul).Uint64()) - 35 + 27)
return nv
}
}
return byte(v.Uint64())
}
// deriveChainId derives the chain id from the given v parameter // deriveChainId derives the chain id from the given v parameter
func deriveChainId(v *big.Int) *big.Int { func deriveChainId(v *big.Int) *big.Int {
if v.BitLen() <= 64 { if v.BitLen() <= 64 {

View file

@ -30,7 +30,7 @@ func TestEIP155Signing(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
signer := NewEIP155Signer(big.NewInt(18)) signer := NewEIP155Signer(big.NewInt(18))
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key) tx, err := SignTx(NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil), signer, key)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -49,7 +49,7 @@ func TestEIP155ChainId(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
signer := NewEIP155Signer(big.NewInt(18)) signer := NewEIP155Signer(big.NewInt(18))
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key) tx, err := SignTx(NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil), signer, key)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -62,7 +62,7 @@ func TestEIP155ChainId(t *testing.T) {
} }
tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil) tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil)
tx, err = tx.SignECDSA(HomesteadSigner{}, key) tx, err = SignTx(tx, HomesteadSigner{}, key)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -121,7 +121,7 @@ func TestChainId(t *testing.T) {
tx := NewTransaction(0, common.Address{}, new(big.Int), new(big.Int), new(big.Int), nil) tx := NewTransaction(0, common.Address{}, new(big.Int), new(big.Int), new(big.Int), nil)
var err error var err error
tx, err = tx.SignECDSA(NewEIP155Signer(big.NewInt(1)), key) tx, err = SignTx(tx, NewEIP155Signer(big.NewInt(1)), key)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -47,7 +47,7 @@ var (
common.FromHex("5544"), common.FromHex("5544"),
).WithSignature( ).WithSignature(
HomesteadSigner{}, HomesteadSigner{},
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"), common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"),
) )
) )
@ -138,7 +138,7 @@ func TestTransactionPriceNonceSort(t *testing.T) {
for start, key := range keys { for start, key := range keys {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
for i := 0; i < 25; i++ { for i := 0; i < 25; i++ {
tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(signer, key) tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil), signer, key)
groups[addr] = append(groups[addr], tx) groups[addr] = append(groups[addr], tx)
} }
} }

View file

@ -24,7 +24,7 @@ import (
// ContractRef is a reference to the contract's backing object // ContractRef is a reference to the contract's backing object
type ContractRef interface { type ContractRef interface {
ReturnGas(*big.Int, *big.Int) ReturnGas(*big.Int)
Address() common.Address Address() common.Address
Value() *big.Int Value() *big.Int
SetCode(common.Hash, []byte) SetCode(common.Hash, []byte)
@ -48,7 +48,7 @@ type Contract struct {
CodeAddr *common.Address CodeAddr *common.Address
Input []byte Input []byte
value, Gas, UsedGas, Price *big.Int value, Gas, UsedGas *big.Int
Args []byte Args []byte
@ -56,7 +56,7 @@ type Contract struct {
} }
// NewContract returns a new contract environment for the execution of EVM. // NewContract returns a new contract environment for the execution of EVM.
func NewContract(caller ContractRef, object ContractRef, value, gas, price *big.Int) *Contract { func NewContract(caller ContractRef, object ContractRef, value, gas *big.Int) *Contract {
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil} c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object, Args: nil}
if parent, ok := caller.(*Contract); ok { if parent, ok := caller.(*Contract); ok {
@ -70,9 +70,6 @@ func NewContract(caller ContractRef, object ContractRef, value, gas, price *big.
// This pointer will be off the state transition // This pointer will be off the state transition
c.Gas = gas //new(big.Int).Set(gas) c.Gas = gas //new(big.Int).Set(gas)
c.value = new(big.Int).Set(value) c.value = new(big.Int).Set(value)
// In most cases price and value are pointers to transaction objects
// and we don't want the transaction's values to change.
c.Price = new(big.Int).Set(price)
c.UsedGas = new(big.Int) c.UsedGas = new(big.Int)
return c return c
@ -114,7 +111,7 @@ func (c *Contract) Caller() common.Address {
// caller. // caller.
func (c *Contract) Finalise() { func (c *Contract) Finalise() {
// Return the remaining gas to the caller // Return the remaining gas to the caller
c.caller.ReturnGas(c.Gas, c.Price) c.caller.ReturnGas(c.Gas)
} }
// UseGas attempts the use gas and subtracts it and returns true on success // UseGas attempts the use gas and subtracts it and returns true on success
@ -127,7 +124,7 @@ func (c *Contract) UseGas(gas *big.Int) (ok bool) {
} }
// ReturnGas adds the given gas back to itself. // ReturnGas adds the given gas back to itself.
func (c *Contract) ReturnGas(gas, price *big.Int) { func (c *Contract) ReturnGas(gas *big.Int) {
// Return the gas to the context // Return the gas to the context
c.Gas.Add(c.Gas, gas) c.Gas.Add(c.Gas, gas)
c.UsedGas.Sub(c.UsedGas, gas) c.UsedGas.Sub(c.UsedGas, gas)

View file

@ -26,84 +26,59 @@ import (
"github.com/ubiq/go-ubiq/params" "github.com/ubiq/go-ubiq/params"
) )
// PrecompiledAccount represents a native ethereum contract // Precompiled contract is the basic interface for native Go contracts. The implementation
type PrecompiledAccount struct { // requires a deterministic gas count based on the input size of the Run method of the
Gas func(l int) *big.Int // contract.
fn func(in []byte) []byte type PrecompiledContract interface {
} RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use
Run(input []byte) []byte // Run runs the precompiled contract
// Call calls the native function
func (self PrecompiledAccount) Call(in []byte) []byte {
return self.fn(in)
} }
// Precompiled contains the default set of ethereum contracts // Precompiled contains the default set of ethereum contracts
var Precompiled = PrecompiledContracts() var PrecompiledContracts = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256{},
common.BytesToAddress([]byte{3}): &ripemd160{},
common.BytesToAddress([]byte{4}): &dataCopy{},
}
// PrecompiledContracts returns the default set of precompiled ethereum // RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
// contracts defined by the ethereum yellow paper. func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
func PrecompiledContracts() map[string]*PrecompiledAccount { gas := p.RequiredGas(len(input))
return map[string]*PrecompiledAccount{ if contract.UseGas(gas) {
// ECRECOVER ret = p.Run(input)
string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int {
return params.EcrecoverGas
}, ecrecoverFunc},
// SHA256 return ret, nil
string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int { } else {
n := big.NewInt(int64(l+31) / 32) return nil, ErrOutOfGas
n.Mul(n, params.Sha256WordGas)
return n.Add(n, params.Sha256Gas)
}, sha256Func},
// RIPEMD160
string(common.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31) / 32)
n.Mul(n, params.Ripemd160WordGas)
return n.Add(n, params.Ripemd160Gas)
}, ripemd160Func},
string(common.LeftPadBytes([]byte{4}, 20)): &PrecompiledAccount{func(l int) *big.Int {
n := big.NewInt(int64(l+31) / 32)
n.Mul(n, params.IdentityWordGas)
return n.Add(n, params.IdentityGas)
}, memCpy},
} }
} }
func sha256Func(in []byte) []byte { // ECRECOVER implemented as a native contract
return crypto.Sha256(in) type ecrecover struct{}
func (c *ecrecover) RequiredGas(inputSize int) *big.Int {
return params.EcrecoverGas
} }
func ripemd160Func(in []byte) []byte { func (c *ecrecover) Run(in []byte) []byte {
return common.LeftPadBytes(crypto.Ripemd160(in), 32) const ecRecoverInputLength = 128
}
const ecRecoverInputLength = 128 in = common.RightPadBytes(in, ecRecoverInputLength)
func ecrecoverFunc(in []byte) []byte {
in = common.RightPadBytes(in, 128)
// "in" is (hash, v, r, s), each 32 bytes // "in" is (hash, v, r, s), each 32 bytes
// but for ecrecover we want (r, s, v) // but for ecrecover we want (r, s, v)
r := common.BytesToBig(in[64:96]) r := common.BytesToBig(in[64:96])
s := common.BytesToBig(in[96:128]) s := common.BytesToBig(in[96:128])
// Treat V as a 256bit integer v := in[63] - 27
vbig := common.Bytes2Big(in[32:64])
v := byte(vbig.Uint64())
// tighter sig s values in homestead only apply to tx sigs // tighter sig s values in homestead only apply to tx sigs
if !crypto.ValidateSignatureValues(v, r, s, false) { if common.Bytes2Big(in[32:63]).BitLen() > 0 || !crypto.ValidateSignatureValues(v, r, s, false) {
glog.V(logger.Detail).Infof("ECRECOVER error: v, r or s value invalid") glog.V(logger.Detail).Infof("ECRECOVER error: v, r or s value invalid")
return nil return nil
} }
// v needs to be at the end for libsecp256k1
// v needs to be at the end and normalized for libsecp256k1 pubKey, err := crypto.Ecrecover(in[:32], append(in[64:128], v))
vbignormal := new(big.Int).Sub(vbig, big.NewInt(27))
vnormal := byte(vbignormal.Uint64())
rsv := append(in[64:128], vnormal)
pubKey, err := crypto.Ecrecover(in[:32], rsv)
// make sure the public key is a valid one // make sure the public key is a valid one
if err != nil { if err != nil {
glog.V(logger.Detail).Infoln("ECRECOVER error: ", err) glog.V(logger.Detail).Infoln("ECRECOVER error: ", err)
@ -114,6 +89,39 @@ func ecrecoverFunc(in []byte) []byte {
return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32) return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32)
} }
func memCpy(in []byte) []byte { // SHA256 implemented as a native contract
type sha256 struct{}
func (c *sha256) RequiredGas(inputSize int) *big.Int {
n := big.NewInt(int64(inputSize+31) / 32)
n.Mul(n, params.Sha256WordGas)
return n.Add(n, params.Sha256Gas)
}
func (c *sha256) Run(in []byte) []byte {
return crypto.Sha256(in)
}
// RIPMED160 implemented as a native contract
type ripemd160 struct{}
func (c *ripemd160) RequiredGas(inputSize int) *big.Int {
n := big.NewInt(int64(inputSize+31) / 32)
n.Mul(n, params.Ripemd160WordGas)
return n.Add(n, params.Ripemd160Gas)
}
func (c *ripemd160) Run(in []byte) []byte {
return common.LeftPadBytes(crypto.Ripemd160(in), 32)
}
// data copy implemented as a native contract
type dataCopy struct{}
func (c *dataCopy) RequiredGas(inputSize int) *big.Int {
n := big.NewInt(int64(inputSize+31) / 32)
n.Mul(n, params.IdentityWordGas)
return n.Add(n, params.IdentityGas)
}
func (c *dataCopy) Run(in []byte) []byte {
return in return in
} }

View file

@ -17,110 +17,312 @@
package vm package vm
import ( import (
"fmt"
"math/big" "math/big"
"sync/atomic"
"github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common"
"github.com/ubiq/go-ubiq/crypto"
"github.com/ubiq/go-ubiq/params" "github.com/ubiq/go-ubiq/params"
) )
// Environment is an EVM requirement and helper which allows access to outside type (
// information such as states. CanTransferFunc func(StateDB, common.Address, *big.Int) bool
type Environment interface { TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
// The current ruleset // GetHashFunc returns the nth block hash in the blockchain
ChainConfig() *params.ChainConfig // and is used by the BLOCKHASH EVM op code.
// The state database GetHashFunc func(uint64) common.Hash
Db() Database )
// Creates a restorable snapshot
SnapshotDatabase() int // Context provides the EVM with auxiliary information. Once provided it shouldn't be modified.
// Set database to previous snapshot type Context struct {
RevertToSnapshot(int) // CanTransfer returns whether the account contains
// Address of the original invoker (first occurrence of the VM invoker) // sufficient ether to transfer the value
Origin() common.Address CanTransfer CanTransferFunc
// The block number this VM is invoked on // Transfer transfers ether from one account to the other
BlockNumber() *big.Int Transfer TransferFunc
// The n'th hash ago from this block number // GetHash returns the hash corresponding to n
GetHash(uint64) common.Hash GetHash GetHashFunc
// The handler's address
Coinbase() common.Address // Message information
// The current time (block time) Origin common.Address // Provides information for ORIGIN
Time() *big.Int GasPrice *big.Int // Provides information for GASPRICE
// Difficulty set on the current block
Difficulty() *big.Int // Block information
// The gas limit of the block Coinbase common.Address // Provides information for COINBASE
GasLimit() *big.Int GasLimit *big.Int // Provides information for GASLIMIT
// Determines whether it's possible to transact BlockNumber *big.Int // Provides information for NUMBER
CanTransfer(from common.Address, balance *big.Int) bool Time *big.Int // Provides information for TIME
// Transfers amount from one account to the other Difficulty *big.Int // Provides information for DIFFICULTY
Transfer(from, to Account, amount *big.Int)
// Adds a LOG to the state
AddLog(*Log)
// Type of the VM
Vm() Vm
// Get the curret calling depth
Depth() int
// Set the current calling depth
SetDepth(i int)
// Call another contract
Call(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
// Take another's contract code and execute within our own context
CallCode(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error)
// Same as CallCode except sender and value is propagated from parent to child scope
DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error)
// Create a new contract
Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error)
} }
// Vm is the basic interface for an implementation of the EVM. // EVM provides information about external sources for the EVM
type Vm interface { //
// Run should execute the given contract with the input given in in // The EVM should never be reused and is not thread safe.
// and return the contract execution return bytes or an error if it type EVM struct {
// failed. // Context provides auxiliary blockchain related information
Run(c *Contract, in []byte) ([]byte, error) Context
// StateDB gives access to the underlying state
StateDB StateDB
// Depth is the current call stack
depth int
// chainConfig contains information about the current chain
chainConfig *params.ChainConfig
// virtual machine configuration options used to initialise the
// evm.
vmConfig Config
// global (to this context) ethereum virtual machine
// used throughout the execution of the tx.
interpreter *Interpreter
// abort is used to abort the EVM calling operations
// NOTE: must be set atomically
abort int32
} }
// Database is a EVM database for full state querying. // NewEVM retutrns a new EVM evmironment.
type Database interface { func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
GetAccount(common.Address) Account evm := &EVM{
CreateAccount(common.Address) Account Context: ctx,
StateDB: statedb,
vmConfig: vmConfig,
chainConfig: chainConfig,
}
AddBalance(common.Address, *big.Int) evm.interpreter = NewInterpreter(evm, vmConfig)
GetBalance(common.Address) *big.Int return evm
GetNonce(common.Address) uint64
SetNonce(common.Address, uint64)
GetCodeHash(common.Address) common.Hash
GetCodeSize(common.Address) int
GetCode(common.Address) []byte
SetCode(common.Address, []byte)
AddRefund(*big.Int)
GetRefund() *big.Int
GetState(common.Address, common.Hash) common.Hash
SetState(common.Address, common.Hash, common.Hash)
Suicide(common.Address) bool
HasSuicided(common.Address) bool
// Exist reports whether the given account exists in state.
// Notably this should also return true for suicided accounts.
Exist(common.Address) bool
// Empty returns whether the given account is empty. Empty
// is defined according to EIP161 (balance = nonce = code = 0).
Empty(common.Address) bool
} }
// Account represents a contract or basic ethereum account. // Cancel cancels any running EVM operation. This may be called concurrently and it's safe to be
type Account interface { // called multiple times.
SubBalance(amount *big.Int) func (evm *EVM) Cancel() {
AddBalance(amount *big.Int) atomic.StoreInt32(&evm.abort, 1)
SetBalance(*big.Int)
SetNonce(uint64)
Balance() *big.Int
Address() common.Address
ReturnGas(*big.Int, *big.Int)
SetCode(common.Hash, []byte)
ForEachStorage(cb func(key, value common.Hash) bool)
Value() *big.Int
} }
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
// case of an execution error or failed value transfer.
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
caller.ReturnGas(gas)
return nil, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas)
return nil, ErrDepth
}
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
caller.ReturnGas(gas)
return nil, ErrInsufficientBalance
}
var (
to Account
snapshot = evm.StateDB.Snapshot()
)
if !evm.StateDB.Exist(addr) {
if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.BitLen() == 0 {
caller.ReturnGas(gas)
return nil, nil
}
to = evm.StateDB.CreateAccount(addr)
} else {
to = evm.StateDB.GetAccount(addr)
}
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
// initialise a new contract and set the code that is to be used by the
// E The contract is a scoped evmironment for this execution context
// only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input)
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
if err != nil {
contract.UseGas(contract.Gas)
evm.StateDB.RevertToSnapshot(snapshot)
}
return ret, err
}
// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
// case of an execution error or failed value transfer.
//
// CallCode differs from Call in the sense that it executes the given address' code with the caller as context.
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas, value *big.Int) (ret []byte, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
caller.ReturnGas(gas)
return nil, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas)
return nil, ErrDepth
}
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
caller.ReturnGas(gas)
return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", value, evm.StateDB.GetBalance(caller.Address()))
}
var (
snapshot = evm.StateDB.Snapshot()
to = evm.StateDB.GetAccount(caller.Address())
)
// initialise a new contract and set the code that is to be used by the
// E The contract is a scoped evmironment for this execution context
// only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input)
if err != nil {
contract.UseGas(contract.Gas)
evm.StateDB.RevertToSnapshot(snapshot)
}
return ret, err
}
// DelegateCall executes the contract associated with the addr with the given input as parameters.
// It reverses the state in case of an execution error.
//
// DelegateCall differs from CallCode in the sense that it executes the given address' code with the caller as context
// and the caller is set to the caller of the caller.
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas *big.Int) (ret []byte, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
caller.ReturnGas(gas)
return nil, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas)
return nil, ErrDepth
}
var (
snapshot = evm.StateDB.Snapshot()
to = evm.StateDB.GetAccount(caller.Address())
)
// Iinitialise a new contract and make initialise the delegate values
contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, input)
if err != nil {
contract.UseGas(contract.Gas)
evm.StateDB.RevertToSnapshot(snapshot)
}
return ret, err
}
// Create creates a new contract using code as deployment code.
func (evm *EVM) Create(caller ContractRef, code []byte, gas, value *big.Int) (ret []byte, contractAddr common.Address, err error) {
if evm.vmConfig.NoRecursion && evm.depth > 0 {
caller.ReturnGas(gas)
return nil, common.Address{}, nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth.Int64()) {
caller.ReturnGas(gas)
return nil, common.Address{}, ErrDepth
}
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
caller.ReturnGas(gas)
return nil, common.Address{}, ErrInsufficientBalance
}
// Create a new account on the state
nonce := evm.StateDB.GetNonce(caller.Address())
evm.StateDB.SetNonce(caller.Address(), nonce+1)
snapshot := evm.StateDB.Snapshot()
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
to := evm.StateDB.CreateAccount(contractAddr)
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
evm.StateDB.SetNonce(contractAddr, 1)
}
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
// initialise a new contract and set the code that is to be used by the
// E The contract is a scoped evmironment for this execution context
// only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
defer contract.Finalise()
ret, err = evm.interpreter.Run(contract, nil)
// check whether the max code size has been exceeded
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
// if the contract creation ran successfully and no errors were returned
// calculate the gas required to store the code. If the code could not
// be stored due to not enough gas set an error and let it be handled
// by the error checking condition below.
if err == nil && !maxCodeSizeExceeded {
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, params.CreateDataGas)
if contract.UseGas(dataGas) {
evm.StateDB.SetCode(contractAddr, ret)
} else {
err = ErrCodeStoreOutOfGas
}
}
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
if maxCodeSizeExceeded ||
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
contract.UseGas(contract.Gas)
evm.StateDB.RevertToSnapshot(snapshot)
// Nothing should be returned when an error is thrown.
return nil, contractAddr, err
}
// If the vm returned with an error the return value should be set to nil.
// This isn't consensus critical but merely to for behaviour reasons such as
// tests, RPC calls, etc.
if err != nil {
ret = nil
}
return ret, contractAddr, err
}
// ChainConfig returns the evmironment's chain configuration
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
// Interpreter returns the EVM interpreter
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }

Some files were not shown because too many files have changed in this diff Show more