diff --git a/.travis.yml b/.travis.yml index bc28ad0932..68fba06794 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,15 +13,15 @@ matrix: go: 1.6.2 - os: linux dist: trusty - go: 1.7 + go: 1.7.4 - os: osx - go: 1.7 + go: 1.7.4 # This builder does the Ubuntu PPA and Linux Azure uploads - os: linux dist: trusty sudo: required - go: 1.7 + go: 1.7.4 env: - ubuntu-ppa - azure-linux @@ -55,7 +55,7 @@ matrix: # This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads - os: osx - go: 1.7 + go: 1.7.4 env: - azure-osx - mobile @@ -90,7 +90,7 @@ install: - go get golang.org/x/tools/cmd/cover script: - go run build/ci.go install - - go run build/ci.go test -coverage -vet + - go run build/ci.go test -coverage -vet -misspell notifications: webhooks: diff --git a/README.md b/README.md index 957615197b..4803f08d13 100644 --- a/README.md +++ b/README.md @@ -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`). | | `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`). | -| `bzzd` | swarm daemon. This is the entrypoint for the swarm network. `bzzd --help` for command line options. See https://swarm-guide.readthedocs.io for swarm documentation. | -| `bzzup` | swarm command line file uploader. `bzzup --help` for command line options | -| `bzzhash` | command to calculate the swarm hash of a file or directory. `bzzhash --help` for command line options | +| `swarm` | swarm daemon and tools. This is the entrypoint for the swarm network. `swarm --help` for command line options and subcommands. See https://swarm-guide.readthedocs.io for swarm documentation. | ## Running gubiq diff --git a/VERSION b/VERSION index 9075be4951..f01291b87f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.5 +1.5.7 diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index 9cc4374916..46ec075dbd 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -91,8 +91,30 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { // first we need to create a slice of the type var refSlice reflect.Value switch elem.T { - case IntTy, UintTy, BoolTy: // int, uint, bool can all be of type big int. - refSlice = reflect.ValueOf([]*big.Int(nil)) + case IntTy, UintTy, BoolTy: + // create a new reference slice matching the element type + switch t.Type.Kind { + case reflect.Bool: + refSlice = reflect.ValueOf([]bool(nil)) + case reflect.Uint8: + refSlice = reflect.ValueOf([]uint8(nil)) + case reflect.Uint16: + refSlice = reflect.ValueOf([]uint16(nil)) + case reflect.Uint32: + refSlice = reflect.ValueOf([]uint32(nil)) + case reflect.Uint64: + refSlice = reflect.ValueOf([]uint64(nil)) + case reflect.Int8: + refSlice = reflect.ValueOf([]int8(nil)) + case reflect.Int16: + refSlice = reflect.ValueOf([]int16(nil)) + case reflect.Int32: + refSlice = reflect.ValueOf([]int32(nil)) + case reflect.Int64: + refSlice = reflect.ValueOf([]int64(nil)) + default: + refSlice = reflect.ValueOf([]*big.Int(nil)) + } case AddressTy: // address must be of slice Address refSlice = reflect.ValueOf([]common.Address(nil)) case HashTy: // hash must be of slice hash @@ -147,7 +169,27 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { // set inter to the correct type (cast) switch elem.T { case IntTy, UintTy: - inter = common.BytesToBig(returnOutput) + bigNum := common.BytesToBig(returnOutput) + switch t.Type.Kind { + case reflect.Uint8: + inter = uint8(bigNum.Uint64()) + case reflect.Uint16: + inter = uint16(bigNum.Uint64()) + case reflect.Uint32: + inter = uint32(bigNum.Uint64()) + case reflect.Uint64: + inter = bigNum.Uint64() + case reflect.Int8: + inter = int8(bigNum.Int64()) + case reflect.Int16: + inter = int16(bigNum.Int64()) + case reflect.Int32: + inter = int32(bigNum.Int64()) + case reflect.Int64: + inter = bigNum.Int64() + default: + inter = common.BytesToBig(returnOutput) + } case BoolTy: inter = common.BytesToBig(returnOutput).Uint64() > 0 case AddressTy: @@ -169,7 +211,7 @@ func toGoSlice(i int, t Argument, output []byte) (interface{}, error) { // argument in T. func toGoType(i int, t Argument, output []byte) (interface{}, error) { // we need to treat slices differently - if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy { + if (t.Type.IsSlice || t.Type.IsArray) && t.Type.T != BytesTy && t.Type.T != StringTy && t.Type.T != FixedBytesTy && t.Type.T != FunctionTy { return toGoSlice(i, t, output) } @@ -233,7 +275,7 @@ func toGoType(i int, t Argument, output []byte) (interface{}, error) { return common.BytesToAddress(returnOutput), nil case HashTy: return common.BytesToHash(returnOutput), nil - case BytesTy, FixedBytesTy: + case BytesTy, FixedBytesTy, FunctionTy: return returnOutput, nil case StringTy: return string(returnOutput), nil @@ -345,12 +387,13 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) error { func (abi *ABI) UnmarshalJSON(data []byte) error { var fields []struct { - Type string - Name string - Constant bool - Indexed bool - Inputs []Argument - Outputs []Argument + Type string + Name string + Constant bool + Indexed bool + Anonymous bool + Inputs []Argument + Outputs []Argument } if err := json.Unmarshal(data, &fields); err != nil { @@ -375,8 +418,9 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { } case "event": abi.Events[field.Name] = Event{ - Name: field.Name, - Inputs: field.Inputs, + Name: field.Name, + Anonymous: field.Anonymous, + Inputs: field.Inputs, } } } diff --git a/accounts/abi/abi_test.go b/accounts/abi/abi_test.go index 1f9beb0ab6..94a9f5aa05 100644 --- a/accounts/abi/abi_test.go +++ b/accounts/abi/abi_test.go @@ -67,10 +67,10 @@ func TestTypeCheck(t *testing.T) { {"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, {"uint16[3]", []uint16{1, 2, 3}, ""}, {"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, - {"address[]", []common.Address{common.Address{1}}, ""}, - {"address[1]", []common.Address{common.Address{1}}, ""}, - {"address[1]", [1]common.Address{common.Address{1}}, ""}, - {"address[2]", [1]common.Address{common.Address{1}}, "abi: cannot use [1]array as type [2]array as argument"}, + {"address[]", []common.Address{{1}}, ""}, + {"address[1]", []common.Address{{1}}, ""}, + {"address[1]", [1]common.Address{{1}}, ""}, + {"address[2]", [1]common.Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"}, {"bytes32", [32]byte{}, ""}, {"bytes32", [33]byte{}, "abi: cannot use [33]uint8 as type [32]uint8 as argument"}, {"bytes32", common.Hash{1}, ""}, @@ -80,7 +80,8 @@ func TestTypeCheck(t *testing.T) { {"bytes", [2]byte{0, 1}, ""}, {"bytes", common.Hash{1}, ""}, {"string", "hello world", ""}, - {"bytes32[]", [][32]byte{[32]byte{}}, ""}, + {"bytes32[]", [][32]byte{{}}, ""}, + {"function", [24]byte{}, ""}, } { typ, err := NewType(test.typ) if err != nil { @@ -197,6 +198,13 @@ func TestSimpleMethodUnpack(t *testing.T) { "interface", "", }, + { + `[ { "type": "function" } ]`, + pad([]byte{1}, 32, false), + [24]byte{1}, + "function", + "", + }, } { abiDefinition := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) abi, err := JSON(strings.NewReader(abiDefinition)) @@ -255,6 +263,10 @@ func TestSimpleMethodUnpack(t *testing.T) { var v common.Hash err = abi.Unpack(&v, "method", test.marshalledOutput) outvar = v + case "function": + var v [24]byte + err = abi.Unpack(&v, "method", test.marshalledOutput) + outvar = v case "interface": err = abi.Unpack(&outvar, "method", test.marshalledOutput) default: @@ -320,6 +332,30 @@ func TestUnpackSetInterfaceSlice(t *testing.T) { } } +func TestUnpackSetInterfaceArrayOutput(t *testing.T) { + var ( + var1 = new([1]uint32) + var2 = new([1]uint32) + ) + out := []interface{}{var1, var2} + abi, err := JSON(strings.NewReader(`[{"type":"function", "name":"ints", "outputs":[{"type":"uint32[1]"}, {"type":"uint32[1]"}]}]`)) + if err != nil { + t.Fatal(err) + } + marshalledReturn := append(pad([]byte{1}, 32, true), pad([]byte{2}, 32, true)...) + err = abi.Unpack(&out, "ints", marshalledReturn) + if err != nil { + t.Fatal(err) + } + + if *var1 != [1]uint32{1} { + t.Error("expected var1 to be [1], got", *var1) + } + if *var2 != [1]uint32{2} { + t.Error("expected var2 to be [2], got", *var2) + } +} + func TestPack(t *testing.T) { for i, test := range []struct { typ string @@ -331,8 +367,9 @@ func TestPack(t *testing.T) { {"uint16[]", []uint16{1, 2}, formatSliceOutput([]byte{1}, []byte{2})}, {"bytes20", [20]byte{1}, pad([]byte{1}, 32, false)}, {"uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, formatSliceOutput([]byte{1}, []byte{2})}, - {"address[]", []common.Address{common.Address{1}, common.Address{2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, false))}, - {"bytes32[]", []common.Hash{common.Hash{1}, common.Hash{2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))}, + {"address[]", []common.Address{{1}, {2}}, formatSliceOutput(pad([]byte{1}, 20, false), pad([]byte{2}, 20, false))}, + {"bytes32[]", []common.Hash{{1}, {2}}, formatSliceOutput(pad([]byte{1}, 32, false), pad([]byte{2}, 32, false))}, + {"function", [24]byte{1}, pad([]byte{1}, 32, false)}, } { typ, err := NewType(test.typ) if err != nil { @@ -445,12 +482,12 @@ func TestReader(t *testing.T) { Uint256, _ := NewType("uint256") exp := ABI{ Methods: map[string]Method{ - "balance": Method{ + "balance": { "balance", true, nil, nil, }, - "send": Method{ + "send": { "send", false, []Argument{ - Argument{"amount", Uint256, false}, + {"amount", Uint256, false}, }, nil, }, }, @@ -549,7 +586,7 @@ func TestTestSlice(t *testing.T) { func TestMethodSignature(t *testing.T) { String, _ := NewType("string") - m := Method{"foo", false, []Argument{Argument{"bar", String, false}, Argument{"baz", String, false}}, nil} + m := Method{"foo", false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil} exp := "foo(string,string)" if m.Sig() != exp { t.Error("signature mismatch", exp, "!=", m.Sig()) @@ -561,7 +598,7 @@ func TestMethodSignature(t *testing.T) { } uintt, _ := NewType("uint") - m = Method{"foo", false, []Argument{Argument{"bar", uintt, false}}, nil} + m = Method{"foo", false, []Argument{{"bar", uintt, false}}, nil} exp = "foo(uint256)" if m.Sig() != exp { t.Error("signature mismatch", exp, "!=", m.Sig()) @@ -752,23 +789,58 @@ func TestDefaultFunctionParsing(t *testing.T) { func TestBareEvents(t *testing.T) { const definition = `[ { "type" : "event", "name" : "balance" }, - { "type" : "event", "name" : "name" }]` + { "type" : "event", "name" : "anon", "anonymous" : true}, + { "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] } + ]` + + arg0, _ := NewType("uint256") + arg1, _ := NewType("address") + + expectedEvents := map[string]struct { + Anonymous bool + Args []Argument + }{ + "balance": {false, nil}, + "anon": {true, nil}, + "args": {false, []Argument{ + {Name: "arg0", Type: arg0, Indexed: false}, + {Name: "arg1", Type: arg1, Indexed: true}, + }}, + } abi, err := JSON(strings.NewReader(definition)) if err != nil { t.Fatal(err) } - if len(abi.Events) != 2 { - t.Error("expected 2 events") + if len(abi.Events) != len(expectedEvents) { + t.Fatalf("invalid number of events after parsing, want %d, got %d", len(expectedEvents), len(abi.Events)) } - if _, ok := abi.Events["balance"]; !ok { - t.Error("expected 'balance' event to be present") - } - - if _, ok := abi.Events["name"]; !ok { - t.Error("expected 'name' event to be present") + for name, exp := range expectedEvents { + got, ok := abi.Events[name] + if !ok { + t.Errorf("could not found event %s", name) + continue + } + if got.Anonymous != exp.Anonymous { + t.Errorf("invalid anonymous indication for event %s, want %v, got %v", name, exp.Anonymous, got.Anonymous) + } + if len(got.Inputs) != len(exp.Args) { + t.Errorf("invalid number of args, want %d, got %d", len(exp.Args), len(got.Inputs)) + continue + } + for i, arg := range exp.Args { + if arg.Name != got.Inputs[i].Name { + t.Errorf("events[%s].Input[%d] has an invalid name, want %s, got %s", name, i, arg.Name, got.Inputs[i].Name) + } + if arg.Indexed != got.Inputs[i].Indexed { + t.Errorf("events[%s].Input[%d] has an invalid indexed indication, want %v, got %v", name, i, arg.Indexed, got.Inputs[i].Indexed) + } + if arg.Type.T != got.Inputs[i].Type.T { + t.Errorf("events[%s].Input[%d] has an invalid type, want %x, got %x", name, i, arg.Type.T, got.Inputs[i].Type.T) + } + } } } diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 188203a5d1..4691318ce7 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -31,8 +31,9 @@ type Argument struct { func (a *Argument) UnmarshalJSON(data []byte) error { var extarg struct { - Name string - Type string + Name string + Type string + Indexed bool } err := json.Unmarshal(data, &extarg) if err != nil { @@ -44,6 +45,7 @@ func (a *Argument) UnmarshalJSON(data []byte) error { return err } a.Name = extarg.Name + a.Indexed = extarg.Indexed return nil } diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go index 8cef0ee7be..8a20d6a41c 100644 --- a/accounts/abi/bind/auth.go +++ b/accounts/abi/bind/auth.go @@ -52,7 +52,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts { if address != keyAddr { return nil, errors.New("not authorized to sign this account") } - signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key) + signature, err := crypto.Sign(signer.Hash(tx).Bytes(), key) if err != nil { return nil, err } diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 1c627ccd21..5a040743d0 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -225,7 +225,11 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM from.SetBalance(common.MaxBig) // Execute the call. msg := callmsg{call} - vmenv := core.NewEnv(statedb, chainConfig, b.blockchain, msg, block.Header(), vm.Config{}) + + evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain) + // Create a new environment which holds all relevant information + // about the transaction and calling mechanisms. + vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{}) gaspool := new(core.GasPool).AddGas(common.MaxBig) ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() return ret, gasUsed, err diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index de10dadc4d..9fcee75f24 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -170,7 +170,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i if value == nil { value = new(big.Int) } - nonce := uint64(0) + var nonce uint64 if opts.Nonce == nil { nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From) if err != nil { diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 2516d9685e..e1da75c632 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -147,21 +147,21 @@ func bindTypeGo(kind abi.Type) string { switch { case strings.HasPrefix(stringKind, "address"): - parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 2 { return stringKind } return fmt.Sprintf("%scommon.Address", parts[1]) case strings.HasPrefix(stringKind, "bytes"): - parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 3 { return stringKind } return fmt.Sprintf("%s[%s]byte", parts[2], parts[1]) case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): - parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 4 { return stringKind } @@ -172,7 +172,7 @@ func bindTypeGo(kind abi.Type) string { return fmt.Sprintf("%s*big.Int", parts[3]) case strings.HasPrefix(stringKind, "bool") || strings.HasPrefix(stringKind, "string"): - parts := regexp.MustCompile("([a-z]+)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`([a-z]+)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 3 { return stringKind } @@ -191,7 +191,7 @@ func bindTypeJava(kind abi.Type) string { switch { case strings.HasPrefix(stringKind, "address"): - parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 2 { return stringKind } @@ -201,7 +201,7 @@ func bindTypeJava(kind abi.Type) string { return fmt.Sprintf("Addresses") case strings.HasPrefix(stringKind, "bytes"): - parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`bytes([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 3 { return stringKind } @@ -211,7 +211,7 @@ func bindTypeJava(kind abi.Type) string { return "byte[]" case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"): - parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 4 { return stringKind } @@ -230,7 +230,7 @@ func bindTypeJava(kind abi.Type) string { return fmt.Sprintf("BigInts") case strings.HasPrefix(stringKind, "bool"): - parts := regexp.MustCompile("bool(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`bool(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 2 { return stringKind } @@ -240,7 +240,7 @@ func bindTypeJava(kind abi.Type) string { return fmt.Sprintf("bool[]") case strings.HasPrefix(stringKind, "string"): - parts := regexp.MustCompile("string(\\[[0-9]*\\])?").FindStringSubmatch(stringKind) + parts := regexp.MustCompile(`string(\[[0-9]*\])?`).FindStringSubmatch(stringKind) if len(parts) != 2 { return stringKind } @@ -278,7 +278,7 @@ func namedTypeJava(javaKind string, solKind abi.Type) string { case "bool[]": return "Bools" case "BigInt": - parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(solKind.String()) + parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String()) if len(parts) != 4 { return javaKind } diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index 97ea7fc0ad..f304dcbc38 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) { // Create the transaction. tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) - tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey) + tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) // Wait for it to get mined in the background. var ( diff --git a/accounts/abi/event.go b/accounts/abi/event.go index 71b2deddac..6613fd43d6 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -25,10 +25,12 @@ import ( ) // Event is an event potentially triggered by the EVM's LOG mechanism. The Event -// holds type information (inputs) about the yielded output +// holds type information (inputs) about the yielded output. Anonymous events +// don't get the signature canonical representation as the first LOG topic. type Event struct { - Name string - Inputs []Argument + Name string + Anonymous bool + Inputs []Argument } // Id returns the canonical representation of the event's signature used by the diff --git a/accounts/abi/packing.go b/accounts/abi/packing.go index f4c9c1e14d..a117a37ac9 100644 --- a/accounts/abi/packing.go +++ b/accounts/abi/packing.go @@ -54,7 +54,7 @@ func packElement(t Type, reflectValue reflect.Value) []byte { reflectValue = mustArrayToByteSlice(reflectValue) } return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()) - case FixedBytesTy: + case FixedBytesTy, FunctionTy: if reflectValue.Kind() == reflect.Array { reflectValue = mustArrayToByteSlice(reflectValue) } diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 39b843f817..f2832aef56 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -33,7 +33,8 @@ const ( FixedBytesTy BytesTy HashTy - RealTy + FixedpointTy + FunctionTy ) // Type is the reflection of the supported argument type @@ -57,16 +58,16 @@ var ( // Types can be in the format of: // // Input = Type [ "[" [ Number ] "]" ] Name . - // Type = [ "u" ] "int" [ Number ] . + // Type = [ "u" ] "int" [ Number ] [ x ] [ Number ]. // // Examples: // - // string int uint real + // string int uint fixed // string32 int8 uint8 uint[] - // address int256 uint256 real[2] - fullTypeRegex = regexp.MustCompile("([a-zA-Z0-9]+)(\\[([0-9]*)?\\])?") + // address int256 uint256 fixed128x128[2] + fullTypeRegex = regexp.MustCompile(`([a-zA-Z0-9]+)(\[([0-9]*)\])?`) // typeRegex parses the abi sub types - typeRegex = regexp.MustCompile("([a-zA-Z]+)([0-9]*)?") + typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") ) // NewType creates a new reflection type of abi type given in t. @@ -90,14 +91,19 @@ func NewType(t string) (typ Type, err error) { } typ.Elem = &sliceType typ.stringKind = sliceType.stringKind + t[len(res[1]):] - return typ, nil + // Although we know that this is an array, we cannot return + // as we don't know the type of the element, however, if it + // is still an array, then don't determine the type. + if typ.Elem.IsArray || typ.Elem.IsSlice { + return typ, nil + } } // parse the type and size of the abi-type. parsedType := typeRegex.FindAllStringSubmatch(res[1], -1)[0] // varSize is the size of the variable var varSize int - if len(parsedType[2]) > 0 { + if len(parsedType[3]) > 0 { var err error varSize, err = strconv.Atoi(parsedType[2]) if err != nil { @@ -111,7 +117,12 @@ func NewType(t string) (typ Type, err error) { varSize = 256 t += "256" } - typ.stringKind = t + + // only set stringKind if not array or slice, as for those, + // the correct string type has been set + if !(typ.IsArray || typ.IsSlice) { + typ.stringKind = t + } switch varType { case "int": @@ -148,6 +159,12 @@ func NewType(t string) (typ Type, err error) { typ.T = FixedBytesTy typ.SliceSize = varSize } + case "function": + sliceType, _ := NewType("uint8") + typ.Elem = &sliceType + typ.IsArray = true + typ.T = FunctionTy + typ.SliceSize = 24 default: return Type{}, fmt.Errorf("unsupported arg type: %s", t) } @@ -168,7 +185,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { return nil, err } - if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy { + if (t.IsSlice || t.IsArray) && t.T != BytesTy && t.T != FixedBytesTy && t.T != FunctionTy { var packed []byte for i := 0; i < v.Len(); i++ { diff --git a/accounts/abi/type_test.go b/accounts/abi/type_test.go new file mode 100644 index 0000000000..1557c2a41b --- /dev/null +++ b/accounts/abi/type_test.go @@ -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 . + +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)) + } + } +} diff --git a/accounts/account_manager.go b/accounts/account_manager.go index c3b340bcfb..a3bc57db8c 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -136,13 +136,12 @@ func (am *Manager) DeleteAccount(a Account, passphrase string) error { return err } -// Sign calculates a ECDSA signature for the given hash. -// Note, Ethereum signatures have a particular format as described in the -// yellow paper. Use the SignEthereum function to calculate a signature -// in Ethereum format. +// Sign calculates a ECDSA signature for the given hash. The produced signature +// is in the [R || S || V] format where V is 0 or 1. func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) { am.mu.RLock() defer am.mu.RUnlock() + unlockedKey, found := am.unlocked[addr] if !found { return nil, ErrLocked @@ -150,28 +149,16 @@ func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) { return crypto.Sign(hash, unlockedKey.PrivateKey) } -// SignEthereum calculates a ECDSA signature for the given hash. -// The signature has the format as described in the Ethereum yellow paper. -func (am *Manager) SignEthereum(addr common.Address, hash []byte) ([]byte, error) { - am.mu.RLock() - defer am.mu.RUnlock() - unlockedKey, found := am.unlocked[addr] - if !found { - return nil, ErrLocked - } - return crypto.SignEthereum(hash, unlockedKey.PrivateKey) -} - -// SignWithPassphrase signs hash if the private key matching the given -// address can be decrypted with the given passphrase. -func (am *Manager) SignWithPassphrase(addr common.Address, passphrase string, hash []byte) (signature []byte, err error) { - _, key, err := am.getDecryptedKey(Account{Address: addr}, passphrase) +// SignWithPassphrase signs hash if the private key matching the given address +// can be decrypted with the given passphrase. The produced signature is in the +// [R || S || V] format where V is 0 or 1. +func (am *Manager) SignWithPassphrase(a Account, passphrase string, hash []byte) (signature []byte, err error) { + _, key, err := am.getDecryptedKey(a, passphrase) if err != nil { return nil, err } - defer zeroKey(key.PrivateKey) - return crypto.SignEthereum(hash, key.PrivateKey) + return crypto.Sign(hash, key.PrivateKey) } // Unlock unlocks the given account indefinitely. diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index 5ae3aa55c7..988ae1a4b3 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -95,7 +95,7 @@ func TestSignWithPassphrase(t *testing.T) { t.Fatal("expected account to be locked") } - _, err = am.SignWithPassphrase(acc.Address, pass, testSigData) + _, err = am.SignWithPassphrase(acc, pass, testSigData) if err != nil { t.Fatal(err) } @@ -104,7 +104,7 @@ func TestSignWithPassphrase(t *testing.T) { t.Fatal("expected account to be locked") } - if _, err = am.SignWithPassphrase(acc.Address, "invalid passwd", testSigData); err == nil { + if _, err = am.SignWithPassphrase(acc, "invalid passwd", testSigData); err == nil { t.Fatal("expected SignHash to fail with invalid password") } } @@ -115,6 +115,9 @@ func TestTimedUnlock(t *testing.T) { pass := "foo" a1, err := am.NewAccount(pass) + if err != nil { + t.Fatal(err) + } // Signing without passphrase fails because account is locked _, err = am.Sign(a1.Address, testSigData) @@ -147,6 +150,9 @@ func TestOverrideUnlock(t *testing.T) { pass := "foo" a1, err := am.NewAccount(pass) + if err != nil { + t.Fatal(err) + } // Unlock indefinitely. if err = am.TimedUnlock(a1, pass, 5*time.Minute); err != nil { diff --git a/accounts/presale.go b/accounts/presale.go index 211a241564..17fa4f13d3 100644 --- a/accounts/presale.go +++ b/accounts/presale.go @@ -22,6 +22,7 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "fmt" "github.com/ubiq/go-ubiq/crypto" @@ -53,6 +54,9 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error return nil, err } encSeedBytes, err := hex.DecodeString(preSaleKeyStruct.EncSeed) + if err != nil { + return nil, errors.New("invalid hex in encSeed") + } iv := encSeedBytes[:16] cipherText := encSeedBytes[16:] /* diff --git a/appveyor.yml b/appveyor.yml index 181ea0d5d6..3463e4e091 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,8 +22,8 @@ environment: install: - rmdir C:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.3.windows-%GETH_ARCH%.zip - - 7z x go1.7.3.windows-%GETH_ARCH%.zip -y -oC:\ > NUL + - appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.4.windows-%GETH_ARCH%.zip + - 7z x go1.7.4.windows-%GETH_ARCH%.zip -y -oC:\ > NUL - go version - gcc --version diff --git a/build/ci.go b/build/ci.go index 3c24aba018..7826088cb1 100644 --- a/build/ci.go +++ b/build/ci.go @@ -24,7 +24,7 @@ Usage: go run ci.go Available commands are: install [-arch architecture] [ packages... ] -- builds packages and executables - test [ -coverage ] [ -vet ] [ packages... ] -- runs the tests + test [ -coverage ] [ -vet ] [ -misspell ] [ packages... ] -- runs the tests archive [-arch architecture] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts importkeys -- imports signing keys from env debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package @@ -72,9 +72,7 @@ var ( executablePath("abigen"), executablePath("evm"), executablePath("gubiq"), - executablePath("bzzd"), - executablePath("bzzhash"), - executablePath("bzzup"), + executablePath("swarm"), executablePath("rlpdump"), } @@ -93,16 +91,8 @@ var ( Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.", }, { - Name: "bzzd", - Description: "Ethereum Swarm daemon", - }, - { - Name: "bzzup", - Description: "Ethereum Swarm command line file/directory uploader", - }, - { - Name: "bzzhash", - Description: "Ethereum Swarm file/directory hash calculator", + Name: "swarm", + Description: "Ethereum Swarm daemon and tools", }, { Name: "abigen", @@ -112,7 +102,8 @@ var ( // Distros for which packages are created. // Note: vivid is unsupported because there is no golang-1.6 package for it. - debDistros = []string{"trusty", "wily", "xenial", "yakkety"} + // Note: wily is unsupported because it was officially deprecated on lanchpad. + debDistros = []string{"trusty", "xenial", "yakkety"} ) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) @@ -204,7 +195,7 @@ func doInstall(cmdline []string) { if err != nil { log.Fatal(err) } - for name, _ := range pkgs { + for name := range pkgs { if name == "main" { gobuild := goToolArch(*arch, "build", buildFlags(env)...) gobuild.Args = append(gobuild.Args, "-v") @@ -271,6 +262,7 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd { func doTest(cmdline []string) { var ( vet = flag.Bool("vet", false, "Whether to run go vet") + misspell = flag.Bool("misspell", false, "Whether to run the spell checker") coverage = flag.Bool("coverage", false, "Whether to record code coverage") ) flag.CommandLine.Parse(cmdline) @@ -296,7 +288,9 @@ func doTest(cmdline []string) { if *vet { build.MustRun(goTool("vet", packages...)) } - + if *misspell { + spellcheck(packages) + } // Run the actual tests. gotest := goTool("test") // Test a single package at a time. CI builders are slow @@ -309,6 +303,34 @@ func doTest(cmdline []string) { build.MustRun(gotest) } +// spellcheck runs the client9/misspell spellchecker package on all Go, Cgo and +// test files in the requested packages. +func spellcheck(packages []string) { + // Ensure the spellchecker is available + build.MustRun(goTool("get", "github.com/client9/misspell/cmd/misspell")) + + // Windows chokes on long argument lists, check packages individualy + for _, pkg := range packages { + // The spell checker doesn't work on packages, gather all .go files for it + out, err := goTool("list", "-f", "{{.Dir}}{{range .GoFiles}}\n{{.}}{{end}}{{range .CgoFiles}}\n{{.}}{{end}}{{range .TestGoFiles}}\n{{.}}{{end}}", pkg).CombinedOutput() + if err != nil { + log.Fatalf("source file listing failed: %v\n%s", err, string(out)) + } + // Retrieve the folder and assemble the source list + lines := strings.Split(string(out), "\n") + root := lines[0] + + sources := make([]string, 0, len(lines)-1) + for _, line := range lines[1:] { + if line = strings.TrimSpace(line); line != "" { + sources = append(sources, filepath.Join(root, line)) + } + } + // Run the spell checker for this particular package + build.MustRunCommand(filepath.Join(GOBIN, "misspell"), append([]string{"-error"}, sources...)...) + } +} + // Release Packaging func doArchive(cmdline []string) { @@ -332,7 +354,7 @@ func doArchive(cmdline []string) { var ( env = build.Env() base = archiveBasename(*arch, env) - gubiq = "gubiq-" + base + ext + gubiq = "gubiq-" + base + ext alltools = "gubiq-alltools-" + base + ext ) maybeSkipArchive(env) @@ -612,8 +634,8 @@ func doWindowsInstaller(cmdline []string) { // Aggregate binaries that are included in the installer var ( - devTools []string - allTools []string + devTools []string + allTools []string gubiqTool string ) for _, file := range allToolsArchiveFiles { @@ -632,12 +654,13 @@ func doWindowsInstaller(cmdline []string) { // first section contains the gubiq binary, second section holds the dev tools. templateData := map[string]interface{}{ "License": "COPYING", - "Gubiq": gubiqTool, + "Gubiq": gubiqTool, "DevTools": devTools, } 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.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools) + build.Render("build/nsis.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.nsh"), 0644, nil) build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil) build.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll", 0755) build.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING", 0755) @@ -800,7 +823,7 @@ func doXCodeFramework(cmdline []string) { // Build the iOS XCode framework build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile")) build.MustRun(gomobileTool("init")) - bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "--prefix", "GE", "-v", "github.com/ubiq/go-ubiq/mobile") + bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "-v", "github.com/ubiq/go-ubiq/mobile") if *local { // If we're building locally, use the build folder and stop afterwards diff --git a/build/nsis.gubiq.nsi b/build/nsis.gubiq.nsi index 1c5546e083..f7a2e1a32b 100644 --- a/build/nsis.gubiq.nsi +++ b/build/nsis.gubiq.nsi @@ -17,8 +17,12 @@ # # Requirements: # - NSIS, http://nsis.sourceforge.net/Main_Page +# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds # - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi) # +# After intalling NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the +# files found in Stub. +# # based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller # # TODO: @@ -37,6 +41,7 @@ RequestExecutionLevel admin SetCompressor /SOLID lzma !include LogicLib.nsh +!include PathUpdate.nsh !include EnvVarUpdate.nsh !macro VerifyUserIsAdmin diff --git a/build/nsis.install.nsh b/build/nsis.install.nsh index 82f9153cb2..2664c73bb3 100644 --- a/build/nsis.install.nsh +++ b/build/nsis.install.nsh @@ -37,8 +37,9 @@ Section "Gubiq" GETH_IDX ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc" ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\gubiq.ipc" - # Add gubiq to PATH - ${EnvVarUpdate} $0 "PATH" "A" "HKLM" $INSTDIR + # Add instdir to PATH + Push "$INSTDIR" + Call AddToPath SectionEnd # Install optional develop tools. diff --git a/build/nsis.pathupdate.nsh b/build/nsis.pathupdate.nsh new file mode 100644 index 0000000000..f54b7e3e13 --- /dev/null +++ b/build/nsis.pathupdate.nsh @@ -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 + + diff --git a/build/nsis.uninstall.nsh b/build/nsis.uninstall.nsh index 04a15d2820..c7fe292426 100644 --- a/build/nsis.uninstall.nsh +++ b/build/nsis.uninstall.nsh @@ -25,7 +25,8 @@ Section "Uninstall" ${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\gubiq.ipc" # Remove install directory from PATH - ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" $INSTDIR + Push "$INSTDIR" + Call un.RemoveFromPath # Cleanup registry (deletes all sub keys) DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" diff --git a/build/update-license.go b/build/update-license.go index f1ebd53bad..bc956ea136 100644 --- a/build/update-license.go +++ b/build/update-license.go @@ -185,7 +185,7 @@ func getFiles() []string { files = append(files, line) }) if err != nil { - log.Fatalf("error getting files:", err) + log.Fatal("error getting files:", err) } return files } @@ -294,7 +294,7 @@ func getInfo(files <-chan string, out chan<- *info, wg *sync.WaitGroup) { wg.Done() } -// fileInfo finds the lowest year in which the given file was commited. +// fileInfo finds the lowest year in which the given file was committed. func fileInfo(file string) (*info, error) { info := &info{file: file, Year: int64(time.Now().Year())} cmd := exec.Command("git", "log", "--follow", "--find-renames=80", "--find-copies=80", "--pretty=format:%ai", "--", file) diff --git a/cmd/bzzup/main.go b/cmd/bzzup/main.go deleted file mode 100644 index 7d251aadb0..0000000000 --- a/cmd/bzzup/main.go +++ /dev/null @@ -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 . - -// 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 -} diff --git a/cmd/disasm/main.go b/cmd/disasm/main.go index 4e6d860d90..d2f5c1dfc0 100644 --- a/cmd/disasm/main.go +++ b/cmd/disasm/main.go @@ -18,11 +18,12 @@ package main import ( + "encoding/hex" "fmt" "io/ioutil" "os" + "strings" - "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core/vm" ) @@ -32,20 +33,28 @@ func main() { fmt.Println(err) os.Exit(1) } - code = common.Hex2Bytes(string(code[:len(code)-1])) + code, err = hex.DecodeString(strings.TrimSpace(string(code[:]))) + if err != nil { + fmt.Printf("Error: %v\n", err) + return + } fmt.Printf("%x\n", code) for pc := uint64(0); pc < uint64(len(code)); pc++ { op := vm.OpCode(code[pc]) - fmt.Printf("%-5d %v", pc, op) switch op { case vm.PUSH1, vm.PUSH2, vm.PUSH3, vm.PUSH4, vm.PUSH5, vm.PUSH6, vm.PUSH7, vm.PUSH8, vm.PUSH9, vm.PUSH10, vm.PUSH11, vm.PUSH12, vm.PUSH13, vm.PUSH14, vm.PUSH15, vm.PUSH16, vm.PUSH17, vm.PUSH18, vm.PUSH19, vm.PUSH20, vm.PUSH21, vm.PUSH22, vm.PUSH23, vm.PUSH24, vm.PUSH25, vm.PUSH26, vm.PUSH27, vm.PUSH28, vm.PUSH29, vm.PUSH30, vm.PUSH31, vm.PUSH32: a := uint64(op) - uint64(vm.PUSH1) + 1 - fmt.Printf(" => %x", code[pc+1:pc+1+a]) - + u := pc + 1 + a + if uint64(len(code)) <= pc || uint64(len(code)) < u { + fmt.Printf("Error: incomplete push instruction at %v\n", pc) + return + } + fmt.Printf("%-5d %v => %x\n", pc, op, code[pc+1:u]) pc += a + default: + fmt.Printf("%-5d %v\n", pc, op) } - fmt.Println() } } diff --git a/cmd/ethtest/main.go b/cmd/ethtest/main.go index cc60113aed..dc3fc9238f 100644 --- a/cmd/ethtest/main.go +++ b/cmd/ethtest/main.go @@ -88,12 +88,7 @@ func runTestWithReader(test string, r io.Reader) error { default: err = fmt.Errorf("Invalid test type specified: %v", test) } - - if err != nil { - return err - } - - return nil + return err } func getFiles(path string) ([]string, error) { diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 085831d4dd..41bfca424e 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -20,21 +20,18 @@ package main import ( "fmt" "io/ioutil" - "math/big" "os" - "runtime" + goruntime "runtime" "time" "github.com/ubiq/go-ubiq/cmd/utils" "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/types" "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/ethdb" "github.com/ubiq/go-ubiq/logger/glog" - "github.com/ubiq/go-ubiq/params" "gopkg.in/urfave/cli.v1" ) @@ -47,14 +44,6 @@ var ( Name: "debug", Usage: "output full trace logs", } - ForceJitFlag = cli.BoolFlag{ - Name: "forcejit", - Usage: "forces jit compilation", - } - DisableJitFlag = cli.BoolFlag{ - Name: "nojit", - Usage: "disabled jit compilation", - } CodeFlag = cli.StringFlag{ Name: "code", Usage: "EVM code", @@ -98,6 +87,10 @@ var ( Name: "create", Usage: "indicates the action should be create rather than call", } + DisableGasMeteringFlag = cli.BoolFlag{ + Name: "nogasmetering", + Usage: "disable gas metering", + } ) func init() { @@ -105,8 +98,6 @@ func init() { CreateFlag, DebugFlag, VerbosityFlag, - ForceJitFlag, - DisableJitFlag, SysStatFlag, CodeFlag, CodeFileFlag, @@ -115,6 +106,7 @@ func init() { ValueFlag, DumpFlag, InputFlag, + DisableGasMeteringFlag, } app.Action = run } @@ -129,13 +121,6 @@ func run(ctx *cli.Context) error { logger := vm.NewStructLogger(nil) - vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name)), vm.Config{ - Debug: ctx.GlobalBool(DebugFlag.Name), - ForceJit: ctx.GlobalBool(ForceJitFlag.Name), - EnableJit: !ctx.GlobalBool(DisableJitFlag.Name), - Tracer: logger, - }) - tstart := time.Now() var ( @@ -168,25 +153,32 @@ func run(ctx *cli.Context) error { if ctx.GlobalBool(CreateFlag.Name) { input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) - ret, _, err = vmenv.Create( - sender, - input, - common.Big(ctx.GlobalString(GasFlag.Name)), - common.Big(ctx.GlobalString(PriceFlag.Name)), - common.Big(ctx.GlobalString(ValueFlag.Name)), - ) + ret, _, err = runtime.Create(input, &runtime.Config{ + Origin: sender.Address(), + State: statedb, + GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)), + GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), + Value: common.Big(ctx.GlobalString(ValueFlag.Name)), + EVMConfig: vm.Config{ + Tracer: logger, + DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), + }, + }) } else { receiver := statedb.CreateAccount(common.StringToAddress("receiver")) - receiver.SetCode(crypto.Keccak256Hash(code), code) - ret, err = vmenv.Call( - sender, - receiver.Address(), - common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), - common.Big(ctx.GlobalString(GasFlag.Name)), - common.Big(ctx.GlobalString(PriceFlag.Name)), - common.Big(ctx.GlobalString(ValueFlag.Name)), - ) + + ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ + Origin: sender.Address(), + State: statedb, + GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)), + GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), + Value: common.Big(ctx.GlobalString(ValueFlag.Name)), + EVMConfig: vm.Config{ + Tracer: logger, + DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), + }, + }) } vmdone := time.Since(tstart) @@ -197,8 +189,8 @@ func run(ctx *cli.Context) error { vm.StdErrFormat(logger.StructLogs()) if ctx.GlobalBool(SysStatFlag.Name) { - var mem runtime.MemStats - runtime.ReadMemStats(&mem) + var mem goruntime.MemStats + goruntime.ReadMemStats(&mem) fmt.Printf("vm took %v\n", vmdone) fmt.Printf(`alloc: %d tot alloc: %d @@ -223,87 +215,3 @@ func main() { os.Exit(1) } } - -type VMEnv struct { - state *state.StateDB - block *types.Block - - transactor *common.Address - value *big.Int - - depth int - Gas *big.Int - time *big.Int - logs []vm.StructLog - - evm *vm.EVM -} - -func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int, cfg vm.Config) *VMEnv { - env := &VMEnv{ - state: state, - transactor: &transactor, - value: value, - time: big.NewInt(time.Now().Unix()), - } - - env.evm = vm.New(env, cfg) - return env -} - -// ruleSet implements vm.ChainConfig and will always default to the homestead rule set. -type ruleSet struct{} - -func (ruleSet) IsHomestead(*big.Int) bool { return true } -func (ruleSet) GasTable(*big.Int) params.GasTable { - return params.GasTableHomesteadGasRepriceFork -} - -func (self *VMEnv) ChainConfig() *params.ChainConfig { return params.TestChainConfig } -func (self *VMEnv) Vm() vm.Vm { return self.evm } -func (self *VMEnv) Db() vm.Database { return self.state } -func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() } -func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) } -func (self *VMEnv) Origin() common.Address { return *self.transactor } -func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 } -func (self *VMEnv) Coinbase() common.Address { return *self.transactor } -func (self *VMEnv) Time() *big.Int { return self.time } -func (self *VMEnv) Difficulty() *big.Int { return common.Big1 } -func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) } -func (self *VMEnv) Value() *big.Int { return self.value } -func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) } -func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy } -func (self *VMEnv) Depth() int { return 0 } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) GetHash(n uint64) common.Hash { - if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 { - return self.block.Hash() - } - return common.Hash{} -} -func (self *VMEnv) AddLog(log *vm.Log) { - self.state.AddLog(log) -} -func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool { - return self.state.GetBalance(from).Cmp(balance) >= 0 -} -func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) { - core.Transfer(from, to, amount) -} - -func (self *VMEnv) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - self.Gas = gas - return core.Call(self, caller, addr, data, gas, price, value) -} - -func (self *VMEnv) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return core.CallCode(self, caller, addr, data, gas, price, value) -} - -func (self *VMEnv) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - return core.DelegateCall(self, caller, addr, data, gas, price) -} - -func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - return core.Create(self, caller, data, gas, price, value) -} diff --git a/cmd/gubiq/accountcmd_test.go b/cmd/gubiq/accountcmd_test.go index de5d35e462..5ac21e42fb 100644 --- a/cmd/gubiq/accountcmd_test.go +++ b/cmd/gubiq/accountcmd_test.go @@ -148,7 +148,7 @@ Passphrase: {{.InputLine "foobar"}} "Unlocked account f466859ead1932d743d622cb74fc058882e8648a", } 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) } } @@ -193,7 +193,7 @@ Passphrase: {{.InputLine "foobar"}} "Unlocked account 289d485d9771714cce91d3393d764e1311907acc", } 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) } } @@ -212,7 +212,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) { "Unlocked account 289d485d9771714cce91d3393d764e1311907acc", } 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) } } @@ -260,7 +260,7 @@ In order to avoid this warning, you need to remove the following duplicate key f "Unlocked account f466859ead1932d743d622cb74fc058882e8648a", } for _, m := range wantMessages { - if strings.Index(gubiq.stderrText(), m) == -1 { + if !strings.Contains(gubiq.stderrText(), m) { t.Errorf("stderr text does not contain %q", m) } } diff --git a/cmd/gubiq/library.c b/cmd/gubiq/library.c deleted file mode 100644 index f738621a82..0000000000 --- a/cmd/gubiq/library.c +++ /dev/null @@ -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 . - -// 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); -} diff --git a/cmd/gubiq/library.go b/cmd/gubiq/library.go deleted file mode 100644 index c7a8a44d31..0000000000 --- a/cmd/gubiq/library.go +++ /dev/null @@ -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 . - -// 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 -} diff --git a/cmd/gubiq/library_android.go b/cmd/gubiq/library_android.go deleted file mode 100644 index 17a0285d6c..0000000000 --- a/cmd/gubiq/library_android.go +++ /dev/null @@ -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 . - -// Contains specialized code for running Gubiq on Android. - -package main - -// #include -// #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") - } - }() -} diff --git a/cmd/gubiq/main.go b/cmd/gubiq/main.go index 6394066ec2..0d9a91cd4f 100644 --- a/cmd/gubiq/main.go +++ b/cmd/gubiq/main.go @@ -88,7 +88,6 @@ func init() { utils.BootnodesFlag, utils.DataDirFlag, utils.KeyStoreDirFlag, - utils.OlympicFlag, utils.FastSyncFlag, utils.LightModeFlag, utils.LightServFlag, @@ -168,7 +167,6 @@ func init() { } app.After = func(ctx *cli.Context) error { - logger.Flush() debug.Exit() console.Stdin.Close() // Resets terminal mode. return nil diff --git a/cmd/gubiq/monitorcmd.go b/cmd/gubiq/monitorcmd.go index 0f65222c4c..6a9508063c 100644 --- a/cmd/gubiq/monitorcmd.go +++ b/cmd/gubiq/monitorcmd.go @@ -236,8 +236,9 @@ func expandMetrics(metrics map[string]interface{}, path string) []string { // fetchMetric iterates over the metrics map and retrieves a specific one. func fetchMetric(metrics map[string]interface{}, metric string) float64 { - parts, found := strings.Split(metric, "/"), true + parts := strings.Split(metric, "/") for _, part := range parts[:len(parts)-1] { + var found bool metrics, found = metrics[part].(map[string]interface{}) if !found { return 0 diff --git a/cmd/gubiq/usage.go b/cmd/gubiq/usage.go index c4aaa8bcf9..4b1d5f746e 100644 --- a/cmd/gubiq/usage.go +++ b/cmd/gubiq/usage.go @@ -67,7 +67,6 @@ var AppHelpFlagGroups = []flagGroup{ utils.DataDirFlag, utils.KeyStoreDirFlag, utils.NetworkIdFlag, - utils.OlympicFlag, utils.TestNetFlag, utils.DevModeFlag, utils.IdentityFlag, diff --git a/cmd/bzzhash/main.go b/cmd/swarm/hash.go similarity index 80% rename from cmd/bzzhash/main.go rename to cmd/swarm/hash.go index 8ebe059470..e1062300ab 100644 --- a/cmd/bzzhash/main.go +++ b/cmd/swarm/hash.go @@ -19,22 +19,21 @@ package main import ( "fmt" + "log" "os" - "runtime" "github.com/ubiq/go-ubiq/swarm/storage" + "gopkg.in/urfave/cli.v1" ) -func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) - - if len(os.Args) < 2 { - fmt.Println("Usage: bzzhash ") - os.Exit(0) +func hash(ctx *cli.Context) { + args := ctx.Args() + if len(args) < 1 { + log.Fatal("Usage: swarm hash ") } - f, err := os.Open(os.Args[1]) + f, err := os.Open(args[0]) if err != nil { - fmt.Println("Error opening file " + os.Args[1]) + fmt.Println("Error opening file " + args[1]) os.Exit(1) } @@ -42,7 +41,7 @@ func main() { chunker := storage.NewTreeChunker(storage.NewChunkerParams()) key, err := chunker.Split(f, stat.Size(), nil, nil, nil) if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) + log.Fatalf("%v\n", err) } else { fmt.Printf("%v\n", key) } diff --git a/cmd/bzzd/main.go b/cmd/swarm/main.go similarity index 68% rename from cmd/bzzd/main.go rename to cmd/swarm/main.go index e63dad373e..8041605057 100644 --- a/cmd/bzzd/main.go +++ b/cmd/swarm/main.go @@ -43,11 +43,15 @@ import ( "gopkg.in/urfave/cli.v1" ) -const clientIdentifier = "bzzd" +const ( + clientIdentifier = "swarm" + versionString = "0.2" +) var ( - gitCommit string // Git SHA1 commit hash of the release (set via linker flags) - app = utils.NewApp(gitCommit, "Ubiq Swarm server daemon") + gitCommit string // Git SHA1 commit hash of the release (set via linker flags) + app = utils.NewApp(gitCommit, "Ubiq Swarm") + testbetBootNodes = []string{} ) var ( @@ -65,30 +69,49 @@ var ( } SwarmNetworkIdFlag = cli.IntFlag{ Name: "bzznetworkid", - Usage: "Network identifier (integer, default 322=swarm testnet)", + Usage: "Network identifier (integer, default 3=swarm testnet)", Value: network.NetworkId, } SwarmConfigPathFlag = cli.StringFlag{ Name: "bzzconfig", Usage: "Swarm config file path (datadir/bzz)", } - SwarmSwapEnabled = cli.BoolFlag{ + SwarmSwapEnabledFlag = cli.BoolFlag{ Name: "swap", Usage: "Swarm SWAP enabled (default false)", } - SwarmSyncEnabled = cli.BoolTFlag{ + SwarmSyncEnabledFlag = cli.BoolTFlag{ Name: "sync", Usage: "Swarm Syncing enabled (default true)", } - EthAPI = cli.StringFlag{ + EthAPIFlag = cli.StringFlag{ Name: "ethapi", Usage: "URL of the Ethereum API provider", Value: node.DefaultIPCEndpoint("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() { // Override flag defaults so bzzd can run alongside gubiq. utils.ListenPortFlag.Value = 30399 @@ -96,8 +119,39 @@ func init() { utils.IPCApiFlag.Value = "admin, bzz, chequebook, debug, rpc, web3" // Set up the cli app. - app.Commands = nil app.Action = bzzd + app.HideVersion = true // we have a command to print the version + app.Copyright = "Copyright 2013-2016 The go-ethereum Authors" + app.Commands = []cli.Command{ + { + Action: version, + Name: "version", + Usage: "Print version numbers", + ArgsUsage: " ", + Description: ` +The output of this command is supposed to be machine-readable. +`, + }, + { + Action: upload, + Name: "up", + Usage: "upload a file or directory to swarm using the HTTP API", + ArgsUsage: " ", + 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: " ", + Description: ` +Prints the swarm hash of file or directory. +`, + }, + } + app.Flags = []cli.Flag{ utils.IdentityFlag, utils.DataDirFlag, @@ -115,14 +169,20 @@ func init() { utils.IPCApiFlag, utils.IPCPathFlag, // bzzd-specific flags - EthAPI, + CorsStringFlag, + EthAPIFlag, SwarmConfigPathFlag, - SwarmSwapEnabled, - SwarmSyncEnabled, + SwarmSwapEnabledFlag, + SwarmSyncEnabledFlag, SwarmPortFlag, SwarmAccountFlag, SwarmNetworkIdFlag, ChequebookAddrFlag, + // upload flags + SwarmApiFlag, + SwarmRecursiveUploadFlag, + SwarmWantManifestFlag, + SwarmUploadDefaultPath, } app.Flags = append(app.Flags, debug.Flags...) app.Before = func(ctx *cli.Context) error { @@ -142,17 +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 { stack := utils.MakeNode(ctx, clientIdentifier, gitCommit) registerBzzService(ctx, stack) utils.StartNode(stack) - + networkId := ctx.GlobalUint64(SwarmNetworkIdFlag.Name) // Add bootnodes as initial peers. if ctx.GlobalIsSet(utils.BootnodesFlag.Name) { bootnodes := strings.Split(ctx.GlobalString(utils.BootnodesFlag.Name), ",") injectBootnodes(stack.Server(), bootnodes) } else { - injectBootnodes(stack.Server(), defaultBootnodes) + if networkId == 3 { + injectBootnodes(stack.Server(), testbetBootNodes) + } } stack.Wait() @@ -175,22 +251,21 @@ func registerBzzService(ctx *cli.Context, stack *node.Node) { if len(bzzport) > 0 { bzzconfig.Port = bzzport } - swapEnabled := ctx.GlobalBool(SwarmSwapEnabled.Name) - syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabled.Name) + swapEnabled := ctx.GlobalBool(SwarmSwapEnabledFlag.Name) + syncEnabled := ctx.GlobalBoolT(SwarmSyncEnabledFlag.Name) - ethapi := ctx.GlobalString(EthAPI.Name) + ethapi := ctx.GlobalString(EthAPIFlag.Name) + cors := ctx.GlobalString(CorsStringFlag.Name) boot := func(ctx *node.ServiceContext) (node.Service, error) { var client *ethclient.Client - if ethapi == "" { - err = fmt.Errorf("use ethapi flag to connect to a an eth client and talk to the blockchain") - } else { + if len(ethapi) > 0 { client, err = ethclient.Dial(ethapi) + if err != nil { + utils.Fatalf("Can't connect: %v", err) + } } - if err != nil { - utils.Fatalf("Can't connect: %v", err) - } - return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled) + return swarm.NewSwarm(ctx, client, bzzconfig, swapEnabled, syncEnabled, cors) } if err := stack.Register(boot); err != nil { utils.Fatalf("Failed to register the Swarm service: %v", err) diff --git a/cmd/swarm/upload.go b/cmd/swarm/upload.go new file mode 100644 index 0000000000..d8039d45b5 --- /dev/null +++ b/cmd/swarm/upload.go @@ -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 . + +// 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 +} diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 8c4a9ec4ec..6e138e7d8a 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -18,12 +18,14 @@ package utils import ( + "compress/gzip" "fmt" "io" "os" "os/signal" "regexp" "runtime" + "strings" "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core" @@ -65,7 +67,6 @@ func Fatalf(format string, args ...interface{}) { } } fmt.Fprintf(w, "Fatal: "+format+"\n", args...) - logger.Flush() os.Exit(1) } @@ -93,7 +94,7 @@ func StartNode(stack *node.Node) { func FormatTransactionData(data string) []byte { d := common.StringToByteFunc(data, func(s string) (ret []byte) { - slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000) + slice := regexp.MustCompile(`\n|\s`).Split(s, 1000000000) for _, dataItem := range slice { d := common.FormatData(dataItem) ret = append(ret, d...) @@ -133,7 +134,15 @@ func ImportChain(chain *core.BlockChain, fn string) error { return err } defer fh.Close() - stream := rlp.NewStream(fh, 0) + + var reader io.Reader = fh + if strings.HasSuffix(fn, ".gz") { + if reader, err = gzip.NewReader(reader); err != nil { + return err + } + } + + stream := rlp.NewStream(reader, 0) // Run actual the import. blocks := make(types.Blocks, importBatchSize) @@ -195,10 +204,18 @@ func ExportChain(blockchain *core.BlockChain, fn string) error { return err } defer fh.Close() - if err := blockchain.Export(fh); err != nil { + + var writer io.Writer = fh + if strings.HasSuffix(fn, ".gz") { + writer = gzip.NewWriter(writer) + defer writer.(*gzip.Writer).Close() + } + + if err := blockchain.Export(writer); err != nil { return err } glog.Infoln("Exported blockchain to ", fn) + return nil } @@ -210,7 +227,14 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las return err } defer fh.Close() - if err := blockchain.ExportN(fh, first, last); err != nil { + + var writer io.Writer = fh + if strings.HasSuffix(fn, ".gz") { + writer = gzip.NewWriter(writer) + defer writer.(*gzip.Writer).Close() + } + + if err := blockchain.ExportN(writer, first, last); err != nil { return err } glog.Infoln("Exported blockchain to ", fn) diff --git a/cmd/utils/customflags.go b/cmd/utils/customflags.go index 1c3ebc81ae..39a47031f5 100644 --- a/cmd/utils/customflags.go +++ b/cmd/utils/customflags.go @@ -23,8 +23,6 @@ import ( "os/user" "path" "strings" - - "gopkg.in/urfave/cli.v1" ) // Custom type which is registered in the flags library which cli uses for @@ -46,7 +44,6 @@ func (self *DirectoryString) Set(value string) error { // Custom cli.Flag type which expand the received string to an absolute path. // e.g. ~/.ubiq -> /home/username/.ubiq type DirectoryFlag struct { - cli.GenericFlag Name string Value DirectoryString Usage string @@ -54,15 +51,10 @@ type DirectoryFlag struct { } func (self DirectoryFlag) String() string { - var fmtString string - fmtString = "%s %v\t%v" - + fmtString := "%s %v\t%v" if len(self.Value.Value) > 0 { fmtString = "%s \"%v\"\t%v" - } else { - fmtString = "%s %v\t%v" } - return withEnvHint(self.EnvVar, fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage)) } @@ -122,7 +114,7 @@ func withEnvHint(envVar, str string) string { return str + envText } -func (self DirectoryFlag) getName() string { +func (self DirectoryFlag) GetName() string { return self.Name } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 86c699de62..d3fc0fc88e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -21,7 +21,6 @@ import ( "crypto/ecdsa" "fmt" "io/ioutil" - "math" "math/big" "os" "path/filepath" @@ -116,13 +115,9 @@ var ( } NetworkIdFlag = cli.IntFlag{ Name: "networkid", - Usage: "Network identifier (integer, 0=Olympic (disused), 1=Frontier, 2=Morden (disused), 3=Ropsten)", + Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)", Value: eth.NetworkId, } - OlympicFlag = cli.BoolFlag{ - Name: "olympic", - Usage: "Olympic network: pre-configured pre-release test network", - } TestNetFlag = cli.BoolFlag{ Name: "testnet", Usage: "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 // flags, reverting to pre-configured ones if none have been specified. func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node { - // Return pre-configured nodes if none were manually requested - if !ctx.GlobalIsSet(BootnodesFlag.Name) { - if ctx.GlobalBool(TestNetFlag.Name) { - return params.TestnetBootnodes - } - return params.MainnetBootnodes + urls := params.MainnetBootnodes + if ctx.GlobalIsSet(BootnodesFlag.Name) { + urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") + } else if ctx.GlobalBool(TestNetFlag.Name) { + urls = params.TestnetBootnodes } - // Otherwise parse and use the CLI bootstrap nodes - bootnodes := []*discover.Node{} - for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") { + bootnodes := make([]*discover.Node, 0, len(urls)) + for _, url := range urls { node, err := discover.ParseNode(url) if err != nil { glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err) @@ -509,14 +502,13 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node { // MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line // flags, reverting to pre-configured ones if none have been specified. func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node { - // Return pre-configured nodes if none were manually requested - if !ctx.GlobalIsSet(BootnodesFlag.Name) { - return params.DiscoveryV5Bootnodes + urls := params.DiscoveryV5Bootnodes + if ctx.GlobalIsSet(BootnodesFlag.Name) { + urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") } - // Otherwise parse and use the CLI bootstrap nodes - bootnodes := []*discv5.Node{} - for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") { + bootnodes := make([]*discv5.Node, 0, len(urls)) + for _, url := range urls { node, err := discv5.ParseNode(url) if err != nil { glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err) @@ -715,7 +707,7 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node { // given node. func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) { // Avoid conflicting network flags - networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag} + networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag} for _, flag := range netFlags { if ctx.GlobalBool(flag.Name) { networks++ @@ -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 switch { - case ctx.GlobalBool(OlympicFlag.Name): - if !ctx.GlobalIsSet(NetworkIdFlag.Name) { - ethConf.NetworkId = 88 - } - ethConf.Genesis = core.OlympicGenesisBlock() - case ctx.GlobalBool(TestNetFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { ethConf.NetworkId = 3 @@ -766,7 +752,7 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) { ethConf.Genesis = core.DefaultTestnetGenesisBlock() case ctx.GlobalBool(DevModeFlag.Name): - ethConf.Genesis = core.OlympicGenesisBlock() + ethConf.Genesis = core.DevGenesisBlock() if !ctx.GlobalIsSet(GasPriceFlag.Name) { ethConf.GasPrice = new(big.Int) } @@ -823,16 +809,6 @@ func RegisterEthStatsService(stack *node.Node, url string) { // SetupNetwork configures the system for either the main net or some test network. func SetupNetwork(ctx *cli.Context) { - switch { - case ctx.GlobalBool(OlympicFlag.Name): - params.DurationLimit = big.NewInt(8) - params.GenesisGasLimit = big.NewInt(3141592) - params.MinGasLimit = big.NewInt(125000) - params.MaximumExtraDataSize = big.NewInt(1024) - NetworkIdFlag.Value = 0 - core.BlockReward = big.NewInt(1.5e+18) - core.ExpDiffPeriod = big.NewInt(math.MaxInt64) - } params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name)) } @@ -920,12 +896,13 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai var err error chainDb = MakeChainDatabase(ctx, stack) - if ctx.GlobalBool(OlympicFlag.Name) { + if ctx.GlobalBool(TestNetFlag.Name) { _, err := core.WriteTestNetGenesisBlock(chainDb) if err != nil { glog.Fatalln(err) } } + chainConfig := MakeChainConfigFromDb(ctx, chainDb) pow := pow.PoW(core.FakePow{}) diff --git a/common/big_test.go b/common/big_test.go index 1eb0c0c1fd..4d04a8db36 100644 --- a/common/big_test.go +++ b/common/big_test.go @@ -27,7 +27,7 @@ func TestMisc(t *testing.T) { c := []byte{1, 2, 3, 4} z := BitTest(a, 1) - if z != true { + if !z { t.Error("Expected true got", z) } @@ -79,11 +79,11 @@ func TestBigCopy(t *testing.T) { z := BigToBytes(c, 16) zbytes := []byte{232, 212, 165, 16, 0} - if bytes.Compare(y, ybytes) != 0 { + if !bytes.Equal(y, ybytes) { t.Error("Got", ybytes) } - if bytes.Compare(z, zbytes) != 0 { + if !bytes.Equal(z, zbytes) { t.Error("Got", zbytes) } } diff --git a/common/bytes.go b/common/bytes.go index b9fb3b2da6..cbceea8b5c 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -143,7 +143,7 @@ func Hex2BytesFixed(str string, flen int) []byte { return h } else { if len(h) > flen { - return h[len(h)-flen : len(h)] + return h[len(h)-flen:] } else { hh := make([]byte, flen) copy(hh[flen-len(h):flen], h[:]) diff --git a/common/bytes_test.go b/common/bytes_test.go index 2e52084777..98d402c489 100644 --- a/common/bytes_test.go +++ b/common/bytes_test.go @@ -181,7 +181,7 @@ func TestFromHex(t *testing.T) { input := "0x01" expected := []byte{1} result := FromHex(input) - if bytes.Compare(expected, result) != 0 { + if !bytes.Equal(expected, result) { t.Errorf("Expected % x got % x", expected, result) } } @@ -190,7 +190,7 @@ func TestFromHexOddLength(t *testing.T) { input := "0x1" expected := []byte{1} result := FromHex(input) - if bytes.Compare(expected, result) != 0 { + if !bytes.Equal(expected, result) { t.Errorf("Expected % x got % x", expected, result) } } diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index ca6cffce20..3442250503 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -22,9 +22,7 @@ import ( "encoding/json" "errors" "fmt" - "io" "io/ioutil" - "os" "os/exec" "regexp" "strings" @@ -34,7 +32,7 @@ import ( ) var ( - versionRegexp = regexp.MustCompile("[0-9]+\\.[0-9]+\\.[0-9]+") + versionRegexp = regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`) solcParams = []string{ "--combined-json", "bin,abi,userdoc,devdoc", "--add-std", // include standard lib contracts @@ -96,27 +94,16 @@ func CompileSolidityString(solc, source string) (map[string]*Contract, error) { if solc == "" { solc = "solc" } - // Write source to a temporary file. Compiling stdin used to be supported - // but seems to produce an exception with solc 0.3.5. - infile, err := ioutil.TempFile("", "gubiq-compile-solidity") - if err != nil { - return nil, err - } - defer os.Remove(infile.Name()) - if _, err := io.WriteString(infile, source); err != nil { - return nil, err - } - if err := infile.Close(); err != nil { - return nil, err - } - - return CompileSolidity(solc, infile.Name()) + args := append(solcParams, "--") + cmd := exec.Command(solc, append(args, "-")...) + cmd.Stdin = strings.NewReader(source) + return runsolc(cmd, source) } // CompileSolidity compiles all given Solidity source files. func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) { if len(sourcefiles) == 0 { - return nil, errors.New("solc: no source ") + return nil, errors.New("solc: no source files") } source, err := slurpFiles(sourcefiles) if err != nil { @@ -125,10 +112,13 @@ func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, if solc == "" { solc = "solc" } - - var stderr, stdout bytes.Buffer args := append(solcParams, "--") cmd := exec.Command(solc, append(args, sourcefiles...)...) + return runsolc(cmd, source) +} + +func runsolc(cmd *exec.Cmd, source string) (map[string]*Contract, error) { + var stderr, stdout bytes.Buffer cmd.Stderr = &stderr cmd.Stdout = &stdout if err := cmd.Run(); err != nil { diff --git a/common/compiler/solidity_test.go b/common/compiler/solidity_test.go index d4a8c3cf5a..ba124632f7 100644 --- a/common/compiler/solidity_test.go +++ b/common/compiler/solidity_test.go @@ -20,6 +20,7 @@ import ( "encoding/json" "io/ioutil" "os" + "os/exec" "path" "testing" @@ -27,8 +28,7 @@ import ( ) const ( - supportedSolcVersion = "0.3.5" - testSource = ` + testSource = ` contract test { /// @notice Will multiply ` + "`a`" + ` by 7. function multiply(uint a) returns(uint d) { @@ -36,23 +36,18 @@ contract test { } } ` - testCode = "0x6060604052602a8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b6007600435026060908152602090f3" testInfo = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}` ) -func skipUnsupported(t *testing.T) { - sol, err := SolidityVersion("") - if err != nil { +func skipWithoutSolc(t *testing.T) { + if _, err := exec.LookPath("solc"); err != nil { t.Skip(err) - return - } - if sol.Version != supportedSolcVersion { - t.Skipf("unsupported version of solc found (%v, expect %v)", sol.Version, supportedSolcVersion) } } func TestCompiler(t *testing.T) { - skipUnsupported(t) + skipWithoutSolc(t) + contracts, err := CompileSolidityString("", testSource) if err != nil { t.Fatalf("error compiling source. result %v: %v", contracts, err) @@ -64,19 +59,20 @@ func TestCompiler(t *testing.T) { if !ok { t.Fatal("info for contract 'test' not present in result") } - if c.Code != testCode { - t.Errorf("wrong code: expected\n%s, got\n%s", testCode, c.Code) + if c.Code == "" { + t.Error("empty code") } if c.Info.Source != testSource { t.Error("wrong source") } - if c.Info.CompilerVersion != supportedSolcVersion { - t.Errorf("wrong version: expected %q, got %q", supportedSolcVersion, c.Info.CompilerVersion) + if c.Info.CompilerVersion == "" { + t.Error("empty version") } } func TestCompileError(t *testing.T) { - skipUnsupported(t) + skipWithoutSolc(t) + contracts, err := CompileSolidityString("", testSource[4:]) if err == nil { t.Errorf("error expected compiling source. got none. result %v", contracts) diff --git a/common/format.go b/common/format.go index 119637d2e4..fccc299620 100644 --- a/common/format.go +++ b/common/format.go @@ -27,7 +27,7 @@ import ( // the unnecessary precision off from the formatted textual representation. type PrettyDuration time.Duration -var prettyDurationRe = regexp.MustCompile("\\.[0-9]+") +var prettyDurationRe = regexp.MustCompile(`\.[0-9]+`) // String implements the Stringer interface, allowing pretty printing of duration // values rounded to three decimals. diff --git a/common/hexutil/json.go b/common/hexutil/json.go index cbbadbed6a..c36d862b5e 100644 --- a/common/hexutil/json.go +++ b/common/hexutil/json.go @@ -237,7 +237,7 @@ func checkJSON(input []byte) (raw []byte, err error) { return nil, errNonString } if len(input) == 2 { - return nil, ErrEmptyString + return nil, nil // empty strings are allowed } if !bytesHave0xPrefix(input[1:]) { return nil, ErrMissingPrefix @@ -255,7 +255,7 @@ func checkNumberJSON(input []byte) (raw []byte, err error) { } input = input[1 : len(input)-1] if len(input) == 0 { - return nil, ErrEmptyString + return nil, nil // empty strings are allowed } if !bytesHave0xPrefix(input) { return nil, ErrMissingPrefix diff --git a/common/hexutil/json_test.go b/common/hexutil/json_test.go index 2d2e2fc0fd..290bf9ca24 100644 --- a/common/hexutil/json_test.go +++ b/common/hexutil/json_test.go @@ -60,13 +60,13 @@ var unmarshalBytesTests = []unmarshalTest{ {input: "", wantErr: errNonString}, {input: "null", wantErr: errNonString}, {input: "10", wantErr: errNonString}, - {input: `""`, wantErr: ErrEmptyString}, {input: `"0"`, wantErr: ErrMissingPrefix}, {input: `"0x0"`, wantErr: ErrOddLength}, {input: `"0xxx"`, wantErr: ErrSyntax}, {input: `"0x01zz01"`, wantErr: ErrSyntax}, // valid encoding + {input: `""`, want: referenceBytes("")}, {input: `"0x"`, want: referenceBytes("")}, {input: `"0x02"`, want: referenceBytes("02")}, {input: `"0X02"`, want: referenceBytes("02")}, @@ -125,7 +125,6 @@ var unmarshalBigTests = []unmarshalTest{ {input: "", wantErr: errNonString}, {input: "null", wantErr: errNonString}, {input: "10", wantErr: errNonString}, - {input: `""`, wantErr: ErrEmptyString}, {input: `"0"`, wantErr: ErrMissingPrefix}, {input: `"0x"`, wantErr: ErrEmptyNumber}, {input: `"0x01"`, wantErr: ErrLeadingZero}, @@ -133,6 +132,7 @@ var unmarshalBigTests = []unmarshalTest{ {input: `"0x1zz01"`, wantErr: ErrSyntax}, // valid encoding + {input: `""`, want: big.NewInt(0)}, {input: `"0x0"`, want: big.NewInt(0)}, {input: `"0x2"`, want: big.NewInt(0x2)}, {input: `"0x2F2"`, want: big.NewInt(0x2f2)}, @@ -198,7 +198,6 @@ var unmarshalUint64Tests = []unmarshalTest{ {input: "", wantErr: errNonString}, {input: "null", wantErr: errNonString}, {input: "10", wantErr: errNonString}, - {input: `""`, wantErr: ErrEmptyString}, {input: `"0"`, wantErr: ErrMissingPrefix}, {input: `"0x"`, wantErr: ErrEmptyNumber}, {input: `"0x01"`, wantErr: ErrLeadingZero}, @@ -207,6 +206,7 @@ var unmarshalUint64Tests = []unmarshalTest{ {input: `"0x1zz01"`, wantErr: ErrSyntax}, // valid encoding + {input: `""`, want: uint64(0)}, {input: `"0x0"`, want: uint64(0)}, {input: `"0x2"`, want: uint64(0x2)}, {input: `"0x2F2"`, want: uint64(0x2f2)}, diff --git a/common/math/dist_test.go b/common/math/dist_test.go index 826faea8b3..f5857b6f80 100644 --- a/common/math/dist_test.go +++ b/common/math/dist_test.go @@ -41,24 +41,24 @@ func TestSum(t *testing.T) { func TestDist(t *testing.T) { var vectors = []Vector{ - Vector{big.NewInt(1000), big.NewInt(1234)}, - Vector{big.NewInt(500), big.NewInt(10023)}, - Vector{big.NewInt(1034), big.NewInt(1987)}, - Vector{big.NewInt(1034), big.NewInt(1987)}, - Vector{big.NewInt(8983), big.NewInt(1977)}, - Vector{big.NewInt(98382), big.NewInt(1887)}, - Vector{big.NewInt(12398), big.NewInt(1287)}, - Vector{big.NewInt(12398), big.NewInt(1487)}, - Vector{big.NewInt(12398), big.NewInt(1987)}, - Vector{big.NewInt(12398), big.NewInt(128)}, - Vector{big.NewInt(12398), big.NewInt(1987)}, - Vector{big.NewInt(1398), big.NewInt(187)}, - Vector{big.NewInt(12328), big.NewInt(1927)}, - Vector{big.NewInt(12398), big.NewInt(1987)}, - Vector{big.NewInt(22398), big.NewInt(1287)}, - Vector{big.NewInt(1370), big.NewInt(1981)}, - Vector{big.NewInt(12398), big.NewInt(1957)}, - Vector{big.NewInt(42198), big.NewInt(1987)}, + {big.NewInt(1000), big.NewInt(1234)}, + {big.NewInt(500), big.NewInt(10023)}, + {big.NewInt(1034), big.NewInt(1987)}, + {big.NewInt(1034), big.NewInt(1987)}, + {big.NewInt(8983), big.NewInt(1977)}, + {big.NewInt(98382), big.NewInt(1887)}, + {big.NewInt(12398), big.NewInt(1287)}, + {big.NewInt(12398), big.NewInt(1487)}, + {big.NewInt(12398), big.NewInt(1987)}, + {big.NewInt(12398), big.NewInt(128)}, + {big.NewInt(12398), big.NewInt(1987)}, + {big.NewInt(1398), big.NewInt(187)}, + {big.NewInt(12328), big.NewInt(1927)}, + {big.NewInt(12398), big.NewInt(1987)}, + {big.NewInt(22398), big.NewInt(1287)}, + {big.NewInt(1370), big.NewInt(1981)}, + {big.NewInt(12398), big.NewInt(1957)}, + {big.NewInt(42198), big.NewInt(1987)}, } VectorsBy(GasSort).Sort(vectors) diff --git a/compression/rle/read_write.go b/compression/rle/read_write.go index 88ed7b05fc..b9bbe0a170 100644 --- a/compression/rle/read_write.go +++ b/compression/rle/read_write.go @@ -76,9 +76,9 @@ func compressChunk(dat []byte) (ret []byte, n int) { } return []byte{token, byte(j + 2)}, j case len(dat) >= 32: - if dat[0] == empty[0] && bytes.Compare(dat[:32], empty) == 0 { + if dat[0] == empty[0] && bytes.Equal(dat[:32], empty) { return []byte{token, emptyShaToken}, 32 - } else if dat[0] == emptyList[0] && bytes.Compare(dat[:32], emptyList) == 0 { + } else if dat[0] == emptyList[0] && bytes.Equal(dat[:32], emptyList) { return []byte{token, emptyListShaToken}, 32 } fallthrough diff --git a/console/bridge.go b/console/bridge.go index 0e3d67effe..64c8d27a66 100644 --- a/console/bridge.go +++ b/console/bridge.go @@ -46,7 +46,7 @@ func newBridge(client *rpc.Client, prompter UserPrompter, printer io.Writer) *br } // NewAccount is a wrapper around the personal.newAccount RPC method that uses a -// non-echoing password prompt to aquire the passphrase and executes the original +// non-echoing password prompt to acquire the passphrase and executes the original // RPC method (saved in jeth.newAccount) with it to actually execute the RPC call. func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) { var ( @@ -75,7 +75,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) { default: throwJSException("expected 0 or 1 string argument") } - // Password aquired, execute the call and return + // Password acquired, execute the call and return ret, err := call.Otto.Call("jeth.newAccount", nil, password) if err != nil { throwJSException(err.Error()) @@ -84,7 +84,7 @@ func (b *bridge) NewAccount(call otto.FunctionCall) (response otto.Value) { } // UnlockAccount is a wrapper around the personal.unlockAccount RPC method that -// uses a non-echoing password prompt to aquire the passphrase and executes the +// uses a non-echoing password prompt to acquire the passphrase and executes the // original RPC method (saved in jeth.unlockAccount) with it to actually execute // the RPC call. func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) { @@ -127,7 +127,7 @@ func (b *bridge) UnlockAccount(call otto.FunctionCall) (response otto.Value) { } // Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password -// prompt to aquire the passphrase and executes the original RPC method (saved in +// prompt to acquire the passphrase and executes the original RPC method (saved in // jeth.sign) with it to actually execute the RPC call. func (b *bridge) Sign(call otto.FunctionCall) (response otto.Value) { var ( @@ -270,18 +270,15 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) { } else { resultVal, err := JSON.Call("parse", string(result)) if err != nil { - resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object() + setError(resp, -32603, err.Error()) } else { resp.Set("result", resultVal) } } case rpc.Error: - resp.Set("error", map[string]interface{}{ - "code": err.ErrorCode(), - "message": err.Error(), - }) + setError(resp, err.ErrorCode(), err.Error()) default: - resp = newErrorResponse(call, -32603, err.Error(), &req.Id).Object() + setError(resp, -32603, err.Error()) } resps.Call("push", resp) } @@ -300,12 +297,8 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) { return response } -func newErrorResponse(call otto.FunctionCall, code int, msg string, id interface{}) otto.Value { - // Bundle the error into a JSON RPC call response - m := map[string]interface{}{"version": "2.0", "id": id, "error": map[string]interface{}{"code": code, msg: msg}} - res, _ := json.Marshal(m) - val, _ := call.Otto.Run("(" + string(res) + ")") - return val +func setError(resp *otto.Object, code int, msg string) { + resp.Set("error", map[string]interface{}{"code": code, "message": msg}) } // throwJSException panics on an otto.Value. The Otto VM will recover from the diff --git a/console/console.go b/console/console.go index 7b649a4bb3..0952f1d344 100644 --- a/console/console.go +++ b/console/console.go @@ -36,9 +36,9 @@ import ( ) var ( - passwordRegexp = regexp.MustCompile("personal.[nus]") - onlyWhitespace = regexp.MustCompile("^\\s*$") - exit = regexp.MustCompile("^\\s*exit\\s*;*\\s*$") + passwordRegexp = regexp.MustCompile(`personal.[nus]`) + onlyWhitespace = regexp.MustCompile(`^\s*$`) + exit = regexp.MustCompile(`^\s*exit\s*;*\s*$`) ) // HistoryFile is the file within the data directory to store input scrollback. @@ -226,8 +226,8 @@ func (c *Console) AutoCompleteInput(line string, pos int) (string, []string, str } // Chunck data to relevant part for autocompletion // E.g. in case of nested lines eth.getBalance(eth.coinb - start := 0 - for start = pos - 1; start > 0; start-- { + start := pos - 1 + for ; start > 0; start-- { // Skip all methods and namespaces (i.e. including te dot) if line[start] == '.' || (line[start] >= 'a' && line[start] <= 'z') || (line[start] >= 'A' && line[start] <= 'Z') { continue @@ -275,10 +275,7 @@ func (c *Console) Evaluate(statement string) error { fmt.Fprintf(c.printer, "[native] error: %v\n", r) } }() - if err := c.jsre.Evaluate(statement, c.printer); err != nil { - return err - } - return nil + return c.jsre.Evaluate(statement, c.printer) } // Interactive starts an interactive user session, where input is propted from diff --git a/console/prompter.go b/console/prompter.go index 5946d9ece3..6acbfb0e25 100644 --- a/console/prompter.go +++ b/console/prompter.go @@ -44,7 +44,7 @@ type UserPrompter interface { PromptConfirm(prompt string) (bool, error) // SetHistory sets the the input scrollback history that the prompter will allow - // the user to scoll back to. + // the user to scroll back to. SetHistory(history []string) // AppendHistory appends an entry to the scrollback history. It should be called @@ -147,7 +147,7 @@ func (p *terminalPrompter) PromptConfirm(prompt string) (bool, error) { } // SetHistory sets the the input scrollback history that the prompter will allow -// the user to scoll back to. +// the user to scroll back to. func (p *terminalPrompter) SetHistory(history []string) { p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n"))) } diff --git a/contracts/chequebook/cheque.go b/contracts/chequebook/cheque.go index 08dbbdd71e..42ec391ca0 100644 --- a/contracts/chequebook/cheque.go +++ b/contracts/chequebook/cheque.go @@ -252,7 +252,7 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch * return nil, fmt.Errorf("amount must be greater than zero (%v)", amount) } if self.balance.Cmp(amount) < 0 { - err = fmt.Errorf("insufficent funds to issue cheque for amount: %v. balance: %v", amount, self.balance) + err = fmt.Errorf("insufficient funds to issue cheque for amount: %v. balance: %v", amount, self.balance) } else { var sig []byte sent, found := self.sent[beneficiary] @@ -277,7 +277,7 @@ func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch * } // auto deposit if threshold is set and balance is less then threshold - // note this is called even if issueing cheque fails + // note this is called even if issuing cheque fails // so we reattempt depositing if self.threshold != nil { if self.balance.Cmp(self.threshold) < 0 { diff --git a/contracts/chequebook/cheque_test.go b/contracts/chequebook/cheque_test.go index c87c3c7ce2..9185ce1ae3 100644 --- a/contracts/chequebook/cheque_test.go +++ b/contracts/chequebook/cheque_test.go @@ -73,8 +73,8 @@ func TestIssueAndReceive(t *testing.T) { } chbook.sent[addr1] = new(big.Int).SetUint64(42) amount := common.Big1 - ch, err := chbook.Issue(addr1, amount) - if err == nil { + + if _, err = chbook.Issue(addr1, amount); err == nil { t.Fatalf("expected insufficient funds error, got none") } @@ -83,7 +83,7 @@ func TestIssueAndReceive(t *testing.T) { t.Fatalf("expected: %v, got %v", "0", chbook.Balance()) } - ch, err = chbook.Issue(addr1, amount) + ch, err := chbook.Issue(addr1, amount) if err != nil { t.Fatalf("expected no error, got %v", err) } @@ -128,8 +128,8 @@ func TestCheckbookFile(t *testing.T) { t.Errorf("expected: %v, got %v", "0", chbook.Balance()) } - ch, err := chbook.Issue(addr1, common.Big1) - if err != nil { + var ch *Cheque + if ch, err = chbook.Issue(addr1, common.Big1); err != nil { t.Fatalf("expected no error, got %v", err) } if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 { @@ -155,7 +155,7 @@ func TestVerifyErrors(t *testing.T) { } path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json") - contr1, err := deploy(key1, common.Big2, backend) + contr1, _ := deploy(key1, common.Big2, backend) chbook1, err := NewChequebook(path1, contr1, key1, backend) if err != nil { t.Errorf("expected no error, got %v", err) @@ -223,7 +223,8 @@ func TestVerifyErrors(t *testing.T) { func TestDeposit(t *testing.T) { path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json") backend := newTestBackend() - contr0, err := deploy(key0, new(big.Int), backend) + contr0, _ := deploy(key0, new(big.Int), backend) + chbook, err := NewChequebook(path0, contr0, key0, backend) if err != nil { t.Errorf("expected no error, got %v", err) @@ -361,7 +362,8 @@ func TestDeposit(t *testing.T) { func TestCash(t *testing.T) { path := filepath.Join(os.TempDir(), "chequebook-test.json") backend := newTestBackend() - contr0, err := deploy(key0, common.Big2, backend) + contr0, _ := deploy(key0, common.Big2, backend) + chbook, err := NewChequebook(path, contr0, key0, backend) if err != nil { t.Errorf("expected no error, got %v", err) @@ -380,11 +382,12 @@ func TestCash(t *testing.T) { } // cashing latest cheque - _, err = chbox.Receive(ch) - if err != nil { + if _, err = chbox.Receive(ch); err != nil { t.Fatalf("expected no error, got %v", err) } - _, err = ch.Cash(chbook.session) + if _, err = ch.Cash(chbook.session); err != nil { + t.Fatal("Cash failed:", err) + } backend.Commit() chbook.balance = new(big.Int).Set(common.Big3) diff --git a/contracts/ens/ens_test.go b/contracts/ens/ens_test.go index be90688f16..167e60a730 100644 --- a/contracts/ens/ens_test.go +++ b/contracts/ens/ens_test.go @@ -29,7 +29,7 @@ import ( var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") name = "my name on ENS" - hash = crypto.Sha3Hash([]byte("my content")) + hash = crypto.Keccak256Hash([]byte("my content")) addr = crypto.PubkeyToAddress(key.PublicKey) ) diff --git a/contracts/release/contract.sol b/contracts/release/contract.sol index 70df41b55b..aaaa641390 100644 --- a/contracts/release/contract.sol +++ b/contracts/release/contract.sol @@ -78,7 +78,7 @@ contract ReleaseOracle { } // signers is an accessor method to retrieve all te signers (public accessor - // generates an indexed one, not a retreive-all version). + // generates an indexed one, not a retrieve-all version). function signers() constant returns(address[]) { return voters; } @@ -178,7 +178,7 @@ contract ReleaseOracle { voters[i] = voters[voters.length - 1]; voters.length--; - delete verProp; // Nuke any version proposal (no suprise releases!) + delete verProp; // Nuke any version proposal (no surprise releases!) break; } } diff --git a/core/bench_test.go b/core/bench_test.go index 7469f84651..deffec3e83 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) gas := IntrinsicGas(data, false, false) - tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(types.HomesteadSigner{}, benchRootKey) + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey) gen.AddTx(tx) } } @@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { nil, nil, ) - tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from]) + tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from]) gen.AddTx(tx) from = to } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 1481ee4a1a..b70aa79a7e 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -24,11 +24,9 @@ import ( "github.com/ubiq/go-ubiq/common" "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/ethdb" "github.com/ubiq/go-ubiq/event" "github.com/ubiq/go-ubiq/params" - "github.com/ubiq/go-ubiq/pow/ezp" ) func testChainConfig() *params.ChainConfig { @@ -49,20 +47,19 @@ func proc() (Validator, *BlockChain) { } func TestNumber(t *testing.T) { - pow := ezp.New() _, chain := proc() statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb) cfg := testChainConfig() header := makeHeader(cfg, chain.Genesis(), statedb) header.Number = big.NewInt(3) - err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false) + err := ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false) if err != BlockNumberErr { t.Errorf("expected block number error, got %q", err) } header = makeHeader(cfg, chain.Genesis(), statedb) - err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false) + err = ValidateHeader(cfg, FakePow{}, header, chain.Genesis().Header(), false, false) if err == BlockNumberErr { t.Errorf("didn't expect block number error") } @@ -77,7 +74,7 @@ func TestPutReceipt(t *testing.T) { hash[0] = 2 receipt := new(types.Receipt) - receipt.Logs = vm.Logs{&vm.Log{ + receipt.Logs = []*types.Log{{ Address: addr, Topics: []common.Hash{hash}, Data: []byte("hi"), diff --git a/core/blockchain.go b/core/blockchain.go index 49fae0bdbb..5db25be6cc 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -29,7 +29,9 @@ import ( "sync/atomic" "time" + "github.com/hashicorp/golang-lru" "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/types" "github.com/ubiq/go-ubiq/core/vm" @@ -43,13 +45,9 @@ import ( "github.com/ubiq/go-ubiq/pow" "github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/trie" - "github.com/hashicorp/golang-lru" ) var ( - chainlogger = logger.NewLogger("CHAIN") - jsonlogger = logger.NewJsonLogger() - blockInsertTimer = metrics.NewTimer("chain/inserts") 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 } // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain - for hash, _ := range BadHashes { + for hash := range BadHashes { if header := bc.GetHeaderByHash(hash); header != nil { // get the canonical block corresponding to the offending header's number headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64()) @@ -404,10 +402,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) { // Export writes the active chain to the given writer. func (self *BlockChain) Export(w io.Writer) error { - if err := self.ExportN(w, uint64(0), self.currentBlock.NumberU64()); err != nil { - return err - } - return nil + return self.ExportN(w, uint64(0), self.currentBlock.NumberU64()) } // ExportN writes a subset of the active chain to the given writer. @@ -634,7 +629,11 @@ func (self *BlockChain) procFutureBlocks() { } if len(blocks) > 0 { types.BlockBy(types.Number).Sort(blocks) - self.InsertChain(blocks) + + // Insert one by one as chain insertion needs contiguous ancestry between blocks + for i := range blocks { + self.InsertChain(blocks[i : i+1]) + } } } @@ -708,6 +707,18 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty // transaction and receipt data. // XXX should this be moved to the test? func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { + // Do a sanity check that the provided chain is actually ordered and linked + for i := 1; i < len(blockChain); i++ { + if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() { + // Chain broke ancestry, log a messge (programming error) and skip insertion + failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, blockChain[i-1].NumberU64(), + blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4]) + + glog.V(logger.Error).Info(failure.Error()) + return 0, failure + } + } + // Pre-checks passed, start the block body and receipt imports self.wg.Add(1) defer self.wg.Done() @@ -822,7 +833,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain if stats.ignored > 0 { ignored = fmt.Sprintf(" (%d ignored)", stats.ignored) } - glog.V(logger.Info).Infof("imported %d receipts in %9v. #%d [%x… / %x…]%s", stats.processed, common.PrettyDuration(time.Since(start)), last.Number(), first.Hash().Bytes()[:4], last.Hash().Bytes()[:4], ignored) + glog.V(logger.Info).Infof("imported %4d receipts in %9v. #%d [%x… / %x…]%s", stats.processed, common.PrettyDuration(time.Since(start)), last.Number(), first.Hash().Bytes()[:4], last.Hash().Bytes()[:4], ignored) return 0, nil } @@ -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 // it will return the index number of the failing block as well an error describing what went wrong (for possible errors see core/errors.go). func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { + // Do a sanity check that the provided chain is actually ordered and linked + for i := 1; i < len(chain); i++ { + if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() { + // Chain broke ancestry, log a messge (programming error) and skip insertion + failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", + i-1, chain[i-1].NumberU64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4]) + + glog.V(logger.Error).Info(failure.Error()) + return 0, failure + } + } + // Pre-checks passed, start the full block imports self.wg.Add(1) defer self.wg.Done() @@ -886,9 +909,9 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { // faster than direct delivery and requires much less mutex // acquiring. var ( - stats = insertStats{startTime: time.Now()} + stats = insertStats{startTime: mclock.Now()} events = make([]interface{}, 0, len(chain)) - coalescedLogs vm.Logs + coalescedLogs []*types.Log nonceChecked = make([]bool, len(chain)) ) @@ -949,10 +972,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { } self.reportBlock(block, nil, err) - return i, err } - // Create a new statedb using the parent block and report an // error if it fails. switch { @@ -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())) } blockInsertTimer.UpdateSince(bstart) - events = append(events, ChainSideEvent{block, logs}) + events = append(events, ChainSideEvent{block}) case SplitStatTy: events = append(events, ChainSplitEvent{block, logs}) @@ -1044,7 +1065,7 @@ type insertStats struct { queued, processed, ignored int usedGas uint64 lastIndex int - startTime time.Time + startTime mclock.AbsTime } // statsReportLimit is the time limit during import after which we always print @@ -1056,28 +1077,24 @@ const statsReportLimit = 8 * time.Second func (st *insertStats) report(chain []*types.Block, index int) { // Fetch the timings for the batch var ( - now = time.Now() - elapsed = now.Sub(st.startTime) + now = mclock.Now() + elapsed = time.Duration(now) - time.Duration(st.startTime) ) - if elapsed == 0 { // Yes Windows, I'm looking at you - elapsed = 1 - } // If we're at the last block of the batch or report period reached, log if index == len(chain)-1 || elapsed >= statsReportLimit { start, end := chain[st.lastIndex], chain[index] txcount := countTransactions(chain[st.lastIndex : index+1]) - extra := "" + var hashes, extra string if st.queued > 0 || st.ignored > 0 { extra = fmt.Sprintf(" (%d queued %d ignored)", st.queued, st.ignored) } - hashes := "" if st.processed > 1 { hashes = fmt.Sprintf("%x… / %x…", start.Hash().Bytes()[:4], end.Hash().Bytes()[:4]) } else { hashes = fmt.Sprintf("%x…", end.Hash().Bytes()[:4]) } - glog.Infof("imported %d blocks, %5d txs (%7.3f Mg) in %9v (%6.3f Mg/s). #%v [%s]%s", st.processed, txcount, float64(st.usedGas)/1000000, common.PrettyDuration(elapsed), float64(st.usedGas)*1000/float64(elapsed), end.Number(), hashes, extra) + glog.Infof("imported %4d blocks, %5d txs (%7.3f Mg) in %9v (%6.3f Mg/s). #%v [%s]%s", st.processed, txcount, float64(st.usedGas)/1000000, common.PrettyDuration(elapsed), float64(st.usedGas)*1000/float64(elapsed), end.Number(), hashes, extra) *st = insertStats{startTime: now, lastIndex: index} } @@ -1095,24 +1112,25 @@ func countTransactions(chain []*types.Block) (c int) { // event about them func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { var ( - newChain types.Blocks - oldChain types.Blocks - commonBlock *types.Block - oldStart = oldBlock - newStart = newBlock - deletedTxs types.Transactions - deletedLogs vm.Logs - deletedLogsByHash = make(map[common.Hash]vm.Logs) + newChain types.Blocks + oldChain types.Blocks + commonBlock *types.Block + oldStart = oldBlock + newStart = newBlock + deletedTxs types.Transactions + deletedLogs []*types.Log // collectLogs collects the logs that were generated during the // processing of the block that corresponds with the given hash. // These logs are later announced as deleted. collectLogs = func(h common.Hash) { - // Coalesce logs + // Coalesce logs and set 'Removed'. receipts := GetBlockReceipts(self.chainDb, h, self.hc.GetBlockNumber(h)) for _, receipt := range receipts { - deletedLogs = append(deletedLogs, receipt.Logs...) - - deletedLogsByHash[h] = receipt.Logs + for _, log := range receipt.Logs { + del := *log + del.Removed = true + deletedLogs = append(deletedLogs, &del) + } } } ) @@ -1206,7 +1224,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { if len(oldChain) > 0 { go func() { for _, block := range oldChain { - self.eventMux.Post(ChainSideEvent{Block: block, Logs: deletedLogsByHash[block.Hash()]}) + self.eventMux.Post(ChainSideEvent{Block: block}) } }() } @@ -1216,7 +1234,7 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // postChainEvents iterates over the events generated by a chain insertion and // posts them into the event mux. -func (self *BlockChain) postChainEvents(events []interface{}, logs vm.Logs) { +func (self *BlockChain) postChainEvents(events []interface{}, logs []*types.Log) { // post event logs for further processing self.eventMux.Post(logs) for _, event := range events { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index aad9c48597..828b2bdc8f 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -435,7 +435,7 @@ func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return n func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error { return nil } -func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { +func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) { return nil, nil, new(big.Int), nil } @@ -719,7 +719,7 @@ func TestFastVsFullChains(t *testing.T) { // If the block number is multiple of 3, send a few bonus transactions to the miner if i%3 == 2 { for j := 0; j < i%4+1; j++ { - tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key) if err != nil { panic(err) } @@ -883,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) { // Create two transactions shared between the chains: // - postponed: transaction included at a later block in the forked chain // - swapped: transaction included at the same block number in the forked chain - postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) - swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) + postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) + swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) // Create two transactions that will be dropped by the forked chain: // - pastDrop: transaction dropped retroactively from a past block @@ -900,13 +900,13 @@ func TestChainTxReorgs(t *testing.T) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) { switch i { case 0: - pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2) + pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork case 2: - freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2) + freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(swapped) // This transaction will be swapped out at the exact height @@ -925,18 +925,18 @@ func TestChainTxReorgs(t *testing.T) { chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) { switch i { case 0: - pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3) + pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) gen.AddTx(pastAdd) // This transaction needs to be injected during reorg case 2: gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain - freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3) + freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time case 3: - futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3) + futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) gen.AddTx(futureAdd) // This transaction will be added after a full reorg } }) @@ -995,7 +995,7 @@ func TestLogReorgs(t *testing.T) { subs := evmux.Subscribe(RemovedLogsEvent{}) chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) { if i == 1 { - tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(signer, key1) + tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code), signer, key1) if err != nil { t.Fatalf("failed to create tx: %v", err) } @@ -1035,7 +1035,7 @@ func TestReorgSideEvent(t *testing.T) { } replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) { - tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(signer, key1) + tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1) if i == 2 { gen.OffsetTime(-1) } @@ -1107,7 +1107,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {}) - for i, _ := range chain { + for i := range chain { go func(block *types.Block) { // try to retrieve a block by its canonical hash and see if the block data can be retrieved. for { @@ -1152,7 +1152,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) } ) switch i { @@ -1215,7 +1215,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) } ) switch i { @@ -1260,11 +1260,11 @@ func TestEIP161AccountRemoval(t *testing.T) { ) switch i { case 0: - tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) case 1: - tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) case 2: - tx, err = types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) } if err != nil { t.Fatal(err) diff --git a/core/chain_makers.go b/core/chain_makers.go index 63dbce3d3f..3cd32d7ae1 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -106,7 +106,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, _, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) + receipt, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) if err != nil { panic(err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index a124ebaa6b..0c194499f0 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -55,13 +55,13 @@ func ExampleGenerateChain() { switch i { case 0: // In block 1, addr1 sends addr2 some ether. - tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, key1) + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) gen.AddTx(tx) case 1: // In block 2, addr1 sends some more ether to addr2. // addr2 passes it on to addr3. - tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1) - tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2) + tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) + tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) gen.AddTx(tx1) gen.AddTx(tx2) case 2: diff --git a/core/database_util.go b/core/database_util.go index f779d9a72e..7ace490b59 100644 --- a/core/database_util.go +++ b/core/database_util.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "math/big" + "sync" "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core/types" @@ -63,6 +64,8 @@ var ( oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually] ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error + + mipmapBloomMu sync.Mutex // protect against race condition when updating mipmap blooms ) // encodeBlockNumber encodes a block number as big endian uint64 @@ -564,6 +567,9 @@ func mipmapKey(num, level uint64) []byte { // WriteMapmapBloom writes each address included in the receipts' logs to the // MIP bloom bin. func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts) error { + mipmapBloomMu.Lock() + defer mipmapBloomMu.Unlock() + batch := db.NewBatch() for _, level := range MIPMapLevels { key := mipmapKey(number, level) diff --git a/core/database_util_test.go b/core/database_util_test.go index 105ef86a8b..18f4ba4837 100644 --- a/core/database_util_test.go +++ b/core/database_util_test.go @@ -26,7 +26,6 @@ import ( "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/crypto" "github.com/ubiq/go-ubiq/crypto/sha3" "github.com/ubiq/go-ubiq/ethdb" @@ -393,9 +392,9 @@ func TestReceiptStorage(t *testing.T) { receipt1 := &types.Receipt{ PostState: []byte{0x01}, CumulativeGasUsed: big.NewInt(1), - Logs: vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte{0x11})}, - &vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, + Logs: []*types.Log{ + {Address: common.BytesToAddress([]byte{0x11})}, + {Address: common.BytesToAddress([]byte{0x01, 0x11})}, }, TxHash: common.BytesToHash([]byte{0x11, 0x11}), ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), @@ -404,9 +403,9 @@ func TestReceiptStorage(t *testing.T) { receipt2 := &types.Receipt{ PostState: []byte{0x02}, CumulativeGasUsed: big.NewInt(2), - Logs: vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte{0x22})}, - &vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})}, + Logs: []*types.Log{ + {Address: common.BytesToAddress([]byte{0x22})}, + {Address: common.BytesToAddress([]byte{0x02, 0x22})}, }, TxHash: common.BytesToHash([]byte{0x22, 0x22}), ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), @@ -431,7 +430,7 @@ func TestReceiptStorage(t *testing.T) { rlpHave, _ := rlp.EncodeToBytes(r) rlpWant, _ := rlp.EncodeToBytes(receipt) - if bytes.Compare(rlpHave, rlpWant) != 0 { + if !bytes.Equal(rlpHave, rlpWant) { t.Fatalf("receipt #%d [%x]: receipt mismatch: have %v, want %v", i, receipt.TxHash, r, receipt) } } @@ -452,9 +451,9 @@ func TestBlockReceiptStorage(t *testing.T) { receipt1 := &types.Receipt{ PostState: []byte{0x01}, CumulativeGasUsed: big.NewInt(1), - Logs: vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte{0x11})}, - &vm.Log{Address: common.BytesToAddress([]byte{0x01, 0x11})}, + Logs: []*types.Log{ + {Address: common.BytesToAddress([]byte{0x11})}, + {Address: common.BytesToAddress([]byte{0x01, 0x11})}, }, TxHash: common.BytesToHash([]byte{0x11, 0x11}), ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), @@ -463,9 +462,9 @@ func TestBlockReceiptStorage(t *testing.T) { receipt2 := &types.Receipt{ PostState: []byte{0x02}, CumulativeGasUsed: big.NewInt(2), - Logs: vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte{0x22})}, - &vm.Log{Address: common.BytesToAddress([]byte{0x02, 0x22})}, + Logs: []*types.Log{ + {Address: common.BytesToAddress([]byte{0x22})}, + {Address: common.BytesToAddress([]byte{0x02, 0x22})}, }, TxHash: common.BytesToHash([]byte{0x22, 0x22}), ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), @@ -489,7 +488,7 @@ func TestBlockReceiptStorage(t *testing.T) { rlpHave, _ := rlp.EncodeToBytes(rs[i]) rlpWant, _ := rlp.EncodeToBytes(receipts[i]) - if bytes.Compare(rlpHave, rlpWant) != 0 { + if !bytes.Equal(rlpHave, rlpWant) { t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i]) } } @@ -505,14 +504,14 @@ func TestMipmapBloom(t *testing.T) { db, _ := ethdb.NewMemDatabase() receipt1 := new(types.Receipt) - receipt1.Logs = vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte("test"))}, - &vm.Log{Address: common.BytesToAddress([]byte("address"))}, + receipt1.Logs = []*types.Log{ + {Address: common.BytesToAddress([]byte("test"))}, + {Address: common.BytesToAddress([]byte("address"))}, } receipt2 := new(types.Receipt) - receipt2.Logs = vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte("test"))}, - &vm.Log{Address: common.BytesToAddress([]byte("address1"))}, + receipt2.Logs = []*types.Log{ + {Address: common.BytesToAddress([]byte("test"))}, + {Address: common.BytesToAddress([]byte("address1"))}, } WriteMipmapBloom(db, 1, types.Receipts{receipt1}) @@ -528,14 +527,14 @@ func TestMipmapBloom(t *testing.T) { // reset db, _ = ethdb.NewMemDatabase() receipt := new(types.Receipt) - receipt.Logs = vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte("test"))}, + receipt.Logs = []*types.Log{ + {Address: common.BytesToAddress([]byte("test"))}, } WriteMipmapBloom(db, 999, types.Receipts{receipt1}) receipt = new(types.Receipt) - receipt.Logs = vm.Logs{ - &vm.Log{Address: common.BytesToAddress([]byte("test 1"))}, + receipt.Logs = []*types.Log{ + {Address: common.BytesToAddress([]byte("test 1"))}, } WriteMipmapBloom(db, 1000, types.Receipts{receipt}) @@ -568,17 +567,12 @@ func TestMipmapChain(t *testing.T) { switch i { case 1: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{ - &vm.Log{ - Address: addr, - Topics: []common.Hash{hash1}, - }, - } + receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 1000: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{&vm.Log{Address: addr2}} + receipt.Logs = []*types.Log{{Address: addr2}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} diff --git a/core/default_genesis.go b/core/default_genesis.go index ce6c4f04e9..7f3692829a 100644 --- a/core/default_genesis.go +++ b/core/default_genesis.go @@ -20,4 +20,9 @@ package core // 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==" +// 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=" + +// defaultDevnetGenesisBlockis a gzip compressed dump of a dev Ethereum network genesis block. +const defaultDevnetGenesisBlock = "QlpoOTFBWSZTWb66siUAAmldgEERWAR/8AAEP6eOakACGu6ULVwyRNGKeBCbUaAGIJUDJpT2lP1BQAAANqp6jTUxMIxGmAJgFVTAp4mjSaoAxAB4cLqQ6aBgTRPcAECErBIZ9PyZJw5IYvQPWlcXDXnhaC9buNtJaAFApAgwkUIRBmBY6EhTY8/6ZXse6lLD1Eh3sfas7VHnxse2LZeXpME9fADujvYB4Wr9cgQA+Wq0gRnrfVmgVwIiIrgfON+c4EhrApvQT2LjUh6y3x41XXOxriA89W52MDId9R7vasE3pfWWATQF7nAEAWRb861EU6M9SmBTET1UUGuBmgxzewhmUe4Rj4jSvgRFRTYgI8WzzcQn3nNr6x3GW94Yp1xG4kOoC/MxDhbF8uMahuMTmKyEep0SwLaxquoT3F9X0NxmouMWhxTAlxHQoN872vbYJS/Wrls2LuptmbKr4R6BJ/oJfPNpq+H362F5ZyhNQBxXep4ZOr94ylFM6UfOeUq37kFeGzXOle3LKItkvJ70OKqEqzujic72rnpZHym6b3xSONoWjYzRzIUbOKSUgdVtEhtvUg24asA2cy1zFzsfnj8CXe0Bdi7kinChIX11ZEo=" diff --git a/core/events.go b/core/events.go index 9ca414ecb3..8267f30456 100644 --- a/core/events.go +++ b/core/events.go @@ -21,7 +21,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core/types" - "github.com/ubiq/go-ubiq/core/vm" ) // TxPreEvent is posted when a transaction enters the transaction pool. @@ -32,7 +31,7 @@ type TxPostEvent struct{ Tx *types.Transaction } // PendingLogsEvent is posted pre mining and notifies of pending logs. type PendingLogsEvent struct { - Logs vm.Logs + Logs []*types.Log } // PendingStateEvent is posted pre mining and notifies of pending state changes. @@ -45,28 +44,27 @@ type NewMinedBlockEvent struct{ Block *types.Block } type RemovedTransactionEvent struct{ Txs types.Transactions } // RemovedLogEvent is posted when a reorg happens -type RemovedLogsEvent struct{ Logs vm.Logs } +type RemovedLogsEvent struct{ Logs []*types.Log } // ChainSplit is posted when a new head is detected type ChainSplitEvent struct { Block *types.Block - Logs vm.Logs + Logs []*types.Log } type ChainEvent struct { Block *types.Block Hash common.Hash - Logs vm.Logs + Logs []*types.Log } type ChainSideEvent struct { Block *types.Block - Logs vm.Logs } type PendingBlockEvent struct { Block *types.Block - Logs vm.Logs + Logs []*types.Log } type ChainUncleEvent struct { diff --git a/core/evm.go b/core/evm.go new file mode 100644 index 0000000000..e6868580c1 --- /dev/null +++ b/core/evm.go @@ -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 . + +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) +} diff --git a/core/execution.go b/core/execution.go deleted file mode 100644 index cbc9dfd196..0000000000 --- a/core/execution.go +++ /dev/null @@ -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 . - -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) -} diff --git a/core/genesis.go b/core/genesis.go index 3c21a919f4..29d1c74b09 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -172,18 +172,12 @@ func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) { return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock())) } -// WriteTestNetGenesisBlock assembles the Morden test network genesis block and +// WriteTestNetGenesisBlock assembles the test network genesis block and // writes it - along with all associated state - into a chain database. func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) { return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock())) } -// WriteOlympicGenesisBlock assembles the Olympic genesis block and writes it -// along with all associated state into a chain database. -func WriteOlympicGenesisBlock(db ethdb.Database) (*types.Block, error) { - return WriteGenesisBlock(db, strings.NewReader(OlympicGenesisBlock())) -} - // DefaultGenesisBlock assembles a JSON string representing the default Ethereum // genesis block. func DefaultGenesisBlock() string { @@ -198,6 +192,8 @@ func DefaultGenesisBlock() string { return string(blob) } +// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum +// test network genesis block. func DefaultTestnetGenesisBlock() string { reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock))) blob, err := ioutil.ReadAll(reader) @@ -207,26 +203,12 @@ func DefaultTestnetGenesisBlock() string { return string(blob) } -// OlympicGenesisBlock assembles a JSON string representing the Olympic genesis -// block. -func OlympicGenesisBlock() string { - return fmt.Sprintf(`{ - "nonce":"0x%x", - "gasLimit":"0x%x", - "difficulty":"0x%x", - "alloc": { - "0000000000000000000000000000000000000001": {"balance": "1"}, - "0000000000000000000000000000000000000002": {"balance": "1"}, - "0000000000000000000000000000000000000003": {"balance": "1"}, - "0000000000000000000000000000000000000004": {"balance": "1"}, - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"} - } - }`, types.EncodeNonce(42), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes()) +// DevGenesisBlock assembles a JSON string representing a local dev genesis block. +func DevGenesisBlock() string { + reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock))) + blob, err := ioutil.ReadAll(reader) + if err != nil { + panic(fmt.Sprintf("failed to load dev genesis: %v", err)) + } + return string(blob) } diff --git a/core/headerchain.go b/core/headerchain.go index 0c742780b8..2cc7bbce6a 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -225,6 +225,17 @@ type WhCallback func(*types.Header) error // of the header retrieval mechanisms already need to verfy nonces, as well as // because nonces can be verified sparsely, not needing to check each. func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, writeHeader WhCallback) (int, error) { + // Do a sanity check that the provided chain is actually ordered and linked + for i := 1; i < len(chain); i++ { + if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() { + // Chain broke ancestry, log a messge (programming error) and skip insertion + failure := fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", + i-1, chain[i-1].Number.Uint64(), chain[i-1].Hash().Bytes()[:4], i, chain[i].Number.Uint64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash.Bytes()[:4]) + + glog.V(logger.Error).Info(failure.Error()) + return 0, failure + } + } // Collect some import statistics to report on stats := struct{ processed, ignored int }{} start := time.Now() @@ -329,7 +340,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, checkFreq int, w if stats.ignored > 0 { ignored = fmt.Sprintf(" (%d ignored)", stats.ignored) } - glog.V(logger.Info).Infof("imported %d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4]) + glog.V(logger.Info).Infof("imported %4d headers%s in %9v. #%v [%x… / %x…]", stats.processed, ignored, common.PrettyDuration(time.Since(start)), last.Number, first.Hash().Bytes()[:4], last.Hash().Bytes()[:4]) return 0, nil } diff --git a/core/state/iterator.go b/core/state/iterator.go index 69c8fe750a..2a79858b7f 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -123,7 +123,7 @@ func (it *NodeIterator) step() error { if !it.dataIt.Next() { it.dataIt = nil } - if bytes.Compare(account.CodeHash, emptyCodeHash) != 0 { + if !bytes.Equal(account.CodeHash, emptyCodeHash) { it.codeHash = common.BytesToHash(account.CodeHash) it.code, err = it.state.db.Get(account.CodeHash) if err != nil { diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index aa09c3d4d8..30f7a826ea 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -41,7 +41,7 @@ func TestNodeIteratorCoverage(t *testing.T) { } } // Cross check the hashes and the database itself - for hash, _ := range hashes { + for hash := range hashes { if _, err := db.Get(hash.Bytes()); err != nil { t.Errorf("failed to retrieve reported node %x: %v", hash, err) } diff --git a/core/state/managed_state_test.go b/core/state/managed_state_test.go index 40eadfece2..c2e8c3e72e 100644 --- a/core/state/managed_state_test.go +++ b/core/state/managed_state_test.go @@ -52,7 +52,7 @@ func TestRemove(t *testing.T) { ms, account := create() nn := make([]bool, 10) - for i, _ := range nn { + for i := range nn { nn[i] = true } account.nonces = append(account.nonces, nn...) @@ -68,7 +68,7 @@ func TestReuse(t *testing.T) { ms, account := create() nn := make([]bool, 10) - for i, _ := range nn { + for i := range nn { nn[i] = true } account.nonces = append(account.nonces, nn...) @@ -84,16 +84,16 @@ func TestReuse(t *testing.T) { func TestRemoteNonceChange(t *testing.T) { ms, account := create() nn := make([]bool, 10) - for i, _ := range nn { + for i := range nn { nn[i] = true } account.nonces = append(account.nonces, nn...) - nonce := ms.NewNonce(addr) + ms.NewNonce(addr) ms.StateDB.stateObjects[addr].data.Nonce = 200 - nonce = ms.NewNonce(addr) + nonce := ms.NewNonce(addr) if nonce != 200 { - t.Error("expected nonce after remote update to be", 201, "got", nonce) + t.Error("expected nonce after remote update to be", 200, "got", nonce) } ms.NewNonce(addr) ms.NewNonce(addr) @@ -101,7 +101,7 @@ func TestRemoteNonceChange(t *testing.T) { ms.StateDB.stateObjects[addr].data.Nonce = 200 nonce = ms.NewNonce(addr) if nonce != 204 { - t.Error("expected nonce after remote update to be", 201, "got", nonce) + t.Error("expected nonce after remote update to be", 204, "got", nonce) } } diff --git a/core/state/state_object.go b/core/state/state_object.go index 3aab4740cc..9b5993008d 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -288,7 +288,7 @@ func (self *StateObject) setBalance(amount *big.Int) { } // Return the gas back to the origin. Used by the Virtual machine or Closures -func (c *StateObject) ReturnGas(gas, price *big.Int) {} +func (c *StateObject) ReturnGas(gas *big.Int) {} func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject { stateObject := newObject(db, self.address, self.data, onDirty) diff --git a/core/state/statedb.go b/core/state/statedb.go index 83b9138f4d..8828a78b58 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -23,7 +23,9 @@ import ( "sort" "sync" + lru "github.com/hashicorp/golang-lru" "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/crypto" "github.com/ubiq/go-ubiq/ethdb" @@ -31,7 +33,6 @@ import ( "github.com/ubiq/go-ubiq/logger/glog" "github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/trie" - lru "github.com/hashicorp/golang-lru" ) // Trie cache generation limit after which to evic trie nodes from memory. @@ -71,7 +72,7 @@ type StateDB struct { thash, bhash common.Hash txIndex int - logs map[common.Hash]vm.Logs + logs map[common.Hash][]*types.Log logSize uint // Journal of state modifications. This is the backbone of @@ -97,7 +98,7 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) { stateObjects: make(map[common.Address]*StateObject), stateObjectsDirty: make(map[common.Address]struct{}), refund: new(big.Int), - logs: make(map[common.Hash]vm.Logs), + logs: make(map[common.Hash][]*types.Log), }, nil } @@ -118,7 +119,7 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) { stateObjects: make(map[common.Address]*StateObject), stateObjectsDirty: make(map[common.Address]struct{}), refund: new(big.Int), - logs: make(map[common.Hash]vm.Logs), + logs: make(map[common.Hash][]*types.Log), }, nil } @@ -138,7 +139,7 @@ func (self *StateDB) Reset(root common.Hash) error { self.thash = common.Hash{} self.bhash = common.Hash{} self.txIndex = 0 - self.logs = make(map[common.Hash]vm.Logs) + self.logs = make(map[common.Hash][]*types.Log) self.logSize = 0 self.clearJournalAndRefund() @@ -175,7 +176,7 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { self.txIndex = ti } -func (self *StateDB) AddLog(log *vm.Log) { +func (self *StateDB) AddLog(log *types.Log) { self.journal = append(self.journal, addLogChange{txhash: self.thash}) log.TxHash = self.thash @@ -186,12 +187,12 @@ func (self *StateDB) AddLog(log *vm.Log) { self.logSize++ } -func (self *StateDB) GetLogs(hash common.Hash) vm.Logs { +func (self *StateDB) GetLogs(hash common.Hash) []*types.Log { return self.logs[hash] } -func (self *StateDB) Logs() vm.Logs { - var logs vm.Logs +func (self *StateDB) Logs() []*types.Log { + var logs []*types.Log for _, lgs := range self.logs { logs = append(logs, lgs...) } @@ -209,7 +210,7 @@ func (self *StateDB) Exist(addr common.Address) bool { return self.GetStateObject(addr) != nil } -// Empty returns whether the state object is either non-existant +// Empty returns whether the state object is either non-existent // or empty according to the EIP161 specification (balance = nonce = code = 0) func (self *StateDB) Empty(addr common.Address) bool { so := self.GetStateObject(addr) @@ -293,6 +294,7 @@ func (self *StateDB) HasSuicided(addr common.Address) bool { * SETTERS */ +// AddBalance adds amount to the account associated with addr func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { @@ -300,6 +302,14 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { } } +// SubBalance subtracts amount from the account associated with addr +func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) { + stateObject := self.GetOrNewStateObject(addr) + if stateObject != nil { + stateObject.SubBalance(amount) + } +} + func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) { stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { @@ -465,16 +475,16 @@ func (self *StateDB) Copy() *StateDB { stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)), stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), refund: new(big.Int).Set(self.refund), - logs: make(map[common.Hash]vm.Logs, len(self.logs)), + logs: make(map[common.Hash][]*types.Log, len(self.logs)), logSize: self.logSize, } // Copy the dirty states and logs - for addr, _ := range self.stateObjectsDirty { + for addr := range self.stateObjectsDirty { state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty) state.stateObjectsDirty[addr] = struct{}{} } for hash, logs := range self.logs { - state.logs[hash] = make(vm.Logs, len(logs)) + state.logs[hash] = make([]*types.Log, len(logs)) copy(state.logs[hash], logs) } return state @@ -520,7 +530,7 @@ func (self *StateDB) GetRefund() *big.Int { // It is called in between transactions to get the root hash that // goes into transaction receipts. func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { - for addr, _ := range s.stateObjectsDirty { + for addr := range s.stateObjectsDirty { stateObject := s.stateObjects[addr] if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) { s.deleteStateObject(stateObject) @@ -543,7 +553,7 @@ func (s *StateDB) DeleteSuicides() { // Reset refund so that any used-gas calculations can use this method. s.clearJournalAndRefund() - for addr, _ := range s.stateObjectsDirty { + for addr := range s.stateObjectsDirty { stateObject := s.stateObjects[addr] // If the object has been removed by a suicide diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 4053e8d5e5..e5532dc07c 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -29,7 +29,7 @@ import ( "testing/quick" "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" ) @@ -221,7 +221,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { fn: func(a testAction, s *StateDB) { data := make([]byte, 2) binary.BigEndian.PutUint16(data, uint16(a.args[0])) - s.AddLog(&vm.Log{Address: addr, Data: data}) + s.AddLog(&types.Log{Address: addr, Data: data}) }, args: make([]int64, 1), }, diff --git a/core/state/sync.go b/core/state/sync.go index 5da6f2b85f..d9a4d1a45f 100644 --- a/core/state/sync.go +++ b/core/state/sync.go @@ -21,7 +21,6 @@ import ( "math/big" "github.com/ubiq/go-ubiq/common" - "github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/trie" ) @@ -32,7 +31,7 @@ import ( type StateSync trie.TrieSync // NewStateSync create a new state trie download scheduler. -func NewStateSync(root common.Hash, database ethdb.Database) *StateSync { +func NewStateSync(root common.Hash, database trie.DatabaseReader) *StateSync { var syncer *trie.TrieSync callback := func(leaf []byte, parent common.Hash) error { @@ -62,8 +61,8 @@ func (s *StateSync) Missing(max int) []common.Hash { // Process injects a batch of retrieved trie nodes data, returning if something // was committed to the database and also the index of an entry if processing of // it failed. -func (s *StateSync) Process(list []trie.SyncResult) (bool, int, error) { - return (*trie.TrieSync)(s).Process(list) +func (s *StateSync) Process(list []trie.SyncResult, dbw trie.DatabaseWriter) (bool, int, error) { + return (*trie.TrieSync)(s).Process(list, dbw) } // Pending returns the number of state entries currently pending for download. diff --git a/core/state/sync_test.go b/core/state/sync_test.go index f2b8855a2d..8cc96c27c1 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -84,7 +84,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou if nonce := state.GetNonce(acc.address); nonce != acc.nonce { t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce) } - if code := state.GetCode(acc.address); bytes.Compare(code, acc.code) != 0 { + if code := state.GetCode(acc.address); !bytes.Equal(code, acc.code) { t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code) } } @@ -138,7 +138,7 @@ func testIterativeStateSync(t *testing.T, batch int) { } results[i] = trie.SyncResult{Hash: hash, Data: data} } - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } queue = append(queue[:0], sched.Missing(batch)...) @@ -168,7 +168,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { } results[i] = trie.SyncResult{Hash: hash, Data: data} } - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } queue = append(queue[len(results):], sched.Missing(0)...) @@ -198,7 +198,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) { for len(queue) > 0 { // Fetch all the queued nodes in a random order results := make([]trie.SyncResult, 0, len(queue)) - for hash, _ := range queue { + for hash := range queue { data, err := srcDb.Get(hash.Bytes()) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) @@ -206,7 +206,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) { results = append(results, trie.SyncResult{Hash: hash, Data: data}) } // Feed the retrieved results back and queue new tasks - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } queue = make(map[common.Hash]struct{}) @@ -235,7 +235,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { for len(queue) > 0 { // Sync only half of the scheduled nodes, even those in random order results := make([]trie.SyncResult, 0, len(queue)/2+1) - for hash, _ := range queue { + for hash := range queue { delete(queue, hash) data, err := srcDb.Get(hash.Bytes()) @@ -249,7 +249,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { } } // Feed the retrieved results back and queue new tasks - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } for _, hash := range sched.Missing(0) { @@ -283,7 +283,7 @@ func TestIncompleteStateSync(t *testing.T) { results[i] = trie.SyncResult{Hash: hash, Data: data} } // Process each of the state nodes - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } for _, result := range results { @@ -294,7 +294,7 @@ func TestIncompleteStateSync(t *testing.T) { // Skim through the accounts and make sure the root hash is not a code node codeHash := false for _, acc := range srcAccounts { - if bytes.Compare(root.Bytes(), crypto.Sha3(acc.code)) == 0 { + if root == crypto.Keccak256Hash(acc.code) { codeHash = true break } diff --git a/core/state_processor.go b/core/state_processor.go index 409a38d476..31a54b13cc 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -57,25 +57,25 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcess // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) { var ( receipts types.Receipts totalUsedGas = big.NewInt(0) err error header = block.Header() - allLogs vm.Logs + allLogs []*types.Log gp = new(GasPool).AddGas(block.GasLimit()) ) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { //fmt.Println("tx:", i) statedb.StartRecord(tx.Hash(), block.Hash(), i) - receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) + receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) if err != nil { return nil, nil, nil, err } receipts = append(receipts, receipt) - allLogs = append(allLogs, logs...) + allLogs = append(allLogs, receipt.Logs...) } AccumulateRewards(statedb, header, block.Uncles()) @@ -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 -// and uses the input parameters for its environment. -// -// ApplyTransactions returns the generated receipts and vm logs during the -// execution of the state transition phase. -func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) { +// and uses the input parameters for its environment. It returns the receipt +// for the transaction, gas used and an error if the transaction failed, +// indicating the block was invalid. +func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, *big.Int, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { - return nil, nil, nil, err + return nil, nil, err } - - _, gas, err := ApplyMessage(NewEnv(statedb, config, bc, msg, header, cfg), msg, gp) + // Create a new context to be used in the EVM environment + context := NewEVMContext(msg, header, bc) + // Create a new environment which holds all relevant information + // about the transaction and calling mechanisms. + vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) + // Apply the transaction to the current state (included in the env) + _, gas, err := ApplyMessage(vmenv, msg, gp) if err != nil { - return nil, nil, nil, err + return nil, nil, err } // Update the state with pending changes usedGas.Add(usedGas, gas) + // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx + // based on the eip phase, we're passing wether the root touch-delete accounts. receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) - if MessageCreatesContract(msg) { - receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce()) + // if the transaction created a contract, store the creation address in the receipt. + if msg.To() == nil { + receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) } - logs := statedb.GetLogs(tx.Hash()) - receipt.Logs = logs + // Set the receipt logs and create a bloom for filtering + receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) glog.V(logger.Debug).Infoln(receipt) - return receipt, logs, gas, err + return receipt, gas, err } // AccumulateRewards credits the coinbase of the given block with the diff --git a/core/state_transition.go b/core/state_transition.go index 6c7fa2a38c..5204aca203 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -55,9 +55,9 @@ type StateTransition struct { initialGas *big.Int value *big.Int data []byte - state vm.Database + state vm.StateDB - env vm.Environment + env *vm.EVM } // Message represents a message sent to a contract. @@ -106,7 +106,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { } // NewStateTransition initialises and returns a new state transition object. -func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTransition { +func NewStateTransition(env *vm.EVM, msg Message, gp *GasPool) *StateTransition { return &StateTransition{ gp: gp, env: env, @@ -116,7 +116,7 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran initialGas: new(big.Int), value: msg.Value(), data: msg.Data(), - state: env.Db(), + state: env.StateDB, } } @@ -127,7 +127,7 @@ func NewStateTransition(env vm.Environment, msg Message, gp *GasPool) *StateTran // the gas used (which includes gas refunds) and an error if it failed. An error always // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. -func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.Int, error) { +func ApplyMessage(env *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) { st := NewStateTransition(env, msg, gp) ret, _, gasUsed, err := st.TransitionDb() @@ -159,7 +159,7 @@ func (self *StateTransition) to() vm.Account { func (self *StateTransition) useGas(amount *big.Int) error { if self.gas.Cmp(amount) < 0 { - return vm.OutOfGasError + return vm.ErrOutOfGas } self.gas.Sub(self.gas, amount) @@ -217,47 +217,44 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b msg := self.msg sender := self.from() // err checked in preCheck - homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber()) + homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber) contractCreation := MessageCreatesContract(msg) // Pay intrinsic gas if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil { return nil, nil, nil, InvalidTxError(err) } - vmenv := self.env - //var addr common.Address + var ( + vmenv = self.env + // vm errors do not effect consensus and are therefor + // not assigned to err, except for insufficient balance + // error. + vmerr error + ) if contractCreation { - ret, _, err = vmenv.Create(sender, self.data, self.gas, self.gasPrice, self.value) - if homestead && err == vm.CodeStoreOutOfGasError { + ret, _, vmerr = vmenv.Create(sender, self.data, self.gas, self.value) + if homestead && err == vm.ErrCodeStoreOutOfGas { self.gas = Big0 } - - if err != nil { - ret = nil - glog.V(logger.Core).Infoln("VM create err:", err) - } } else { // Increment the nonce for the next transaction self.state.SetNonce(sender.Address(), self.state.GetNonce(sender.Address())+1) - ret, err = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.gasPrice, self.value) - if err != nil { - glog.V(logger.Core).Infoln("VM call err:", err) + ret, vmerr = vmenv.Call(sender, self.to().Address(), self.data, self.gas, self.value) + } + if vmerr != nil { + glog.V(logger.Core).Infoln("vm returned with error:", err) + // The only possible consensus-error would be if there wasn't + // sufficient balance to make the transfer happen. The first + // balance transfer may never fail. + if vmerr == vm.ErrInsufficientBalance { + return nil, nil, nil, InvalidTxError(vmerr) } } - if err != nil && IsValueTransferErr(err) { - return nil, nil, nil, InvalidTxError(err) - } - - // We aren't interested in errors here. Errors returned by the VM are non-consensus errors and therefor shouldn't bubble up - if err != nil { - err = nil - } - requiredGas = new(big.Int).Set(self.gasUsed()) self.refundGas() - self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice)) + self.state.AddBalance(self.env.Coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice)) return ret, requiredGas, self.gasUsed(), err } diff --git a/core/tx_list.go b/core/tx_list.go index 24b3e32132..88a2d3c176 100644 --- a/core/tx_list.go +++ b/core/tx_list.go @@ -110,7 +110,7 @@ func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transac // If transactions were removed, the heap and cache are ruined if len(removed) > 0 { *m.index = make([]uint64, 0, len(m.items)) - for nonce, _ := range m.items { + for nonce := range m.items { *m.index = append(*m.index, nonce) } heap.Init(m.index) @@ -216,7 +216,7 @@ func (m *txSortedMap) Flatten() types.Transactions { // txList is a "list" of transactions belonging to an account, sorted by account // nonce. The same type can be used both for storing contiguous transactions for // the executable/pending queue; and for storing gapped transactions for the non- -// executable/future queue, with minor behavoiral changes. +// executable/future queue, with minor behavioral changes. type txList struct { strict bool // Whether nonces are strictly continuous or not txs *txSortedMap // Heap indexed sorted hash map of the transactions diff --git a/core/tx_pool.go b/core/tx_pool.go index 666835528f..b6a40e3cff 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -37,15 +37,14 @@ import ( var ( // Transaction Pool Errors - ErrInvalidSender = errors.New("Invalid sender") - ErrNonce = errors.New("Nonce too low") - ErrCheap = errors.New("Gas price too low for acceptance") - ErrBalance = errors.New("Insufficient balance") - ErrNonExistentAccount = errors.New("Account does not exist or account balance too low") - ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value") - ErrIntrinsicGas = errors.New("Intrinsic gas too low") - ErrGasLimit = errors.New("Exceeds block gas limit") - ErrNegativeValue = errors.New("Negative value") + ErrInvalidSender = errors.New("Invalid sender") + ErrNonce = errors.New("Nonce too low") + ErrCheap = errors.New("Gas price too low for acceptance") + ErrBalance = errors.New("Insufficient balance") + ErrInsufficientFunds = errors.New("Insufficient funds for gas * price + value") + ErrIntrinsicGas = errors.New("Intrinsic gas too low") + ErrGasLimit = errors.New("Exceeds block gas limit") + ErrNegativeValue = errors.New("Negative value") ) var ( @@ -124,6 +123,8 @@ func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentState quit: make(chan struct{}), } + pool.resetState() + pool.wg.Add(2) go pool.eventLoop() go pool.expirationLoop() @@ -176,7 +177,7 @@ func (pool *TxPool) resetState() { // any transactions that have been included in the block or // have been invalidated because of another transaction (e.g. // higher gas price) - pool.demoteUnexecutables() + pool.demoteUnexecutables(currentState) // Update all accounts to the latest known pending nonce for addr, list := range pool.pending { @@ -185,7 +186,7 @@ func (pool *TxPool) resetState() { } // Check the queue and move transactions over to the pending if possible // or remove those that have become invalid - pool.promoteExecutables() + pool.promoteExecutables(currentState) } func (pool *TxPool) Stop() { @@ -237,21 +238,26 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common // Pending retrieves all currently processable transactions, groupped by origin // account and sorted by nonce. The returned transaction set is a copy and can be // freely modified by calling code. -func (pool *TxPool) Pending() map[common.Address]types.Transactions { +func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { pool.mu.Lock() defer pool.mu.Unlock() + state, err := pool.currentState() + if err != nil { + return nil, err + } + // check queue first - pool.promoteExecutables() + pool.promoteExecutables(state) // invalidate any txs - pool.demoteUnexecutables() + pool.demoteUnexecutables(state) pending := make(map[common.Address]types.Transactions) for addr, list := range pool.pending { pending[addr] = list.Flatten() } - return pending + return pending, nil } // SetLocal marks a transaction as local, skipping gas price @@ -280,13 +286,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { if err != nil { return ErrInvalidSender } - - // Make sure the account exist. Non existent accounts - // haven't got funds and well therefor never pass. - if !currentState.Exist(from) { - return ErrNonExistentAccount - } - // Last but not least check for nonce errors if currentState.GetNonce(from) > tx.Nonce() { return ErrNonce @@ -322,7 +321,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { // add validates a transaction and inserts it into the non-executable queue for // later pending promotion and execution. func (pool *TxPool) add(tx *types.Transaction) error { - // If the transaction is alreayd known, discard it + // If the transaction is already known, discard it hash := tx.Hash() if pool.all[hash] != nil { return fmt.Errorf("Known transaction: %x", hash[:4]) @@ -372,10 +371,6 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) { // // Note, this method assumes the pool lock is held! func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { - // Init delayed since tx pool could have been started before any state sync - if pool.pendingState == nil { - pool.resetState() - } // Try to insert the transaction into the pending queue if pool.pending[addr] == nil { pool.pending[addr] = newTxList(true) @@ -410,13 +405,19 @@ func (pool *TxPool) Add(tx *types.Transaction) error { if err := pool.add(tx); err != nil { return err } - pool.promoteExecutables() + + state, err := pool.currentState() + if err != nil { + return err + } + + pool.promoteExecutables(state) return nil } // AddBatch attempts to queue a batch of transactions. -func (pool *TxPool) AddBatch(txs []*types.Transaction) { +func (pool *TxPool) AddBatch(txs []*types.Transaction) error { pool.mu.Lock() defer pool.mu.Unlock() @@ -425,7 +426,15 @@ func (pool *TxPool) AddBatch(txs []*types.Transaction) { glog.V(logger.Debug).Infoln("tx error:", err) } } - pool.promoteExecutables() + + state, err := pool.currentState() + if err != nil { + return err + } + + pool.promoteExecutables(state) + + return nil } // Get returns a transaction if it is contained in the pool @@ -499,17 +508,7 @@ func (pool *TxPool) removeTx(hash common.Hash) { // promoteExecutables moves transactions that have become processable from the // future queue to the set of pending transactions. During this process, all // invalidated transactions (low nonce, low balance) are deleted. -func (pool *TxPool) promoteExecutables() { - // Init delayed since tx pool could have been started before any state sync - if pool.pendingState == nil { - pool.resetState() - } - // Retrieve the current state to allow nonce and balance checking - state, err := pool.currentState() - if err != nil { - glog.Errorf("Could not get current state: %v", err) - return - } +func (pool *TxPool) promoteExecutables(state *state.StateDB) { // Iterate over all accounts and promote any executable transactions queued := uint64(0) for addr, list := range pool.queue { @@ -610,7 +609,7 @@ func (pool *TxPool) promoteExecutables() { if queued > maxQueuedInTotal { // Sort all accounts with queued transactions by heartbeat addresses := make(addresssByHeartbeat, 0, len(pool.queue)) - for addr, _ := range pool.queue { + for addr := range pool.queue { addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]}) } sort.Sort(addresses) @@ -645,13 +644,7 @@ func (pool *TxPool) promoteExecutables() { // demoteUnexecutables removes invalid and processed transactions from the pools // executable/pending queue and any subsequent transactions that become unexecutable // are moved back into the future queue. -func (pool *TxPool) demoteUnexecutables() { - // Retrieve the current state to allow nonce and balance checking - state, err := pool.currentState() - if err != nil { - glog.V(logger.Info).Infoln("failed to get current state: %v", err) - return - } +func (pool *TxPool) demoteUnexecutables(state *state.StateDB) { // Iterate over all accounts and demote any non-executable transactions for addr, list := range pool.pending { nonce := state.GetNonce(addr) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 4d10b41941..d28d620bdf 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -32,7 +32,7 @@ import ( ) func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { - tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil), types.HomesteadSigner{}, key) return tx } @@ -51,14 +51,84 @@ func deriveSender(tx *types.Transaction) (common.Address, error) { return types.Sender(types.HomesteadSigner{}, tx) } +// This test simulates a scenario where a new block is imported during a +// state reset and tests whether the pending state is in sync with the +// block head event that initiated the resetState(). +func TestStateChangeDuringPoolReset(t *testing.T) { + var ( + db, _ = ethdb.NewMemDatabase() + key, _ = crypto.GenerateKey() + address = crypto.PubkeyToAddress(key.PublicKey) + mux = new(event.TypeMux) + statedb, _ = state.New(common.Hash{}, db) + trigger = false + ) + + // setup pool with 2 transaction in it + statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether)) + + tx0 := transaction(0, big.NewInt(100000), key) + tx1 := transaction(1, big.NewInt(100000), key) + + // stateFunc is used multiple times to reset the pending state. + // when simulate is true it will create a state that indicates + // that tx0 and tx1 are included in the chain. + stateFunc := func() (*state.StateDB, error) { + // delay "state change" by one. The tx pool fetches the + // state multiple times and by delaying it a bit we simulate + // a state change between those fetches. + stdb := statedb + if trigger { + statedb, _ = state.New(common.Hash{}, db) + // simulate that the new head block included tx0 and tx1 + statedb.SetNonce(address, 2) + statedb.SetBalance(address, new(big.Int).Mul(common.Big1, common.Ether)) + trigger = false + } + return stdb, nil + } + + gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) } + + txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc) + txpool.resetState() + + nonce := txpool.State().GetNonce(address) + if nonce != 0 { + t.Fatalf("Invalid nonce, want 0, got %d", nonce) + } + + txpool.AddBatch(types.Transactions{tx0, tx1}) + + nonce = txpool.State().GetNonce(address) + if nonce != 2 { + t.Fatalf("Invalid nonce, want 2, got %d", nonce) + } + + // trigger state change in the background + trigger = true + + txpool.resetState() + + pendingTx, err := txpool.Pending() + if err != nil { + t.Fatalf("Could not fetch pending transactions: %v", err) + } + + for addr, txs := range pendingTx { + t.Logf("%0x: %d\n", addr, len(txs)) + } + + nonce = txpool.State().GetNonce(address) + if nonce != 2 { + t.Fatalf("Invalid nonce, want 2, got %d", nonce) + } +} + func TestInvalidTransactions(t *testing.T) { pool, key := setupTxPool() tx := transaction(0, big.NewInt(100), key) - if err := pool.Add(tx); err != ErrNonExistentAccount { - t.Error("expected", ErrNonExistentAccount) - } - from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1)) @@ -97,9 +167,10 @@ func TestTransactionQueue(t *testing.T) { from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1000)) + pool.resetState() pool.enqueueTx(tx.Hash(), tx) - pool.promoteExecutables() + pool.promoteExecutables(currentState) if len(pool.pending) != 1 { t.Error("expected valid txs to be 1 is", len(pool.pending)) } @@ -108,7 +179,7 @@ func TestTransactionQueue(t *testing.T) { from, _ = deriveSender(tx) currentState.SetNonce(from, 2) pool.enqueueTx(tx.Hash(), tx) - pool.promoteExecutables() + pool.promoteExecutables(currentState) if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok { t.Error("expected transaction to be in tx pool") } @@ -124,11 +195,13 @@ func TestTransactionQueue(t *testing.T) { from, _ = deriveSender(tx1) currentState, _ = pool.currentState() currentState.AddBalance(from, big.NewInt(1000)) + pool.resetState() + pool.enqueueTx(tx1.Hash(), tx1) pool.enqueueTx(tx2.Hash(), tx2) pool.enqueueTx(tx3.Hash(), tx3) - pool.promoteExecutables() + pool.promoteExecutables(currentState) if len(pool.pending) != 1 { t.Error("expected tx pool to be 1, got", len(pool.pending)) @@ -165,7 +238,7 @@ func TestRemoveTx(t *testing.T) { func TestNegativeValue(t *testing.T) { pool, key := setupTxPool() - tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil), types.HomesteadSigner{}, key) from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1)) @@ -214,9 +287,9 @@ func TestTransactionDoubleNonce(t *testing.T) { resetState() signer := types.HomesteadSigner{} - tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, key) - tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(signer, key) - tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(signer, key) + tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil), signer, key) + tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil), signer, key) + tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil), signer, key) // Add the first two transaction, ensure higher priced stays only if err := pool.add(tx1); err != nil { @@ -225,7 +298,8 @@ func TestTransactionDoubleNonce(t *testing.T) { if err := pool.add(tx2); err != nil { t.Error("didn't expect error", err) } - pool.promoteExecutables() + state, _ := pool.currentState() + pool.promoteExecutables(state) if pool.pending[addr].Len() != 1 { t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) } @@ -236,7 +310,7 @@ func TestTransactionDoubleNonce(t *testing.T) { if err := pool.add(tx3); err != nil { t.Error("didn't expect error", err) } - pool.promoteExecutables() + pool.promoteExecutables(state) if pool.pending[addr].Len() != 1 { t.Error("expected 1 pending transactions, got", pool.pending[addr].Len()) } @@ -295,6 +369,7 @@ func TestRemovedTxEvent(t *testing.T) { from, _ := deriveSender(tx) currentState, _ := pool.currentState() currentState.AddBalance(from, big.NewInt(1000000000000)) + pool.resetState() pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) pool.eventMux.Post(ChainHeadEvent{nil}) if pool.pending[from].Len() != 1 { @@ -452,6 +527,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) { state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) + pool.resetState() // Keep queuing up transactions and make sure all above a limit are dropped for i := uint64(1); i <= maxQueuedPerAccount+5; i++ { @@ -564,6 +640,7 @@ func TestTransactionPendingLimiting(t *testing.T) { state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000000)) + pool.resetState() // Keep queuing up transactions and make sure all above a limit are dropped for i := uint64(0); i < maxQueuedPerAccount+5; i++ { @@ -733,7 +810,7 @@ func benchmarkPendingDemotion(b *testing.B, size int) { // Benchmark the speed of pool validation b.ResetTimer() for i := 0; i < b.N; i++ { - pool.demoteUnexecutables() + pool.demoteUnexecutables(state) } } @@ -757,7 +834,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) { // Benchmark the speed of pool validation b.ResetTimer() for i := 0; i < b.N; i++ { - pool.promoteExecutables() + pool.promoteExecutables(state) } } diff --git a/core/types.go b/core/types.go index a6efaefe99..bf9d27ddc7 100644 --- a/core/types.go +++ b/core/types.go @@ -58,5 +58,5 @@ type HeaderValidator interface { // of gas used in the process and return an error if any of the internal rules // failed. type Processor interface { - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) } diff --git a/core/types/block.go b/core/types/block.go index c185ebf14b..9ead628441 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -423,9 +423,9 @@ func CalcUncleHash(uncles []*Header) common.Hash { // WithMiningResult returns a new block with the data from b // where nonce and mix digest are set to the provided values. -func (b *Block) WithMiningResult(nonce uint64, mixDigest common.Hash) *Block { +func (b *Block) WithMiningResult(nonce BlockNonce, mixDigest common.Hash) *Block { cpy := *b.header - binary.BigEndian.PutUint64(cpy.Nonce[:], nonce) + cpy.Nonce = nonce cpy.MixDigest = mixDigest return &Block{ header: &cpy, diff --git a/core/types/block_test.go b/core/types/block_test.go index 1b5cbc4337..8aab6bb7e9 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -53,7 +53,7 @@ func TestBlockEncoding(t *testing.T) { tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil) - tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b")) + tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) fmt.Println(block.Transactions()[0].Hash()) fmt.Println(tx1.data) fmt.Println(tx1.Hash()) diff --git a/core/types/bloom9.go b/core/types/bloom9.go index 57fdefddd5..67f2d82a60 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -22,7 +22,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common/hexutil" - "github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/crypto" ) @@ -95,17 +94,11 @@ func CreateBloom(receipts Receipts) Bloom { return BytesToBloom(bin.Bytes()) } -func LogsBloom(logs vm.Logs) *big.Int { +func LogsBloom(logs []*Log) *big.Int { bin := new(big.Int) for _, log := range logs { - data := make([]common.Hash, len(log.Topics)) bin.Or(bin, bloom9(log.Address.Bytes())) - - for i, topic := range log.Topics { - data[i] = topic - } - - for _, b := range data { + for _, b := range log.Topics { bin.Or(bin, bloom9(b[:])) } } diff --git a/core/types/log.go b/core/types/log.go new file mode 100644 index 0000000000..c8e9b9c5c8 --- /dev/null +++ b/core/types/log.go @@ -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 . + +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 +} diff --git a/core/types/log_test.go b/core/types/log_test.go new file mode 100644 index 0000000000..97bb7a3831 --- /dev/null +++ b/core/types/log_test.go @@ -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 . + +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 +} diff --git a/core/types/receipt.go b/core/types/receipt.go index 67018d7c43..572c226547 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -25,7 +25,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common/hexutil" - "github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/rlp" ) @@ -40,7 +39,7 @@ type Receipt struct { PostState []byte CumulativeGasUsed *big.Int Bloom Bloom - Logs vm.Logs + Logs []*Log // Implementation fields (don't reorder!) TxHash common.Hash @@ -52,7 +51,7 @@ type jsonReceipt struct { PostState *common.Hash `json:"root"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"` Bloom *Bloom `json:"logsBloom"` - Logs *vm.Logs `json:"logs"` + Logs []*Log `json:"logs"` TxHash *common.Hash `json:"transactionHash"` ContractAddress *common.Address `json:"contractAddress"` GasUsed *hexutil.Big `json:"gasUsed"` @@ -76,7 +75,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error { PostState []byte CumulativeGasUsed *big.Int Bloom Bloom - Logs vm.Logs + Logs []*Log } if err := s.Decode(&receipt); err != nil { return err @@ -93,7 +92,7 @@ func (r *Receipt) MarshalJSON() ([]byte, error) { PostState: &root, CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed), Bloom: &r.Bloom, - Logs: &r.Logs, + Logs: r.Logs, TxHash: &r.TxHash, ContractAddress: &r.ContractAddress, GasUsed: (*hexutil.Big)(r.GasUsed), @@ -120,7 +119,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { PostState: (*dec.PostState)[:], CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed), Bloom: *dec.Bloom, - Logs: *dec.Logs, + Logs: dec.Logs, TxHash: *dec.TxHash, GasUsed: (*big.Int)(dec.GasUsed), } @@ -142,9 +141,9 @@ type ReceiptForStorage Receipt // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt // into an RLP stream. func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { - logs := make([]*vm.LogForStorage, len(r.Logs)) + logs := make([]*LogForStorage, len(r.Logs)) for i, log := range r.Logs { - logs[i] = (*vm.LogForStorage)(log) + logs[i] = (*LogForStorage)(log) } return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed}) } @@ -158,7 +157,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { Bloom Bloom TxHash common.Hash ContractAddress common.Address - Logs []*vm.LogForStorage + Logs []*LogForStorage GasUsed *big.Int } if err := s.Decode(&receipt); err != nil { @@ -166,9 +165,9 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { } // Assign the consensus fields r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom - r.Logs = make(vm.Logs, len(receipt.Logs)) + r.Logs = make([]*Log, len(receipt.Logs)) for i, log := range receipt.Logs { - r.Logs[i] = (*vm.Log)(log) + r.Logs[i] = (*Log)(log) } // Assign the implementation fields r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed diff --git a/core/types/transaction.go b/core/types/transaction.go index 8cfa00f335..7de98045d2 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -18,7 +18,6 @@ package types import ( "container/heap" - "crypto/ecdsa" "encoding/json" "errors" "fmt" @@ -199,9 +198,9 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { var V byte 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 { - 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) { return ErrInvalidSig @@ -272,51 +271,6 @@ func (tx *Transaction) Size() common.StorageSize { 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 requires a signer to derive the sender. @@ -338,14 +292,6 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) { 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. // This signature needs to be formatted as described in the yellow paper (v+27). func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) { diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 0429c8c306..0b4d2b9625 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -50,10 +50,10 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { return signer } -// SignECDSA signs the transaction using the given signer and private key -func SignECDSA(s Signer, tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) { +// SignTx signs the transaction using the given signer and private key +func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) { h := s.Hash(tx) - sig, err := crypto.SignEthereum(h[:], prv) + sig, err := crypto.Sign(h[:], prv) if err != nil { return nil, err } @@ -91,19 +91,13 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) { 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 { // Hash returns the rlp encoded hash for signatures Hash(tx *Transaction) common.Hash // PubilcKey returns the public key derived from the signature PublicKey(tx *Transaction) ([]byte, error) - // SignECDSA signs the transaction with the given and returns a copy of the tx - SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) - // WithSignature returns a copy of the transaction with the given signature + // WithSignature returns a copy of the transaction with the given signature. + // The signature must be encoded in [R || S || V] format where V is 0 or 1. WithSignature(tx *Transaction, sig []byte) (*Transaction, error) // Checks for equality on the signers Equal(Signer) bool @@ -129,10 +123,6 @@ func (s EIP155Signer) Equal(s2 Signer) bool { 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) { // if the transaction is not protected fall back to homestead signer if !tx.Protected() { @@ -143,17 +133,16 @@ func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) { 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) { return nil, ErrInvalidSig } - // encode the signature in uncompressed format R, S := tx.data.R.Bytes(), tx.data.S.Bytes() sig := make([]byte, 65) copy(sig[32-len(R):32], R) copy(sig[64-len(S):64], S) - sig[64] = V - 27 + sig[64] = V // recover the public key from the signature hash := s.Hash(tx) @@ -167,8 +156,8 @@ func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) { return pub, nil } -// WithSignature returns a new transaction with the given signature. -// This signature needs to be formatted as described in the yellow paper (v+27). +// WithSignature returns a new transaction with the given signature. This signature +// 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) { if len(sig) != 65 { 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.V = new(big.Int).SetBytes([]byte{sig[64]}) 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) } 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 // homestead rules. type HomesteadSigner struct{ FrontierSigner } @@ -217,8 +197,8 @@ func (s HomesteadSigner) Equal(s2 Signer) bool { return ok } -// WithSignature returns a new transaction with the given snature. -// This snature needs to be formatted as described in the yellow paper (v+27). +// WithSignature returns a new transaction with the given signature. This signature +// 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) { if len(sig) != 65 { 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.data.R = new(big.Int).SetBytes(sig[:32]) 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 } -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) { if tx.data.V.BitLen() > 8 { 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) { return nil, ErrInvalidSig } @@ -252,7 +223,7 @@ func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) { sig := make([]byte, 65) copy(sig[32-len(r):32], r) copy(sig[64-len(s):64], s) - sig[64] = V - 27 + sig[64] = V // recover the public key from the snature hash := hs.Hash(tx) @@ -273,8 +244,8 @@ func (s FrontierSigner) Equal(s2 Signer) bool { return ok } -// WithSignature returns a new transaction with the given snature. -// This snature needs to be formatted as described in the yellow paper (v+27). +// WithSignature returns a new transaction with the given signature. This signature +// 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) { if len(sig) != 65 { 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.data.R = new(big.Int).SetBytes(sig[:32]) 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 } -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. // It does not uniquely identify the transaction. func (fs FrontierSigner) Hash(tx *Transaction) common.Hash { @@ -313,7 +275,7 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) { 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) { return nil, ErrInvalidSig } @@ -322,7 +284,7 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) { sig := make([]byte, 65) copy(sig[32-len(r):32], r) copy(sig[64-len(s):64], s) - sig[64] = V - 27 + sig[64] = V // recover the public key from the snature hash := fs.Hash(tx) @@ -336,18 +298,6 @@ func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) { 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 func deriveChainId(v *big.Int) *big.Int { if v.BitLen() <= 64 { diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go index e53202ced8..fef1d67fb6 100644 --- a/core/types/transaction_signing_test.go +++ b/core/types/transaction_signing_test.go @@ -30,7 +30,7 @@ func TestEIP155Signing(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) 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 { t.Fatal(err) } @@ -49,7 +49,7 @@ func TestEIP155ChainId(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) 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 { 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, err = tx.SignECDSA(HomesteadSigner{}, key) + tx, err = SignTx(tx, HomesteadSigner{}, key) if err != nil { 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) var err error - tx, err = tx.SignECDSA(NewEIP155Signer(big.NewInt(1)), key) + tx, err = SignTx(tx, NewEIP155Signer(big.NewInt(1)), key) if err != nil { t.Fatal(err) } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 9e01c5c305..a481744754 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -47,7 +47,7 @@ var ( common.FromHex("5544"), ).WithSignature( HomesteadSigner{}, - common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"), + common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"), ) ) @@ -138,7 +138,7 @@ func TestTransactionPriceNonceSort(t *testing.T) { for start, key := range keys { addr := crypto.PubkeyToAddress(key.PublicKey) 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) } } diff --git a/core/vm/contract.go b/core/vm/contract.go index 771f7ce260..35b0e96df8 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -24,7 +24,7 @@ import ( // ContractRef is a reference to the contract's backing object type ContractRef interface { - ReturnGas(*big.Int, *big.Int) + ReturnGas(*big.Int) Address() common.Address Value() *big.Int SetCode(common.Hash, []byte) @@ -48,7 +48,7 @@ type Contract struct { CodeAddr *common.Address Input []byte - value, Gas, UsedGas, Price *big.Int + value, Gas, UsedGas *big.Int Args []byte @@ -56,7 +56,7 @@ type Contract struct { } // 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} 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 c.Gas = gas //new(big.Int).Set(gas) 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) return c @@ -114,7 +111,7 @@ func (c *Contract) Caller() common.Address { // caller. func (c *Contract) Finalise() { // 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 @@ -127,7 +124,7 @@ func (c *Contract) UseGas(gas *big.Int) (ok bool) { } // 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 c.Gas.Add(c.Gas, gas) c.UsedGas.Sub(c.UsedGas, gas) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 48c3234758..63c0d57cc9 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -26,84 +26,59 @@ import ( "github.com/ubiq/go-ubiq/params" ) -// PrecompiledAccount represents a native ethereum contract -type PrecompiledAccount struct { - Gas func(l int) *big.Int - fn func(in []byte) []byte -} - -// Call calls the native function -func (self PrecompiledAccount) Call(in []byte) []byte { - return self.fn(in) +// Precompiled contract is the basic interface for native Go contracts. The implementation +// requires a deterministic gas count based on the input size of the Run method of the +// contract. +type PrecompiledContract interface { + RequiredGas(inputSize int) *big.Int // RequiredPrice calculates the contract gas use + Run(input []byte) []byte // Run runs the precompiled contract } // 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 -// contracts defined by the ethereum yellow paper. -func PrecompiledContracts() map[string]*PrecompiledAccount { - return map[string]*PrecompiledAccount{ - // ECRECOVER - string(common.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int { - return params.EcrecoverGas - }, ecrecoverFunc}, +// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go +func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { + gas := p.RequiredGas(len(input)) + if contract.UseGas(gas) { + ret = p.Run(input) - // SHA256 - string(common.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int { - n := big.NewInt(int64(l+31) / 32) - 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}, + return ret, nil + } else { + return nil, ErrOutOfGas } } -func sha256Func(in []byte) []byte { - return crypto.Sha256(in) +// ECRECOVER implemented as a native contract +type ecrecover struct{} + +func (c *ecrecover) RequiredGas(inputSize int) *big.Int { + return params.EcrecoverGas } -func ripemd160Func(in []byte) []byte { - return common.LeftPadBytes(crypto.Ripemd160(in), 32) -} +func (c *ecrecover) Run(in []byte) []byte { + const ecRecoverInputLength = 128 -const ecRecoverInputLength = 128 - -func ecrecoverFunc(in []byte) []byte { - in = common.RightPadBytes(in, 128) + in = common.RightPadBytes(in, ecRecoverInputLength) // "in" is (hash, v, r, s), each 32 bytes // but for ecrecover we want (r, s, v) r := common.BytesToBig(in[64:96]) s := common.BytesToBig(in[96:128]) - // Treat V as a 256bit integer - vbig := common.Bytes2Big(in[32:64]) - v := byte(vbig.Uint64()) + v := in[63] - 27 // 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") return nil } - - // v needs to be at the end and normalized for libsecp256k1 - 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) + // v needs to be at the end for libsecp256k1 + pubKey, err := crypto.Ecrecover(in[:32], append(in[64:128], v)) // make sure the public key is a valid one if err != nil { 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) } -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 } diff --git a/core/vm/environment.go b/core/vm/environment.go index 7720a2adac..46050281bd 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -17,110 +17,312 @@ package vm import ( + "fmt" "math/big" + "sync/atomic" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/params" ) -// Environment is an EVM requirement and helper which allows access to outside -// information such as states. -type Environment interface { - // The current ruleset - ChainConfig() *params.ChainConfig - // The state database - Db() Database - // Creates a restorable snapshot - SnapshotDatabase() int - // Set database to previous snapshot - RevertToSnapshot(int) - // Address of the original invoker (first occurrence of the VM invoker) - Origin() common.Address - // The block number this VM is invoked on - BlockNumber() *big.Int - // The n'th hash ago from this block number - GetHash(uint64) common.Hash - // The handler's address - Coinbase() common.Address - // The current time (block time) - Time() *big.Int - // Difficulty set on the current block - Difficulty() *big.Int - // The gas limit of the block - GasLimit() *big.Int - // Determines whether it's possible to transact - CanTransfer(from common.Address, balance *big.Int) bool - // Transfers amount from one account to the other - 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) +type ( + CanTransferFunc func(StateDB, common.Address, *big.Int) bool + TransferFunc func(StateDB, common.Address, common.Address, *big.Int) + // GetHashFunc returns the nth block hash in the blockchain + // and is used by the BLOCKHASH EVM op code. + GetHashFunc func(uint64) common.Hash +) + +// Context provides the EVM with auxiliary information. Once provided it shouldn't be modified. +type Context struct { + // CanTransfer returns whether the account contains + // sufficient ether to transfer the value + CanTransfer CanTransferFunc + // Transfer transfers ether from one account to the other + Transfer TransferFunc + // GetHash returns the hash corresponding to n + GetHash GetHashFunc + + // Message information + Origin common.Address // Provides information for ORIGIN + GasPrice *big.Int // Provides information for GASPRICE + + // Block information + Coinbase common.Address // Provides information for COINBASE + GasLimit *big.Int // Provides information for GASLIMIT + BlockNumber *big.Int // Provides information for NUMBER + Time *big.Int // Provides information for TIME + Difficulty *big.Int // Provides information for DIFFICULTY } -// Vm is the basic interface for an implementation of the EVM. -type Vm interface { - // Run should execute the given contract with the input given in in - // and return the contract execution return bytes or an error if it - // failed. - Run(c *Contract, in []byte) ([]byte, error) +// EVM provides information about external sources for the EVM +// +// The EVM should never be reused and is not thread safe. +type EVM struct { + // Context provides auxiliary blockchain related information + 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. -type Database interface { - GetAccount(common.Address) Account - CreateAccount(common.Address) Account +// NewEVM retutrns a new EVM evmironment. +func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { + evm := &EVM{ + Context: ctx, + StateDB: statedb, + vmConfig: vmConfig, + chainConfig: chainConfig, + } - AddBalance(common.Address, *big.Int) - GetBalance(common.Address) *big.Int - - 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 + evm.interpreter = NewInterpreter(evm, vmConfig) + return evm } -// Account represents a contract or basic ethereum account. -type Account interface { - SubBalance(amount *big.Int) - AddBalance(amount *big.Int) - 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 +// Cancel cancels any running EVM operation. This may be called concurrently and it's safe to be +// called multiple times. +func (evm *EVM) Cancel() { + atomic.StoreInt32(&evm.abort, 1) } + +// Call executes the contract associated with the addr with the given input as parameters. It also handles any +// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in +// 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 } diff --git a/core/vm/errors.go b/core/vm/errors.go index 11e6f443e7..69c7d6a98c 100644 --- a/core/vm/errors.go +++ b/core/vm/errors.go @@ -16,14 +16,12 @@ package vm -import ( - "errors" - "fmt" +import "errors" - "github.com/ubiq/go-ubiq/params" +var ( + ErrOutOfGas = errors.New("out of gas") + ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas") + ErrDepth = errors.New("max call depth exceeded") + ErrTraceLimitReached = errors.New("the number of logs reached the specified limit") + ErrInsufficientBalance = errors.New("insufficient balance for transfer") ) - -var OutOfGasError = errors.New("Out of gas") -var CodeStoreOutOfGasError = errors.New("Contract creation code storage out of gas") -var DepthError = fmt.Errorf("Max call depth exceeded (%d)", params.CallCreateDepth) -var TraceLimitReachedError = errors.New("The number of logs reached the specified limit") diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go new file mode 100644 index 0000000000..ec491a9b5a --- /dev/null +++ b/core/vm/gas_table.go @@ -0,0 +1,246 @@ +package vm + +import ( + "math/big" + + "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/params" +) + +func memoryGasCost(mem *Memory, newMemSize *big.Int) *big.Int { + gas := new(big.Int) + if newMemSize.Cmp(common.Big0) > 0 { + newMemSizeWords := toWordSize(newMemSize) + + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { + // be careful reusing variables here when changing. + // The order has been optimised to reduce allocation + oldSize := toWordSize(big.NewInt(int64(mem.Len()))) + pow := new(big.Int).Exp(oldSize, common.Big2, Zero) + linCoef := oldSize.Mul(oldSize, params.MemoryGas) + quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv) + oldTotalFee := new(big.Int).Add(linCoef, quadCoef) + + pow.Exp(newMemSizeWords, common.Big2, Zero) + linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas) + quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv) + newTotalFee := linCoef.Add(linCoef, quadCoef) + + fee := newTotalFee.Sub(newTotalFee, oldTotalFee) + gas.Add(gas, fee) + } + } + return gas +} + +func constGasFunc(gas *big.Int) gasFunc { + return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gas + } +} + +func gasCalldataCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, GasFastestStep) + words := toWordSize(stack.Back(2)) + + return gas.Add(gas, words.Mul(words, params.CopyGas)) +} + +func gasSStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + var ( + y, x = stack.Back(1), stack.Back(0) + val = env.StateDB.GetState(contract.Address(), common.BigToHash(x)) + ) + // This checks for 3 scenario's and calculates gas accordingly + // 1. From a zero-value address to a non-zero value (NEW VALUE) + // 2. From a non-zero value address to a zero-value address (DELETE) + // 3. From a non-zero to a non-zero (CHANGE) + if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { + // 0 => non 0 + return new(big.Int).Set(params.SstoreSetGas) + } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { + env.StateDB.AddRefund(params.SstoreRefundGas) + + return new(big.Int).Set(params.SstoreClearGas) + } else { + // non 0 => non 0 (or 0 => 0) + return new(big.Int).Set(params.SstoreResetGas) + } +} + +func makeGasLog(n uint) gasFunc { + return func(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + mSize := stack.Back(1) + + gas := new(big.Int).Add(memoryGasCost(mem, memorySize), params.LogGas) + gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas)) + gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas)) + return gas + } +} + +func gasSha3(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, params.Sha3Gas) + words := toWordSize(stack.Back(1)) + return gas.Add(gas, words.Mul(words, params.Sha3WordGas)) +} + +func gasCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, GasFastestStep) + words := toWordSize(stack.Back(2)) + + return gas.Add(gas, words.Mul(words, params.CopyGas)) +} + +func gasExtCodeCopy(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := memoryGasCost(mem, memorySize) + gas.Add(gas, gt.ExtcodeCopy) + words := toWordSize(stack.Back(3)) + + return gas.Add(gas, words.Mul(words, params.CopyGas)) +} + +func gasMLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) +} + +func gasMStore8(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) +} + +func gasMStore(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(GasFastestStep, memoryGasCost(mem, memorySize)) +} + +func gasCreate(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return new(big.Int).Add(params.CreateGas, memoryGasCost(mem, memorySize)) +} + +func gasBalance(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gt.Balance +} + +func gasExtCodeSize(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gt.ExtcodeSize +} + +func gasSLoad(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return gt.SLoad +} + +func gasExp(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8) + gas := big.NewInt(expByteLen) + gas.Mul(gas, gt.ExpByte) + return gas.Add(gas, GasSlowStep) +} + +func gasCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int).Set(gt.Calls) + + transfersValue := stack.Back(2).BitLen() > 0 + var ( + address = common.BigToAddress(stack.Back(1)) + eip158 = env.ChainConfig().IsEIP158(env.BlockNumber) + ) + if eip158 { + if env.StateDB.Empty(address) && transfersValue { + gas.Add(gas, params.CallNewAccountGas) + } + } else if !env.StateDB.Exist(address) { + gas.Add(gas, params.CallNewAccountGas) + } + if transfersValue { + gas.Add(gas, params.CallValueTransferGas) + } + gas.Add(gas, memoryGasCost(mem, memorySize)) + + cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) + // Replace the stack item with the new gas calculation. This means that + // either the original item is left on the stack or the item is replaced by: + // (availableGas - gas) * 63 / 64 + // We replace the stack item so that it's available when the opCall instruction is + // called. This information is otherwise lost due to the dependency on *current* + // available gas. + stack.data[stack.len()-1] = cg + + return gas.Add(gas, cg) +} + +func gasCallCode(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int).Set(gt.Calls) + if stack.Back(2).BitLen() > 0 { + gas.Add(gas, params.CallValueTransferGas) + } + gas.Add(gas, memoryGasCost(mem, memorySize)) + + cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) + // Replace the stack item with the new gas calculation. This means that + // either the original item is left on the stack or the item is replaced by: + // (availableGas - gas) * 63 / 64 + // We replace the stack item so that it's available when the opCall instruction is + // called. This information is otherwise lost due to the dependency on *current* + // available gas. + stack.data[stack.len()-1] = cg + + return gas.Add(gas, cg) +} + +func gasReturn(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return memoryGasCost(mem, memorySize) +} + +func gasSuicide(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int) + // EIP150 homestead gas reprice fork: + if env.ChainConfig().IsEIP150(env.BlockNumber) { + gas.Set(gt.Suicide) + var ( + address = common.BigToAddress(stack.Back(0)) + eip158 = env.ChainConfig().IsEIP158(env.BlockNumber) + ) + + if eip158 { + // if empty and transfers value + if env.StateDB.Empty(address) && env.StateDB.GetBalance(contract.Address()).BitLen() > 0 { + gas.Add(gas, gt.CreateBySuicide) + } + } else if !env.StateDB.Exist(address) { + gas.Add(gas, gt.CreateBySuicide) + } + } + + if !env.StateDB.HasSuicided(contract.Address()) { + env.StateDB.AddRefund(params.SuicideRefundGas) + } + return gas +} + +func gasDelegateCall(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + gas := new(big.Int).Add(gt.Calls, memoryGasCost(mem, memorySize)) + + cg := callGas(gt, contract.Gas, gas, stack.data[stack.len()-1]) + // Replace the stack item with the new gas calculation. This means that + // either the original item is left on the stack or the item is replaced by: + // (availableGas - gas) * 63 / 64 + // We replace the stack item so that it's available when the opCall instruction is + // called. + stack.data[stack.len()-1] = cg + + return gas.Add(gas, cg) +} + +func gasPush(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return GasFastestStep +} + +func gasSwap(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return GasFastestStep +} + +func gasDup(gt params.GasTable, env *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize *big.Int) *big.Int { + return GasFastestStep +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index e43660474f..fc63417d15 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -22,132 +22,44 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common/math" + "github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/params" ) -type programInstruction interface { - // executes the program instruction and allows the instruction to modify the state of the program - do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) - // returns whether the program instruction halts the execution of the JIT - halts() bool - // Returns the current op code (debugging purposes) - Op() OpCode -} - -type instrFn func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) - -type instruction struct { - op OpCode - pc uint64 - fn instrFn - data *big.Int - - gas *big.Int - spop int - spush int - - returns bool -} - -func jump(mapping map[uint64]uint64, destinations map[uint64]struct{}, contract *Contract, to *big.Int) (uint64, error) { - if !validDest(destinations, to) { - nop := contract.GetOp(to.Uint64()) - return 0, fmt.Errorf("invalid jump destination (%v) %v", nop, to) - } - - return mapping[to.Uint64()], nil -} - -func (instr instruction) do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // calculate the new memory size and gas price for the current executing opcode - newMemSize, cost, err := jitCalculateGasAndSize(env, contract, instr, env.Db(), memory, stack) - if err != nil { - return nil, err - } - - // Use the calculated gas. When insufficient gas is present, use all gas and return an - // Out Of Gas error - if !contract.UseGas(cost) { - return nil, OutOfGasError - } - // Resize the memory calculated previously - memory.Resize(newMemSize.Uint64()) - - // These opcodes return an argument and are therefor handled - // differently from the rest of the opcodes - switch instr.op { - case JUMP: - if pos, err := jump(program.mapping, program.destinations, contract, stack.pop()); err != nil { - return nil, err - } else { - *pc = pos - return nil, nil - } - case JUMPI: - pos, cond := stack.pop(), stack.pop() - if cond.Cmp(common.BigTrue) >= 0 { - if pos, err := jump(program.mapping, program.destinations, contract, pos); err != nil { - return nil, err - } else { - *pc = pos - return nil, nil - } - } - case RETURN: - offset, size := stack.pop(), stack.pop() - return memory.GetPtr(offset.Int64(), size.Int64()), nil - default: - if instr.fn == nil { - return nil, fmt.Errorf("Invalid opcode 0x%x", instr.op) - } - instr.fn(instr, pc, env, contract, memory, stack) - } - *pc++ +func opAdd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + x, y := stack.pop(), stack.pop() + stack.push(U256(x.Add(x, y))) return nil, nil } -func (instr instruction) halts() bool { - return instr.returns -} - -func (instr instruction) Op() OpCode { - return instr.op -} - -func opStaticJump(instr instruction, pc *uint64, ret *big.Int, env Environment, contract *Contract, memory *Memory, stack *Stack) { - ret.Set(instr.data) -} - -func opAdd(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - x, y := stack.pop(), stack.pop() - stack.push(U256(x.Add(x, y))) -} - -func opSub(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSub(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(U256(x.Sub(x, y))) + return nil, nil } -func opMul(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opMul(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(U256(x.Mul(x, y))) + return nil, nil } -func opDiv(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opDiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Cmp(common.Big0) != 0 { stack.push(U256(x.Div(x, y))) } else { stack.push(new(big.Int)) } + return nil, nil } -func opSdiv(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if y.Cmp(common.Big0) == 0 { stack.push(new(big.Int)) - return + return nil, nil } else { n := new(big.Int) if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 { @@ -161,18 +73,20 @@ func opSdiv(instr instruction, pc *uint64, env Environment, contract *Contract, stack.push(U256(res)) } + return nil, nil } -func opMod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opMod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Cmp(common.Big0) == 0 { stack.push(new(big.Int)) } else { stack.push(U256(x.Mod(x, y))) } + return nil, nil } -func opSmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if y.Cmp(common.Big0) == 0 { @@ -190,14 +104,16 @@ func opSmod(instr instruction, pc *uint64, env Environment, contract *Contract, stack.push(U256(res)) } + return nil, nil } -func opExp(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opExp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { base, exponent := stack.pop(), stack.pop() stack.push(math.Exp(base, exponent)) + return nil, nil } -func opSignExtend(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { back := stack.pop() if back.Cmp(big.NewInt(31)) < 0 { bit := uint(back.Uint64()*8 + 7) @@ -212,80 +128,91 @@ func opSignExtend(instr instruction, pc *uint64, env Environment, contract *Cont stack.push(U256(num)) } + return nil, nil } -func opNot(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opNot(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x := stack.pop() stack.push(U256(x.Not(x))) + return nil, nil } -func opLt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opLt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) < 0 { stack.push(big.NewInt(1)) } else { stack.push(new(big.Int)) } + return nil, nil } -func opGt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opGt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) > 0 { stack.push(big.NewInt(1)) } else { stack.push(new(big.Int)) } + return nil, nil } -func opSlt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSlt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if x.Cmp(S256(y)) < 0 { stack.push(big.NewInt(1)) } else { stack.push(new(big.Int)) } + return nil, nil } -func opSgt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSgt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if x.Cmp(y) > 0 { stack.push(big.NewInt(1)) } else { stack.push(new(big.Int)) } + return nil, nil } -func opEq(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opEq(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) == 0 { stack.push(big.NewInt(1)) } else { stack.push(new(big.Int)) } + return nil, nil } -func opIszero(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opIszero(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x := stack.pop() if x.Cmp(common.Big0) > 0 { stack.push(new(big.Int)) } else { stack.push(big.NewInt(1)) } + return nil, nil } -func opAnd(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opAnd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.And(x, y)) + return nil, nil } -func opOr(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opOr(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Or(x, y)) + return nil, nil } -func opXor(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opXor(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Xor(x, y)) + return nil, nil } -func opByte(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opByte(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { th, val := stack.pop(), stack.pop() if th.Cmp(big.NewInt(32)) < 0 { byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) @@ -293,8 +220,9 @@ func opByte(instr instruction, pc *uint64, env Environment, contract *Contract, } else { stack.push(new(big.Int)) } + return nil, nil } -func opAddmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opAddmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(Zero) > 0 { add := x.Add(x, y) @@ -303,8 +231,9 @@ func opAddmod(instr instruction, pc *uint64, env Environment, contract *Contract } else { stack.push(new(big.Int)) } + return nil, nil } -func opMulmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opMulmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() if z.Cmp(Zero) > 0 { mul := x.Mul(x, y) @@ -313,67 +242,79 @@ func opMulmod(instr instruction, pc *uint64, env Environment, contract *Contract } else { stack.push(new(big.Int)) } + return nil, nil } -func opSha3(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSha3(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() hash := crypto.Keccak256(memory.Get(offset.Int64(), size.Int64())) stack.push(common.BytesToBig(hash)) + return nil, nil } -func opAddress(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opAddress(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(common.Bytes2Big(contract.Address().Bytes())) + return nil, nil } -func opBalance(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opBalance(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { addr := common.BigToAddress(stack.pop()) - balance := env.Db().GetBalance(addr) + balance := env.StateDB.GetBalance(addr) stack.push(new(big.Int).Set(balance)) + return nil, nil } -func opOrigin(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(env.Origin().Big()) +func opOrigin(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(env.Origin.Big()) + return nil, nil } -func opCaller(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCaller(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(contract.Caller().Big()) + return nil, nil } -func opCallValue(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCallValue(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(new(big.Int).Set(contract.value)) + return nil, nil } -func opCalldataLoad(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCalldataLoad(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(common.Bytes2Big(getData(contract.Input, stack.pop(), common.Big32))) + return nil, nil } -func opCalldataSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCalldataSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(big.NewInt(int64(len(contract.Input)))) + return nil, nil } -func opCalldataCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCalldataCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( mOff = stack.pop() cOff = stack.pop() l = stack.pop() ) memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l)) + return nil, nil } -func opExtCodeSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opExtCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { addr := common.BigToAddress(stack.pop()) - l := big.NewInt(int64(env.Db().GetCodeSize(addr))) + l := big.NewInt(int64(env.StateDB.GetCodeSize(addr))) stack.push(l) + return nil, nil } -func opCodeSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { l := big.NewInt(int64(len(contract.Code))) stack.push(l) + return nil, nil } -func opCodeCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( mOff = stack.pop() cOff = stack.pop() @@ -382,160 +323,173 @@ func opCodeCopy(instr instruction, pc *uint64, env Environment, contract *Contra codeCopy := getData(contract.Code, cOff, l) memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) + return nil, nil } -func opExtCodeCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opExtCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( addr = common.BigToAddress(stack.pop()) mOff = stack.pop() cOff = stack.pop() l = stack.pop() ) - codeCopy := getData(env.Db().GetCode(addr), cOff, l) + codeCopy := getData(env.StateDB.GetCode(addr), cOff, l) memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) + return nil, nil } -func opGasprice(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(new(big.Int).Set(contract.Price)) +func opGasprice(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(new(big.Int).Set(env.GasPrice)) + return nil, nil } -func opBlockhash(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opBlockhash(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { num := stack.pop() - n := new(big.Int).Sub(env.BlockNumber(), common.Big257) - if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber()) < 0 { + n := new(big.Int).Sub(env.BlockNumber, common.Big257) + if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber) < 0 { stack.push(env.GetHash(num.Uint64()).Big()) } else { stack.push(new(big.Int)) } + return nil, nil } -func opCoinbase(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(env.Coinbase().Big()) +func opCoinbase(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(env.Coinbase.Big()) + return nil, nil } -func opTimestamp(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(U256(new(big.Int).Set(env.Time()))) +func opTimestamp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(env.Time))) + return nil, nil } -func opNumber(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(U256(new(big.Int).Set(env.BlockNumber()))) +func opNumber(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(env.BlockNumber))) + return nil, nil } -func opDifficulty(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(U256(new(big.Int).Set(env.Difficulty()))) +func opDifficulty(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(env.Difficulty))) + return nil, nil } -func opGasLimit(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(U256(new(big.Int).Set(env.GasLimit()))) +func opGasLimit(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(env.GasLimit))) + return nil, nil } -func opPop(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opPop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.pop() + return nil, nil } -func opPush(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(new(big.Int).Set(instr.data)) -} - -func opDup(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.dup(int(instr.data.Int64())) -} - -func opSwap(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.swap(int(instr.data.Int64())) -} - -func opLog(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - n := int(instr.data.Int64()) - topics := make([]common.Hash, n) - mStart, mSize := stack.pop(), stack.pop() - for i := 0; i < n; i++ { - topics[i] = common.BigToHash(stack.pop()) - } - - d := memory.Get(mStart.Int64(), mSize.Int64()) - log := NewLog(contract.Address(), topics, d, env.BlockNumber().Uint64()) - env.AddLog(log) -} - -func opMload(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opMload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset := stack.pop() val := common.BigD(memory.Get(offset.Int64(), 32)) stack.push(val) + return nil, nil } -func opMstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opMstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // pop value of the stack mStart, val := stack.pop(), stack.pop() memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256)) + return nil, nil } -func opMstore8(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opMstore8(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { off, val := stack.pop().Int64(), stack.pop().Int64() memory.store[off] = byte(val & 0xff) + return nil, nil } -func opSload(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) - val := env.Db().GetState(contract.Address(), loc).Big() + val := env.StateDB.GetState(contract.Address(), loc).Big() stack.push(val) + return nil, nil } -func opSstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opSstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) val := stack.pop() - env.Db().SetState(contract.Address(), loc, common.BigToHash(val)) + env.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) + return nil, nil } -func opJump(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opJump(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + pos := stack.pop() + if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { + nop := contract.GetOp(pos.Uint64()) + return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) + } + *pc = pos.Uint64() + return nil, nil } -func opJumpi(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + pos, cond := stack.pop(), stack.pop() + if cond.Cmp(common.BigTrue) >= 0 { + if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { + nop := contract.GetOp(pos.Uint64()) + return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) + } + *pc = pos.Uint64() + } else { + *pc++ + } + return nil, nil } -func opJumpdest(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opJumpdest(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return nil, nil } -func opPc(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - stack.push(new(big.Int).Set(instr.data)) +func opPc(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(new(big.Int).SetUint64(*pc)) + return nil, nil } -func opMsize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opMsize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(big.NewInt(int64(memory.Len()))) + return nil, nil } -func opGas(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opGas(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(new(big.Int).Set(contract.Gas)) + return nil, nil } -func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCreate(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( value = stack.pop() offset, size = stack.pop(), stack.pop() input = memory.Get(offset.Int64(), size.Int64()) gas = new(big.Int).Set(contract.Gas) ) - if env.ChainConfig().IsEIP150(env.BlockNumber()) { + if env.ChainConfig().IsEIP150(env.BlockNumber) { gas.Div(gas, n64) gas = gas.Sub(contract.Gas, gas) } contract.UseGas(gas) - _, addr, suberr := env.Create(contract, input, gas, contract.Price, value) + _, addr, suberr := env.Create(contract, input, gas, value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if env.ChainConfig().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError { + if env.ChainConfig().IsHomestead(env.BlockNumber) && suberr == ErrCodeStoreOutOfGas { stack.push(new(big.Int)) - } else if suberr != nil && suberr != CodeStoreOutOfGasError { + } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stack.push(new(big.Int)) } else { stack.push(addr.Big()) } + return nil, nil } -func opCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { gas := stack.pop() // pop gas and value of the stack. addr, value := stack.pop(), stack.pop() @@ -554,7 +508,7 @@ func opCall(instr instruction, pc *uint64, env Environment, contract *Contract, gas.Add(gas, params.CallStipend) } - ret, err := env.Call(contract, address, args, gas, contract.Price, value) + ret, err := env.Call(contract, address, args, gas, value) if err != nil { stack.push(new(big.Int)) @@ -564,9 +518,10 @@ func opCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + return nil, nil } -func opCallCode(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { gas := stack.pop() // pop gas and value of the stack. addr, value := stack.pop(), stack.pop() @@ -585,7 +540,7 @@ func opCallCode(instr instruction, pc *uint64, env Environment, contract *Contra gas.Add(gas, params.CallStipend) } - ret, err := env.CallCode(contract, address, args, gas, contract.Price, value) + ret, err := env.CallCode(contract, address, args, gas, value) if err != nil { stack.push(new(big.Int)) @@ -595,39 +550,55 @@ func opCallCode(instr instruction, pc *uint64, env Environment, contract *Contra memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + return nil, nil } -func opDelegateCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opDelegateCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // if not homestead return an error. DELEGATECALL is not supported + // during pre-homestead. + if !env.ChainConfig().IsHomestead(env.BlockNumber) { + return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL) + } + gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(to) args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, err := env.DelegateCall(contract, toAddr, args, gas, contract.Price) + ret, err := env.DelegateCall(contract, toAddr, args, gas) if err != nil { stack.push(new(big.Int)) } else { stack.push(big.NewInt(1)) memory.Set(outOffset.Uint64(), outSize.Uint64(), ret) } + return nil, nil } -func opReturn(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { -} -func opStop(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func opReturn(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + offset, size := stack.pop(), stack.pop() + ret := memory.GetPtr(offset.Int64(), size.Int64()) + + return ret, nil } -func opSuicide(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { - balance := env.Db().GetBalance(contract.Address()) - env.Db().AddBalance(common.BigToAddress(stack.pop()), balance) +func opStop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return nil, nil +} - env.Db().Suicide(contract.Address()) +func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + balance := env.StateDB.GetBalance(contract.Address()) + env.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) + + env.StateDB.Suicide(contract.Address()) + + return nil, nil } // following functions are used by the instruction jump table // make log instruction function -func makeLog(size int) instrFn { - return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func makeLog(size int) executionFunc { + return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { topics := make([]common.Hash, size) mStart, mSize := stack.pop(), stack.pop() for i := 0; i < size; i++ { @@ -635,32 +606,42 @@ func makeLog(size int) instrFn { } d := memory.Get(mStart.Int64(), mSize.Int64()) - log := NewLog(contract.Address(), topics, d, env.BlockNumber().Uint64()) - env.AddLog(log) + env.StateDB.AddLog(&types.Log{ + Address: contract.Address(), + Topics: topics, + Data: d, + // This is a non-consensus field, but assigned here because + // core/state doesn't know the current block number. + BlockNumber: env.BlockNumber.Uint64(), + }) + return nil, nil } } // make push instruction function -func makePush(size uint64, bsize *big.Int) instrFn { - return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func makePush(size uint64, bsize *big.Int) executionFunc { + return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { byts := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize) stack.push(common.Bytes2Big(byts)) *pc += size + return nil, nil } } // make push instruction function -func makeDup(size int64) instrFn { - return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { +func makeDup(size int64) executionFunc { + return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.dup(int(size)) + return nil, nil } } // make swap instruction function -func makeSwap(size int64) instrFn { +func makeSwap(size int64) executionFunc { // switch n + 1 otherwise n would be swapped with n size += 1 - return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) { + return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.swap(int(size)) + return nil, nil } } diff --git a/core/vm/interface.go b/core/vm/interface.go new file mode 100644 index 0000000000..e04bd4c3ff --- /dev/null +++ b/core/vm/interface.go @@ -0,0 +1,90 @@ +// 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 . + +package vm + +import ( + "math/big" + + "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/core/types" +) + +// StateDB is an EVM database for full state querying. +type StateDB interface { + GetAccount(common.Address) Account + CreateAccount(common.Address) Account + + SubBalance(common.Address, *big.Int) + AddBalance(common.Address, *big.Int) + GetBalance(common.Address) *big.Int + + GetNonce(common.Address) uint64 + SetNonce(common.Address, uint64) + + GetCodeHash(common.Address) common.Hash + GetCode(common.Address) []byte + SetCode(common.Address, []byte) + GetCodeSize(common.Address) int + + 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 + + RevertToSnapshot(int) + Snapshot() int + + AddLog(*types.Log) +} + +// Account represents a contract or basic ethereum account. +type Account interface { + SubBalance(amount *big.Int) + AddBalance(amount *big.Int) + SetBalance(*big.Int) + SetNonce(uint64) + Balance() *big.Int + Address() common.Address + ReturnGas(*big.Int) + SetCode(common.Hash, []byte) + ForEachStorage(cb func(key, value common.Hash) bool) + Value() *big.Int +} + +// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM +// depends on this context being implemented for doing subcalls and initialising new EVM contracts. +type CallContext interface { + // Call another contract + Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) + // Take another's contract code and execute within our own context + CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) + // Same as CallCode except sender and value is propagated from parent to child scope + DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) + // Create a new contract + Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) +} diff --git a/core/vm/jit.go b/core/vm/jit.go deleted file mode 100644 index ebbc58a359..0000000000 --- a/core/vm/jit.go +++ /dev/null @@ -1,512 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -import ( - "fmt" - "math/big" - "sync/atomic" - "time" - - "github.com/ubiq/go-ubiq/common" - "github.com/ubiq/go-ubiq/crypto" - "github.com/ubiq/go-ubiq/logger" - "github.com/ubiq/go-ubiq/logger/glog" - "github.com/ubiq/go-ubiq/params" - "github.com/hashicorp/golang-lru" -) - -// progStatus is the type for the JIT program status. -type progStatus int32 - -const ( - progUnknown progStatus = iota // unknown status - progCompile // compile status - progReady // ready for use status - progError // error status (usually caused during compilation) - - defaultJitMaxCache int = 64 // maximum amount of jit cached programs -) - -var MaxProgSize int // Max cache size for JIT programs - -var programs *lru.Cache // lru cache for the JIT programs. - -func init() { - SetJITCacheSize(defaultJitMaxCache) -} - -// SetJITCacheSize recreates the program cache with the max given size. Setting -// a new cache is **not** thread safe. Use with caution. -func SetJITCacheSize(size int) { - programs, _ = lru.New(size) -} - -// GetProgram returns the program by id or nil when non-existent -func GetProgram(id common.Hash) *Program { - if p, ok := programs.Get(id); ok { - return p.(*Program) - } - - return nil -} - -// GenProgramStatus returns the status of the given program id -func GetProgramStatus(id common.Hash) progStatus { - program := GetProgram(id) - if program != nil { - return progStatus(atomic.LoadInt32(&program.status)) - } - - return progUnknown -} - -// Program is a compiled program for the JIT VM and holds all required for -// running a compiled JIT program. -type Program struct { - Id common.Hash // Id of the program - status int32 // status should be accessed atomically - - contract *Contract - - instructions []programInstruction // instruction set - mapping map[uint64]uint64 // real PC mapping to array indices - destinations map[uint64]struct{} // cached jump destinations - - code []byte -} - -// NewProgram returns a new JIT program -func NewProgram(code []byte) *Program { - program := &Program{ - Id: crypto.Keccak256Hash(code), - mapping: make(map[uint64]uint64), - destinations: make(map[uint64]struct{}), - code: code, - } - - programs.Add(program.Id, program) - return program -} - -func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) { - // PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit - // PUSH is also allowed to calculate the same price for all PUSHes - // DUP requirements are handled elsewhere (except for the stack limit check) - baseOp := op - if op >= PUSH1 && op <= PUSH32 { - baseOp = PUSH1 - } - if op >= DUP1 && op <= DUP16 { - baseOp = DUP1 - } - base := _baseCheck[baseOp] - - returns := op == RETURN || op == SUICIDE || op == STOP - instr := instruction{op, pc, fn, data, base.gas, base.stackPop, base.stackPush, returns} - - p.instructions = append(p.instructions, instr) - p.mapping[pc] = uint64(len(p.instructions) - 1) -} - -// CompileProgram compiles the given program and return an error when it fails -func CompileProgram(program *Program) (err error) { - if progStatus(atomic.LoadInt32(&program.status)) == progCompile { - return nil - } - atomic.StoreInt32(&program.status, int32(progCompile)) - defer func() { - if err != nil { - atomic.StoreInt32(&program.status, int32(progError)) - } else { - atomic.StoreInt32(&program.status, int32(progReady)) - } - }() - if glog.V(logger.Debug) { - glog.Infof("compiling %x\n", program.Id[:4]) - tstart := time.Now() - defer func() { - glog.Infof("compiled %x instrc: %d time: %v\n", program.Id[:4], len(program.instructions), time.Since(tstart)) - }() - } - - // loop thru the opcodes and "compile" in to instructions - for pc := uint64(0); pc < uint64(len(program.code)); pc++ { - switch op := OpCode(program.code[pc]); op { - case ADD: - program.addInstr(op, pc, opAdd, nil) - case SUB: - program.addInstr(op, pc, opSub, nil) - case MUL: - program.addInstr(op, pc, opMul, nil) - case DIV: - program.addInstr(op, pc, opDiv, nil) - case SDIV: - program.addInstr(op, pc, opSdiv, nil) - case MOD: - program.addInstr(op, pc, opMod, nil) - case SMOD: - program.addInstr(op, pc, opSmod, nil) - case EXP: - program.addInstr(op, pc, opExp, nil) - case SIGNEXTEND: - program.addInstr(op, pc, opSignExtend, nil) - case NOT: - program.addInstr(op, pc, opNot, nil) - case LT: - program.addInstr(op, pc, opLt, nil) - case GT: - program.addInstr(op, pc, opGt, nil) - case SLT: - program.addInstr(op, pc, opSlt, nil) - case SGT: - program.addInstr(op, pc, opSgt, nil) - case EQ: - program.addInstr(op, pc, opEq, nil) - case ISZERO: - program.addInstr(op, pc, opIszero, nil) - case AND: - program.addInstr(op, pc, opAnd, nil) - case OR: - program.addInstr(op, pc, opOr, nil) - case XOR: - program.addInstr(op, pc, opXor, nil) - case BYTE: - program.addInstr(op, pc, opByte, nil) - case ADDMOD: - program.addInstr(op, pc, opAddmod, nil) - case MULMOD: - program.addInstr(op, pc, opMulmod, nil) - case SHA3: - program.addInstr(op, pc, opSha3, nil) - case ADDRESS: - program.addInstr(op, pc, opAddress, nil) - case BALANCE: - program.addInstr(op, pc, opBalance, nil) - case ORIGIN: - program.addInstr(op, pc, opOrigin, nil) - case CALLER: - program.addInstr(op, pc, opCaller, nil) - case CALLVALUE: - program.addInstr(op, pc, opCallValue, nil) - case CALLDATALOAD: - program.addInstr(op, pc, opCalldataLoad, nil) - case CALLDATASIZE: - program.addInstr(op, pc, opCalldataSize, nil) - case CALLDATACOPY: - program.addInstr(op, pc, opCalldataCopy, nil) - case CODESIZE: - program.addInstr(op, pc, opCodeSize, nil) - case EXTCODESIZE: - program.addInstr(op, pc, opExtCodeSize, nil) - case CODECOPY: - program.addInstr(op, pc, opCodeCopy, nil) - case EXTCODECOPY: - program.addInstr(op, pc, opExtCodeCopy, nil) - case GASPRICE: - program.addInstr(op, pc, opGasprice, nil) - case BLOCKHASH: - program.addInstr(op, pc, opBlockhash, nil) - case COINBASE: - program.addInstr(op, pc, opCoinbase, nil) - case TIMESTAMP: - program.addInstr(op, pc, opTimestamp, nil) - case NUMBER: - program.addInstr(op, pc, opNumber, nil) - case DIFFICULTY: - program.addInstr(op, pc, opDifficulty, nil) - case GASLIMIT: - program.addInstr(op, pc, opGasLimit, nil) - case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: - size := uint64(op - PUSH1 + 1) - bytes := getData([]byte(program.code), new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size)) - - program.addInstr(op, pc, opPush, common.Bytes2Big(bytes)) - - pc += size - - case POP: - program.addInstr(op, pc, opPop, nil) - case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: - program.addInstr(op, pc, opDup, big.NewInt(int64(op-DUP1+1))) - case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: - program.addInstr(op, pc, opSwap, big.NewInt(int64(op-SWAP1+2))) - case LOG0, LOG1, LOG2, LOG3, LOG4: - program.addInstr(op, pc, opLog, big.NewInt(int64(op-LOG0))) - case MLOAD: - program.addInstr(op, pc, opMload, nil) - case MSTORE: - program.addInstr(op, pc, opMstore, nil) - case MSTORE8: - program.addInstr(op, pc, opMstore8, nil) - case SLOAD: - program.addInstr(op, pc, opSload, nil) - case SSTORE: - program.addInstr(op, pc, opSstore, nil) - case JUMP: - program.addInstr(op, pc, opJump, nil) - case JUMPI: - program.addInstr(op, pc, opJumpi, nil) - case JUMPDEST: - program.addInstr(op, pc, opJumpdest, nil) - program.destinations[pc] = struct{}{} - case PC: - program.addInstr(op, pc, opPc, big.NewInt(int64(pc))) - case MSIZE: - program.addInstr(op, pc, opMsize, nil) - case GAS: - program.addInstr(op, pc, opGas, nil) - case CREATE: - program.addInstr(op, pc, opCreate, nil) - case DELEGATECALL: - // Instruction added regardless of homestead phase. - // Homestead (and execution of the opcode) is checked during - // runtime. - program.addInstr(op, pc, opDelegateCall, nil) - case CALL: - program.addInstr(op, pc, opCall, nil) - case CALLCODE: - program.addInstr(op, pc, opCallCode, nil) - case RETURN: - program.addInstr(op, pc, opReturn, nil) - case SUICIDE: - program.addInstr(op, pc, opSuicide, nil) - case STOP: // Stop the contract - program.addInstr(op, pc, opStop, nil) - default: - program.addInstr(op, pc, nil, nil) - } - } - - optimiseProgram(program) - - return nil -} - -// RunProgram runs the program given the environment and contract and returns an -// error if the execution failed (non-consensus) -func RunProgram(program *Program, env Environment, contract *Contract, input []byte) ([]byte, error) { - return runProgram(program, 0, NewMemory(), newstack(), env, contract, input) -} - -func runProgram(program *Program, pcstart uint64, mem *Memory, stack *Stack, env Environment, contract *Contract, input []byte) ([]byte, error) { - contract.Input = input - - var ( - pc uint64 = program.mapping[pcstart] - instrCount = 0 - ) - - if glog.V(logger.Debug) { - glog.Infof("running JIT program %x\n", program.Id[:4]) - tstart := time.Now() - defer func() { - glog.Infof("JIT program %x done. time: %v instrc: %v\n", program.Id[:4], time.Since(tstart), instrCount) - }() - } - - homestead := env.ChainConfig().IsHomestead(env.BlockNumber()) - for pc < uint64(len(program.instructions)) { - instrCount++ - - instr := program.instructions[pc] - if instr.Op() == DELEGATECALL && !homestead { - return nil, fmt.Errorf("Invalid opcode 0x%x", instr.Op()) - } - - ret, err := instr.do(program, &pc, env, contract, mem, stack) - if err != nil { - return nil, err - } - - if instr.halts() { - return ret, nil - } - } - - contract.Input = nil - - return nil, nil -} - -// validDest checks if the given destination is a valid one given the -// destination table of the program -func validDest(dests map[uint64]struct{}, dest *big.Int) bool { - // PC cannot go beyond len(code) and certainly can't be bigger than 64bits. - // Don't bother checking for JUMPDEST in that case. - if dest.Cmp(bigMaxUint64) > 0 { - return false - } - _, ok := dests[dest.Uint64()] - return ok -} - -// jitCalculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for -// the operation. This does not reduce gas or resizes the memory. -func jitCalculateGasAndSize(env Environment, contract *Contract, instr instruction, statedb Database, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) { - var ( - gas = new(big.Int) - newMemSize *big.Int = new(big.Int) - ) - err := jitBaseCheck(instr, stack, gas) - if err != nil { - return nil, nil, err - } - - // stack Check, memory resize & gas phase - switch op := instr.op; op { - case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: - n := int(op - SWAP1 + 2) - err := stack.require(n) - if err != nil { - return nil, nil, err - } - gas.Set(GasFastestStep) - case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: - n := int(op - DUP1 + 1) - err := stack.require(n) - if err != nil { - return nil, nil, err - } - gas.Set(GasFastestStep) - case LOG0, LOG1, LOG2, LOG3, LOG4: - n := int(op - LOG0) - err := stack.require(n + 2) - if err != nil { - return nil, nil, err - } - - mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] - - add := new(big.Int) - gas.Add(gas, params.LogGas) - gas.Add(gas, add.Mul(big.NewInt(int64(n)), params.LogTopicGas)) - gas.Add(gas, add.Mul(mSize, params.LogDataGas)) - - newMemSize = calcMemSize(mStart, mSize) - case EXP: - gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas)) - case SSTORE: - err := stack.require(2) - if err != nil { - return nil, nil, err - } - - var g *big.Int - y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] - val := statedb.GetState(contract.Address(), common.BigToHash(x)) - - // This checks for 3 scenario's and calculates gas accordingly - // 1. From a zero-value address to a non-zero value (NEW VALUE) - // 2. From a non-zero value address to a zero-value address (DELETE) - // 3. From a non-zero to a non-zero (CHANGE) - if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { - g = params.SstoreSetGas - } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { - statedb.AddRefund(params.SstoreRefundGas) - - g = params.SstoreClearGas - } else { - g = params.SstoreResetGas - } - gas.Set(g) - case SUICIDE: - if !statedb.HasSuicided(contract.Address()) { - statedb.AddRefund(params.SuicideRefundGas) - } - case MLOAD: - newMemSize = calcMemSize(stack.peek(), u256(32)) - case MSTORE8: - newMemSize = calcMemSize(stack.peek(), u256(1)) - case MSTORE: - newMemSize = calcMemSize(stack.peek(), u256(32)) - case RETURN: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) - case SHA3: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) - - words := toWordSize(stack.data[stack.len()-2]) - gas.Add(gas, words.Mul(words, params.Sha3WordGas)) - case CALLDATACOPY: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) - - words := toWordSize(stack.data[stack.len()-3]) - gas.Add(gas, words.Mul(words, params.CopyGas)) - case CODECOPY: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) - - words := toWordSize(stack.data[stack.len()-3]) - gas.Add(gas, words.Mul(words, params.CopyGas)) - case EXTCODECOPY: - newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) - - words := toWordSize(stack.data[stack.len()-4]) - gas.Add(gas, words.Mul(words, params.CopyGas)) - - case CREATE: - newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) - case CALL, CALLCODE: - gas.Add(gas, stack.data[stack.len()-1]) - - if op == CALL { - if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) { - gas.Add(gas, params.CallNewAccountGas) - } - } - - if len(stack.data[stack.len()-3].Bytes()) > 0 { - gas.Add(gas, params.CallValueTransferGas) - } - - x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) - y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5]) - - newMemSize = common.BigMax(x, y) - case DELEGATECALL: - gas.Add(gas, stack.data[stack.len()-1]) - - x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6]) - y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4]) - - newMemSize = common.BigMax(x, y) - } - quadMemGas(mem, newMemSize, gas) - - return newMemSize, gas, nil -} - -// jitBaseCheck is the same as baseCheck except it doesn't do the look up in the -// gas table. This is done during compilation instead. -func jitBaseCheck(instr instruction, stack *Stack, gas *big.Int) error { - err := stack.require(instr.spop) - if err != nil { - return err - } - - if instr.spush > 0 && stack.len()-instr.spop+instr.spush > int(params.StackLimit.Int64()) { - return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64()) - } - - // nil on gas means no base calculation - if instr.gas == nil { - return nil - } - - gas.Add(gas, instr.gas) - - return nil -} diff --git a/core/vm/jit_optimiser.go b/core/vm/jit_optimiser.go deleted file mode 100644 index 9886eb4d7f..0000000000 --- a/core/vm/jit_optimiser.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -import ( - "math/big" - "time" - - "github.com/ubiq/go-ubiq/logger" - "github.com/ubiq/go-ubiq/logger/glog" -) - -// optimeProgram optimises a JIT program creating segments out of program -// instructions. Currently covered are multi-pushes and static jumps -func optimiseProgram(program *Program) { - var load []instruction - - var ( - statsJump = 0 - statsPush = 0 - ) - - if glog.V(logger.Debug) { - glog.Infof("optimising %x\n", program.Id[:4]) - tstart := time.Now() - defer func() { - glog.Infof("optimised %x done in %v with JMP: %d PSH: %d\n", program.Id[:4], time.Since(tstart), statsJump, statsPush) - }() - } - - /* - code := Parse(program.code) - for _, test := range [][]OpCode{ - []OpCode{PUSH, PUSH, ADD}, - []OpCode{PUSH, PUSH, SUB}, - []OpCode{PUSH, PUSH, MUL}, - []OpCode{PUSH, PUSH, DIV}, - } { - matchCount := 0 - MatchFn(code, test, func(i int) bool { - matchCount++ - return true - }) - fmt.Printf("found %d match count on: %v\n", matchCount, test) - } - */ - - for i := 0; i < len(program.instructions); i++ { - instr := program.instructions[i].(instruction) - - switch { - case instr.op.IsPush(): - load = append(load, instr) - case instr.op.IsStaticJump(): - if len(load) == 0 { - continue - } - // if the push load is greater than 1, finalise that - // segment first - if len(load) > 2 { - seg, size := makePushSeg(load[:len(load)-1]) - program.instructions[i-size-1] = seg - statsPush++ - } - // create a segment consisting of a pre determined - // jump, destination and validity. - seg := makeStaticJumpSeg(load[len(load)-1].data, program) - program.instructions[i-1] = seg - statsJump++ - - load = nil - default: - // create a new N pushes segment - if len(load) > 1 { - seg, size := makePushSeg(load) - program.instructions[i-size] = seg - statsPush++ - } - load = nil - } - } -} - -// makePushSeg creates a new push segment from N amount of push instructions -func makePushSeg(instrs []instruction) (pushSeg, int) { - var ( - data []*big.Int - gas = new(big.Int) - ) - - for _, instr := range instrs { - data = append(data, instr.data) - gas.Add(gas, instr.gas) - } - - return pushSeg{data, gas}, len(instrs) -} - -// makeStaticJumpSeg creates a new static jump segment from a predefined -// destination (PUSH, JUMP). -func makeStaticJumpSeg(to *big.Int, program *Program) jumpSeg { - gas := new(big.Int) - gas.Add(gas, _baseCheck[PUSH1].gas) - gas.Add(gas, _baseCheck[JUMP].gas) - - contract := &Contract{Code: program.code} - pos, err := jump(program.mapping, program.destinations, contract, to) - return jumpSeg{pos, err, gas} -} diff --git a/core/vm/jit_test.go b/core/vm/jit_test.go deleted file mode 100644 index 95aa6241c1..0000000000 --- a/core/vm/jit_test.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -import ( - "math/big" - "testing" - "time" - - "github.com/ubiq/go-ubiq/common" - "github.com/ubiq/go-ubiq/crypto" - "github.com/ubiq/go-ubiq/params" -) - -const maxRun = 1000 - -func TestSegmenting(t *testing.T) { - prog := NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, 0x0}) - err := CompileProgram(prog) - if err != nil { - t.Fatal(err) - } - - if instr, ok := prog.instructions[0].(pushSeg); ok { - if len(instr.data) != 2 { - t.Error("expected 2 element width pushSegment, got", len(instr.data)) - } - } else { - t.Errorf("expected instr[0] to be a pushSeg, got %T", prog.instructions[0]) - } - - prog = NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(JUMP)}) - err = CompileProgram(prog) - if err != nil { - t.Fatal(err) - } - if _, ok := prog.instructions[1].(jumpSeg); ok { - } else { - t.Errorf("expected instr[1] to be jumpSeg, got %T", prog.instructions[1]) - } - - prog = NewProgram([]byte{byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(PUSH1), 0x1, byte(JUMP)}) - err = CompileProgram(prog) - if err != nil { - t.Fatal(err) - } - if instr, ok := prog.instructions[0].(pushSeg); ok { - if len(instr.data) != 2 { - t.Error("expected 2 element width pushSegment, got", len(instr.data)) - } - } else { - t.Errorf("expected instr[0] to be a pushSeg, got %T", prog.instructions[0]) - } - if _, ok := prog.instructions[2].(jumpSeg); ok { - } else { - t.Errorf("expected instr[1] to be jumpSeg, got %T", prog.instructions[1]) - } -} - -func TestCompiling(t *testing.T) { - prog := NewProgram([]byte{0x60, 0x10}) - err := CompileProgram(prog) - if err != nil { - t.Error("didn't expect compile error") - } - - if len(prog.instructions) != 1 { - t.Error("expected 1 compiled instruction, got", len(prog.instructions)) - } -} - -func TestResetInput(t *testing.T) { - var sender account - - env := NewEnv(&Config{EnableJit: true, ForceJit: true}) - contract := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0)) - contract.CodeAddr = &common.Address{} - - program := NewProgram([]byte{}) - RunProgram(program, env, contract, []byte{0xbe, 0xef}) - if contract.Input != nil { - t.Errorf("expected input to be nil, got %x", contract.Input) - } -} - -func TestPcMappingToInstruction(t *testing.T) { - program := NewProgram([]byte{byte(PUSH2), 0xbe, 0xef, byte(ADD)}) - CompileProgram(program) - if program.mapping[3] != 1 { - t.Error("expected mapping PC 4 to me instr no. 2, got", program.mapping[4]) - } -} - -var benchmarks = map[string]vmBench{ - "pushes": vmBench{ - false, false, false, - common.Hex2Bytes("600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01600a600a01"), nil, - }, -} - -func BenchmarkPushes(b *testing.B) { - runVmBench(benchmarks["pushes"], b) -} - -type vmBench struct { - precompile bool // compile prior to executing - nojit bool // ignore jit (sets DisbaleJit = true - forcejit bool // forces the jit, precompile is ignored - - code []byte - input []byte -} - -type account struct{} - -func (account) SubBalance(amount *big.Int) {} -func (account) AddBalance(amount *big.Int) {} -func (account) SetAddress(common.Address) {} -func (account) Value() *big.Int { return nil } -func (account) SetBalance(*big.Int) {} -func (account) SetNonce(uint64) {} -func (account) Balance() *big.Int { return nil } -func (account) Address() common.Address { return common.Address{} } -func (account) ReturnGas(*big.Int, *big.Int) {} -func (account) SetCode(common.Hash, []byte) {} -func (account) ForEachStorage(cb func(key, value common.Hash) bool) {} - -func runVmBench(test vmBench, b *testing.B) { - var sender account - - if test.precompile && !test.forcejit { - NewProgram(test.code) - } - env := NewEnv(&Config{EnableJit: !test.nojit, ForceJit: test.forcejit}) - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - context := NewContract(sender, sender, big.NewInt(100), big.NewInt(10000), big.NewInt(0)) - context.Code = test.code - context.CodeAddr = &common.Address{} - _, err := env.Vm().Run(context, test.input) - if err != nil { - b.Error(err) - b.FailNow() - } - } -} - -type Env struct { - gasLimit *big.Int - depth int - evm *EVM -} - -func NewEnv(config *Config) *Env { - env := &Env{gasLimit: big.NewInt(10000), depth: 0} - env.evm = New(env, *config) - return env -} - -func (self *Env) ChainConfig() *params.ChainConfig { - return params.TestChainConfig -} -func (self *Env) Vm() Vm { return self.evm } -func (self *Env) Origin() common.Address { return common.Address{} } -func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) } - -//func (self *Env) PrevHash() []byte { return self.parent } -func (self *Env) Coinbase() common.Address { return common.Address{} } -func (self *Env) SnapshotDatabase() int { return 0 } -func (self *Env) RevertToSnapshot(int) {} -func (self *Env) Time() *big.Int { return big.NewInt(time.Now().Unix()) } -func (self *Env) Difficulty() *big.Int { return big.NewInt(0) } -func (self *Env) Db() Database { return nil } -func (self *Env) GasLimit() *big.Int { return self.gasLimit } -func (self *Env) VmType() Type { return StdVmTy } -func (self *Env) GetHash(n uint64) common.Hash { - return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) -} -func (self *Env) AddLog(log *Log) { -} -func (self *Env) Depth() int { return self.depth } -func (self *Env) SetDepth(i int) { self.depth = i } -func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool { - return true -} -func (self *Env) Transfer(from, to Account, amount *big.Int) {} -func (self *Env) Call(caller ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return nil, nil -} -func (self *Env) CallCode(caller ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return nil, nil -} -func (self *Env) Create(caller ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - return nil, common.Address{}, nil -} -func (self *Env) DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - return nil, nil -} diff --git a/core/vm/jit_util.go b/core/vm/jit_util.go deleted file mode 100644 index 947dae88f4..0000000000 --- a/core/vm/jit_util.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -// Parse parses all opcodes from the given code byte slice. This function -// performs no error checking and may return non-existing opcodes. -func Parse(code []byte) (opcodes []OpCode) { - for pc := uint64(0); pc < uint64(len(code)); pc++ { - op := OpCode(code[pc]) - - switch op { - case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: - a := uint64(op) - uint64(PUSH1) + 1 - pc += a - opcodes = append(opcodes, PUSH) - case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: - opcodes = append(opcodes, DUP) - case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: - opcodes = append(opcodes, SWAP) - default: - opcodes = append(opcodes, op) - } - } - - return opcodes -} - -// MatchFn searcher for match in the given input and calls matcheFn if it finds -// an appropriate match. matcherFn yields the starting position in the input. -// MatchFn will continue to search for a match until it reaches the end of the -// buffer or if matcherFn return false. -func MatchFn(input, match []OpCode, matcherFn func(int) bool) { - // short circuit if either input or match is empty or if the match is - // greater than the input - if len(input) == 0 || len(match) == 0 || len(match) > len(input) { - return - } - -main: - for i, op := range input[:len(input)+1-len(match)] { - // match first opcode and continue search - if op == match[0] { - for j := 1; j < len(match); j++ { - if input[i+j] != match[j] { - continue main - } - } - // check for abort instruction - if !matcherFn(i) { - return - } - } - } -} diff --git a/core/vm/jit_util_test.go b/core/vm/jit_util_test.go deleted file mode 100644 index 2123efe59e..0000000000 --- a/core/vm/jit_util_test.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -import "testing" - -type matchTest struct { - input []OpCode - match []OpCode - matches int -} - -func TestMatchFn(t *testing.T) { - tests := []matchTest{ - matchTest{ - []OpCode{PUSH1, PUSH1, MSTORE, JUMP}, - []OpCode{PUSH1, MSTORE}, - 1, - }, - matchTest{ - []OpCode{PUSH1, PUSH1, MSTORE, JUMP}, - []OpCode{PUSH1, MSTORE, PUSH1}, - 0, - }, - matchTest{ - []OpCode{}, - []OpCode{PUSH1}, - 0, - }, - } - - for i, test := range tests { - var matchCount int - MatchFn(test.input, test.match, func(i int) bool { - matchCount++ - return true - }) - if matchCount != test.matches { - t.Errorf("match count failed on test[%d]: expected %d matches, got %d", i, test.matches, matchCount) - } - } -} - -type parseTest struct { - base OpCode - size int - output OpCode -} - -func TestParser(t *testing.T) { - tests := []parseTest{ - parseTest{PUSH1, 32, PUSH}, - parseTest{DUP1, 16, DUP}, - parseTest{SWAP1, 16, SWAP}, - parseTest{MSTORE, 1, MSTORE}, - } - - for _, test := range tests { - for i := 0; i < test.size; i++ { - code := append([]byte{byte(byte(test.base) + byte(i))}, make([]byte, i+1)...) - output := Parse(code) - if len(output) == 0 { - t.Fatal("empty output") - } - if output[0] != test.output { - t.Errorf("%v failed: expected %v but got %v", test.base+OpCode(i), test.output, output[0]) - } - } - } -} diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index c6f234e6ea..c388572239 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -22,152 +22,838 @@ import ( "github.com/ubiq/go-ubiq/params" ) -type jumpPtr struct { - fn instrFn +type ( + executionFunc func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) + gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, *big.Int) *big.Int + stackValidationFunc func(*Stack) error + memorySizeFunc func(*Stack) *big.Int +) + +type operation struct { + // op is the operation function + execute executionFunc + // gasCost is the gas function and returns the gas required for execution + gasCost gasFunc + // validateStack validates the stack (size) for the operation + validateStack stackValidationFunc + // memorySize returns the memory size required for the operation + memorySize memorySizeFunc + // halts indicates whether the operation shoult halt further execution + // and return + halts bool + // jumps indicates whether operation made a jump. This prevents the program + // counter from further incrementing. + jumps bool + // valid is used to check whether the retrieved operation is valid and known valid bool } -type vmJumpTable [256]jumpPtr +var defaultJumpTable = NewJumpTable() -func newJumpTable(ruleset *params.ChainConfig, blockNumber *big.Int) vmJumpTable { - var jumpTable vmJumpTable +func NewJumpTable() [256]operation { + return [256]operation{ + ADD: { + execute: opAdd, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + SUB: { + execute: opSub, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + MUL: { + execute: opMul, + gasCost: constGasFunc(GasFastStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + DIV: { + execute: opDiv, + gasCost: constGasFunc(GasFastStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + SDIV: { + execute: opSdiv, + gasCost: constGasFunc(GasFastStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + MOD: { + execute: opMod, + gasCost: constGasFunc(GasFastStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + SMOD: { + execute: opSmod, + gasCost: constGasFunc(GasFastStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + EXP: { + execute: opExp, + gasCost: gasExp, + validateStack: makeStackFunc(2, 1), + valid: true, + }, + SIGNEXTEND: { + execute: opSignExtend, + gasCost: constGasFunc(GasFastStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + NOT: { + execute: opNot, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(1, 1), + valid: true, + }, + LT: { + execute: opLt, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + GT: { + execute: opGt, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + SLT: { + execute: opSlt, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + SGT: { + execute: opSgt, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + EQ: { + execute: opEq, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + ISZERO: { + execute: opIszero, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(1, 1), + valid: true, + }, + AND: { + execute: opAnd, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + OR: { + execute: opOr, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + XOR: { + execute: opXor, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + BYTE: { + execute: opByte, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 1), + valid: true, + }, + ADDMOD: { + execute: opAddmod, + gasCost: constGasFunc(GasMidStep), + validateStack: makeStackFunc(3, 1), + valid: true, + }, + MULMOD: { + execute: opMulmod, + gasCost: constGasFunc(GasMidStep), + validateStack: makeStackFunc(3, 1), + valid: true, + }, + SHA3: { + execute: opSha3, + gasCost: gasSha3, + validateStack: makeStackFunc(2, 1), + memorySize: memorySha3, + valid: true, + }, + ADDRESS: { + execute: opAddress, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + BALANCE: { + execute: opBalance, + gasCost: gasBalance, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + ORIGIN: { + execute: opOrigin, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + CALLER: { + execute: opCaller, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + CALLVALUE: { + execute: opCallValue, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + CALLDATALOAD: { + execute: opCalldataLoad, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(1, 1), + valid: true, + }, + CALLDATASIZE: { + execute: opCalldataSize, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + CALLDATACOPY: { + execute: opCalldataCopy, + gasCost: gasCalldataCopy, + validateStack: makeStackFunc(3, 1), + memorySize: memoryCalldataCopy, + valid: true, + }, + CODESIZE: { + execute: opCodeSize, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + EXTCODESIZE: { + execute: opExtCodeSize, + gasCost: gasExtCodeSize, + validateStack: makeStackFunc(1, 1), + valid: true, + }, + CODECOPY: { + execute: opCodeCopy, + gasCost: gasCodeCopy, + validateStack: makeStackFunc(3, 0), + memorySize: memoryCodeCopy, + valid: true, + }, + EXTCODECOPY: { + execute: opExtCodeCopy, + gasCost: gasExtCodeCopy, + validateStack: makeStackFunc(4, 0), + memorySize: memoryExtCodeCopy, + valid: true, + }, + GASPRICE: { + execute: opGasprice, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + BLOCKHASH: { + execute: opBlockhash, + gasCost: constGasFunc(GasExtStep), + validateStack: makeStackFunc(1, 1), + valid: true, + }, + COINBASE: { + execute: opCoinbase, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + TIMESTAMP: { + execute: opTimestamp, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + NUMBER: { + execute: opNumber, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + DIFFICULTY: { + execute: opDifficulty, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + GASLIMIT: { + execute: opGasLimit, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + POP: { + execute: opPop, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(1, 0), + valid: true, + }, + MLOAD: { + execute: opMload, + gasCost: gasMLoad, + validateStack: makeStackFunc(1, 1), + memorySize: memoryMLoad, + valid: true, + }, + MSTORE: { + execute: opMstore, + gasCost: gasMStore, + validateStack: makeStackFunc(2, 0), + memorySize: memoryMStore, + valid: true, + }, + MSTORE8: { + execute: opMstore8, + gasCost: gasMStore8, + memorySize: memoryMStore8, + validateStack: makeStackFunc(2, 0), - // when initialising a new VM execution we must first check the homestead - // changes. - if ruleset.IsHomestead(blockNumber) { - jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true} + valid: true, + }, + SLOAD: { + execute: opSload, + gasCost: gasSLoad, + validateStack: makeStackFunc(1, 1), + valid: true, + }, + SSTORE: { + execute: opSstore, + gasCost: gasSStore, + validateStack: makeStackFunc(2, 0), + valid: true, + }, + JUMPDEST: { + execute: opJumpdest, + gasCost: constGasFunc(params.JumpdestGas), + validateStack: makeStackFunc(0, 0), + valid: true, + }, + PC: { + execute: opPc, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + MSIZE: { + execute: opMsize, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + GAS: { + execute: opGas, + gasCost: constGasFunc(GasQuickStep), + validateStack: makeStackFunc(0, 1), + valid: true, + }, + CREATE: { + execute: opCreate, + gasCost: gasCreate, + validateStack: makeStackFunc(3, 1), + memorySize: memoryCreate, + valid: true, + }, + CALL: { + execute: opCall, + gasCost: gasCall, + validateStack: makeStackFunc(7, 1), + memorySize: memoryCall, + valid: true, + }, + CALLCODE: { + execute: opCallCode, + gasCost: gasCallCode, + validateStack: makeStackFunc(7, 1), + memorySize: memoryCall, + valid: true, + }, + DELEGATECALL: { + execute: opDelegateCall, + gasCost: gasDelegateCall, + validateStack: makeStackFunc(6, 1), + memorySize: memoryDelegateCall, + valid: true, + }, + RETURN: { + execute: opReturn, + gasCost: gasReturn, + validateStack: makeStackFunc(2, 0), + memorySize: memoryReturn, + halts: true, + valid: true, + }, + SUICIDE: { + execute: opSuicide, + gasCost: gasSuicide, + validateStack: makeStackFunc(1, 0), + halts: true, + valid: true, + }, + JUMP: { + execute: opJump, + gasCost: constGasFunc(GasMidStep), + validateStack: makeStackFunc(1, 0), + jumps: true, + valid: true, + }, + JUMPI: { + execute: opJumpi, + gasCost: constGasFunc(GasSlowStep), + validateStack: makeStackFunc(2, 0), + jumps: true, + valid: true, + }, + STOP: { + execute: opStop, + gasCost: constGasFunc(Zero), + validateStack: makeStackFunc(0, 0), + halts: true, + valid: true, + }, + LOG0: { + execute: makeLog(0), + gasCost: makeGasLog(0), + validateStack: makeStackFunc(2, 0), + memorySize: memoryLog, + valid: true, + }, + LOG1: { + execute: makeLog(1), + gasCost: makeGasLog(1), + validateStack: makeStackFunc(3, 0), + memorySize: memoryLog, + valid: true, + }, + LOG2: { + execute: makeLog(2), + gasCost: makeGasLog(2), + validateStack: makeStackFunc(4, 0), + memorySize: memoryLog, + valid: true, + }, + LOG3: { + execute: makeLog(3), + gasCost: makeGasLog(3), + validateStack: makeStackFunc(5, 0), + memorySize: memoryLog, + valid: true, + }, + LOG4: { + execute: makeLog(4), + gasCost: makeGasLog(4), + validateStack: makeStackFunc(6, 0), + memorySize: memoryLog, + valid: true, + }, + SWAP1: { + execute: makeSwap(1), + gasCost: gasSwap, + validateStack: makeStackFunc(2, 0), + valid: true, + }, + SWAP2: { + execute: makeSwap(2), + gasCost: gasSwap, + validateStack: makeStackFunc(3, 0), + valid: true, + }, + SWAP3: { + execute: makeSwap(3), + gasCost: gasSwap, + validateStack: makeStackFunc(4, 0), + valid: true, + }, + SWAP4: { + execute: makeSwap(4), + gasCost: gasSwap, + validateStack: makeStackFunc(5, 0), + valid: true, + }, + SWAP5: { + execute: makeSwap(5), + gasCost: gasSwap, + validateStack: makeStackFunc(6, 0), + valid: true, + }, + SWAP6: { + execute: makeSwap(6), + gasCost: gasSwap, + validateStack: makeStackFunc(7, 0), + valid: true, + }, + SWAP7: { + execute: makeSwap(7), + gasCost: gasSwap, + validateStack: makeStackFunc(8, 0), + valid: true, + }, + SWAP8: { + execute: makeSwap(8), + gasCost: gasSwap, + validateStack: makeStackFunc(9, 0), + valid: true, + }, + SWAP9: { + execute: makeSwap(9), + gasCost: gasSwap, + validateStack: makeStackFunc(10, 0), + valid: true, + }, + SWAP10: { + execute: makeSwap(10), + gasCost: gasSwap, + validateStack: makeStackFunc(11, 0), + valid: true, + }, + SWAP11: { + execute: makeSwap(11), + gasCost: gasSwap, + validateStack: makeStackFunc(12, 0), + valid: true, + }, + SWAP12: { + execute: makeSwap(12), + gasCost: gasSwap, + validateStack: makeStackFunc(13, 0), + valid: true, + }, + SWAP13: { + execute: makeSwap(13), + gasCost: gasSwap, + validateStack: makeStackFunc(14, 0), + valid: true, + }, + SWAP14: { + execute: makeSwap(14), + gasCost: gasSwap, + validateStack: makeStackFunc(15, 0), + valid: true, + }, + SWAP15: { + execute: makeSwap(15), + gasCost: gasSwap, + validateStack: makeStackFunc(16, 0), + valid: true, + }, + SWAP16: { + execute: makeSwap(16), + gasCost: gasSwap, + validateStack: makeStackFunc(17, 0), + valid: true, + }, + PUSH1: { + execute: makePush(1, big.NewInt(1)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH2: { + execute: makePush(2, big.NewInt(2)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH3: { + execute: makePush(3, big.NewInt(3)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH4: { + execute: makePush(4, big.NewInt(4)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH5: { + execute: makePush(5, big.NewInt(5)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH6: { + execute: makePush(6, big.NewInt(6)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH7: { + execute: makePush(7, big.NewInt(7)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH8: { + execute: makePush(8, big.NewInt(8)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH9: { + execute: makePush(9, big.NewInt(9)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH10: { + execute: makePush(10, big.NewInt(10)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH11: { + execute: makePush(11, big.NewInt(11)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH12: { + execute: makePush(12, big.NewInt(12)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH13: { + execute: makePush(13, big.NewInt(13)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH14: { + execute: makePush(14, big.NewInt(14)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH15: { + execute: makePush(15, big.NewInt(15)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH16: { + execute: makePush(16, big.NewInt(16)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH17: { + execute: makePush(17, big.NewInt(17)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH18: { + execute: makePush(18, big.NewInt(18)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH19: { + execute: makePush(19, big.NewInt(19)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH20: { + execute: makePush(20, big.NewInt(20)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH21: { + execute: makePush(21, big.NewInt(21)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH22: { + execute: makePush(22, big.NewInt(22)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH23: { + execute: makePush(23, big.NewInt(23)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH24: { + execute: makePush(24, big.NewInt(24)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH25: { + execute: makePush(25, big.NewInt(25)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH26: { + execute: makePush(26, big.NewInt(26)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH27: { + execute: makePush(27, big.NewInt(27)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH28: { + execute: makePush(28, big.NewInt(28)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH29: { + execute: makePush(29, big.NewInt(29)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH30: { + execute: makePush(30, big.NewInt(30)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH31: { + execute: makePush(31, big.NewInt(31)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + PUSH32: { + execute: makePush(32, big.NewInt(32)), + gasCost: gasPush, + validateStack: makeStackFunc(0, 1), + valid: true, + }, + DUP1: { + execute: makeDup(1), + gasCost: gasDup, + validateStack: makeStackFunc(1, 1), + valid: true, + }, + DUP2: { + execute: makeDup(2), + gasCost: gasDup, + validateStack: makeStackFunc(2, 1), + valid: true, + }, + DUP3: { + execute: makeDup(3), + gasCost: gasDup, + validateStack: makeStackFunc(3, 1), + valid: true, + }, + DUP4: { + execute: makeDup(4), + gasCost: gasDup, + validateStack: makeStackFunc(4, 1), + valid: true, + }, + DUP5: { + execute: makeDup(5), + gasCost: gasDup, + validateStack: makeStackFunc(5, 1), + valid: true, + }, + DUP6: { + execute: makeDup(6), + gasCost: gasDup, + validateStack: makeStackFunc(6, 1), + valid: true, + }, + DUP7: { + execute: makeDup(7), + gasCost: gasDup, + validateStack: makeStackFunc(7, 1), + valid: true, + }, + DUP8: { + execute: makeDup(8), + gasCost: gasDup, + validateStack: makeStackFunc(8, 1), + valid: true, + }, + DUP9: { + execute: makeDup(9), + gasCost: gasDup, + validateStack: makeStackFunc(9, 1), + valid: true, + }, + DUP10: { + execute: makeDup(10), + gasCost: gasDup, + validateStack: makeStackFunc(10, 1), + valid: true, + }, + DUP11: { + execute: makeDup(11), + gasCost: gasDup, + validateStack: makeStackFunc(11, 1), + valid: true, + }, + DUP12: { + execute: makeDup(12), + gasCost: gasDup, + validateStack: makeStackFunc(12, 1), + valid: true, + }, + DUP13: { + execute: makeDup(13), + gasCost: gasDup, + validateStack: makeStackFunc(13, 1), + valid: true, + }, + DUP14: { + execute: makeDup(14), + gasCost: gasDup, + validateStack: makeStackFunc(14, 1), + valid: true, + }, + DUP15: { + execute: makeDup(15), + gasCost: gasDup, + validateStack: makeStackFunc(15, 1), + valid: true, + }, + DUP16: { + execute: makeDup(16), + gasCost: gasDup, + validateStack: makeStackFunc(16, 1), + valid: true, + }, } - - jumpTable[ADD] = jumpPtr{opAdd, true} - jumpTable[SUB] = jumpPtr{opSub, true} - jumpTable[MUL] = jumpPtr{opMul, true} - jumpTable[DIV] = jumpPtr{opDiv, true} - jumpTable[SDIV] = jumpPtr{opSdiv, true} - jumpTable[MOD] = jumpPtr{opMod, true} - jumpTable[SMOD] = jumpPtr{opSmod, true} - jumpTable[EXP] = jumpPtr{opExp, true} - jumpTable[SIGNEXTEND] = jumpPtr{opSignExtend, true} - jumpTable[NOT] = jumpPtr{opNot, true} - jumpTable[LT] = jumpPtr{opLt, true} - jumpTable[GT] = jumpPtr{opGt, true} - jumpTable[SLT] = jumpPtr{opSlt, true} - jumpTable[SGT] = jumpPtr{opSgt, true} - jumpTable[EQ] = jumpPtr{opEq, true} - jumpTable[ISZERO] = jumpPtr{opIszero, true} - jumpTable[AND] = jumpPtr{opAnd, true} - jumpTable[OR] = jumpPtr{opOr, true} - jumpTable[XOR] = jumpPtr{opXor, true} - jumpTable[BYTE] = jumpPtr{opByte, true} - jumpTable[ADDMOD] = jumpPtr{opAddmod, true} - jumpTable[MULMOD] = jumpPtr{opMulmod, true} - jumpTable[SHA3] = jumpPtr{opSha3, true} - jumpTable[ADDRESS] = jumpPtr{opAddress, true} - jumpTable[BALANCE] = jumpPtr{opBalance, true} - jumpTable[ORIGIN] = jumpPtr{opOrigin, true} - jumpTable[CALLER] = jumpPtr{opCaller, true} - jumpTable[CALLVALUE] = jumpPtr{opCallValue, true} - jumpTable[CALLDATALOAD] = jumpPtr{opCalldataLoad, true} - jumpTable[CALLDATASIZE] = jumpPtr{opCalldataSize, true} - jumpTable[CALLDATACOPY] = jumpPtr{opCalldataCopy, true} - jumpTable[CODESIZE] = jumpPtr{opCodeSize, true} - jumpTable[EXTCODESIZE] = jumpPtr{opExtCodeSize, true} - jumpTable[CODECOPY] = jumpPtr{opCodeCopy, true} - jumpTable[EXTCODECOPY] = jumpPtr{opExtCodeCopy, true} - jumpTable[GASPRICE] = jumpPtr{opGasprice, true} - jumpTable[BLOCKHASH] = jumpPtr{opBlockhash, true} - jumpTable[COINBASE] = jumpPtr{opCoinbase, true} - jumpTable[TIMESTAMP] = jumpPtr{opTimestamp, true} - jumpTable[NUMBER] = jumpPtr{opNumber, true} - jumpTable[DIFFICULTY] = jumpPtr{opDifficulty, true} - jumpTable[GASLIMIT] = jumpPtr{opGasLimit, true} - jumpTable[POP] = jumpPtr{opPop, true} - jumpTable[MLOAD] = jumpPtr{opMload, true} - jumpTable[MSTORE] = jumpPtr{opMstore, true} - jumpTable[MSTORE8] = jumpPtr{opMstore8, true} - jumpTable[SLOAD] = jumpPtr{opSload, true} - jumpTable[SSTORE] = jumpPtr{opSstore, true} - jumpTable[JUMPDEST] = jumpPtr{opJumpdest, true} - jumpTable[PC] = jumpPtr{nil, true} - jumpTable[MSIZE] = jumpPtr{opMsize, true} - jumpTable[GAS] = jumpPtr{opGas, true} - jumpTable[CREATE] = jumpPtr{opCreate, true} - jumpTable[CALL] = jumpPtr{opCall, true} - jumpTable[CALLCODE] = jumpPtr{opCallCode, true} - jumpTable[LOG0] = jumpPtr{makeLog(0), true} - jumpTable[LOG1] = jumpPtr{makeLog(1), true} - jumpTable[LOG2] = jumpPtr{makeLog(2), true} - jumpTable[LOG3] = jumpPtr{makeLog(3), true} - jumpTable[LOG4] = jumpPtr{makeLog(4), true} - jumpTable[SWAP1] = jumpPtr{makeSwap(1), true} - jumpTable[SWAP2] = jumpPtr{makeSwap(2), true} - jumpTable[SWAP3] = jumpPtr{makeSwap(3), true} - jumpTable[SWAP4] = jumpPtr{makeSwap(4), true} - jumpTable[SWAP5] = jumpPtr{makeSwap(5), true} - jumpTable[SWAP6] = jumpPtr{makeSwap(6), true} - jumpTable[SWAP7] = jumpPtr{makeSwap(7), true} - jumpTable[SWAP8] = jumpPtr{makeSwap(8), true} - jumpTable[SWAP9] = jumpPtr{makeSwap(9), true} - jumpTable[SWAP10] = jumpPtr{makeSwap(10), true} - jumpTable[SWAP11] = jumpPtr{makeSwap(11), true} - jumpTable[SWAP12] = jumpPtr{makeSwap(12), true} - jumpTable[SWAP13] = jumpPtr{makeSwap(13), true} - jumpTable[SWAP14] = jumpPtr{makeSwap(14), true} - jumpTable[SWAP15] = jumpPtr{makeSwap(15), true} - jumpTable[SWAP16] = jumpPtr{makeSwap(16), true} - jumpTable[PUSH1] = jumpPtr{makePush(1, big.NewInt(1)), true} - jumpTable[PUSH2] = jumpPtr{makePush(2, big.NewInt(2)), true} - jumpTable[PUSH3] = jumpPtr{makePush(3, big.NewInt(3)), true} - jumpTable[PUSH4] = jumpPtr{makePush(4, big.NewInt(4)), true} - jumpTable[PUSH5] = jumpPtr{makePush(5, big.NewInt(5)), true} - jumpTable[PUSH6] = jumpPtr{makePush(6, big.NewInt(6)), true} - jumpTable[PUSH7] = jumpPtr{makePush(7, big.NewInt(7)), true} - jumpTable[PUSH8] = jumpPtr{makePush(8, big.NewInt(8)), true} - jumpTable[PUSH9] = jumpPtr{makePush(9, big.NewInt(9)), true} - jumpTable[PUSH10] = jumpPtr{makePush(10, big.NewInt(10)), true} - jumpTable[PUSH11] = jumpPtr{makePush(11, big.NewInt(11)), true} - jumpTable[PUSH12] = jumpPtr{makePush(12, big.NewInt(12)), true} - jumpTable[PUSH13] = jumpPtr{makePush(13, big.NewInt(13)), true} - jumpTable[PUSH14] = jumpPtr{makePush(14, big.NewInt(14)), true} - jumpTable[PUSH15] = jumpPtr{makePush(15, big.NewInt(15)), true} - jumpTable[PUSH16] = jumpPtr{makePush(16, big.NewInt(16)), true} - jumpTable[PUSH17] = jumpPtr{makePush(17, big.NewInt(17)), true} - jumpTable[PUSH18] = jumpPtr{makePush(18, big.NewInt(18)), true} - jumpTable[PUSH19] = jumpPtr{makePush(19, big.NewInt(19)), true} - jumpTable[PUSH20] = jumpPtr{makePush(20, big.NewInt(20)), true} - jumpTable[PUSH21] = jumpPtr{makePush(21, big.NewInt(21)), true} - jumpTable[PUSH22] = jumpPtr{makePush(22, big.NewInt(22)), true} - jumpTable[PUSH23] = jumpPtr{makePush(23, big.NewInt(23)), true} - jumpTable[PUSH24] = jumpPtr{makePush(24, big.NewInt(24)), true} - jumpTable[PUSH25] = jumpPtr{makePush(25, big.NewInt(25)), true} - jumpTable[PUSH26] = jumpPtr{makePush(26, big.NewInt(26)), true} - jumpTable[PUSH27] = jumpPtr{makePush(27, big.NewInt(27)), true} - jumpTable[PUSH28] = jumpPtr{makePush(28, big.NewInt(28)), true} - jumpTable[PUSH29] = jumpPtr{makePush(29, big.NewInt(29)), true} - jumpTable[PUSH30] = jumpPtr{makePush(30, big.NewInt(30)), true} - jumpTable[PUSH31] = jumpPtr{makePush(31, big.NewInt(31)), true} - jumpTable[PUSH32] = jumpPtr{makePush(32, big.NewInt(32)), true} - jumpTable[DUP1] = jumpPtr{makeDup(1), true} - jumpTable[DUP2] = jumpPtr{makeDup(2), true} - jumpTable[DUP3] = jumpPtr{makeDup(3), true} - jumpTable[DUP4] = jumpPtr{makeDup(4), true} - jumpTable[DUP5] = jumpPtr{makeDup(5), true} - jumpTable[DUP6] = jumpPtr{makeDup(6), true} - jumpTable[DUP7] = jumpPtr{makeDup(7), true} - jumpTable[DUP8] = jumpPtr{makeDup(8), true} - jumpTable[DUP9] = jumpPtr{makeDup(9), true} - jumpTable[DUP10] = jumpPtr{makeDup(10), true} - jumpTable[DUP11] = jumpPtr{makeDup(11), true} - jumpTable[DUP12] = jumpPtr{makeDup(12), true} - jumpTable[DUP13] = jumpPtr{makeDup(13), true} - jumpTable[DUP14] = jumpPtr{makeDup(14), true} - jumpTable[DUP15] = jumpPtr{makeDup(15), true} - jumpTable[DUP16] = jumpPtr{makeDup(16), true} - - jumpTable[RETURN] = jumpPtr{nil, true} - jumpTable[SUICIDE] = jumpPtr{nil, true} - jumpTable[JUMP] = jumpPtr{nil, true} - jumpTable[JUMPI] = jumpPtr{nil, true} - jumpTable[STOP] = jumpPtr{nil, true} - - return jumpTable } diff --git a/core/vm/log.go b/core/vm/log.go deleted file mode 100644 index 014f222bf7..0000000000 --- a/core/vm/log.go +++ /dev/null @@ -1,126 +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 . - -package vm - -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 (don't reorder!). - 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 -} - -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"` -} - -func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log { - return &Log{Address: address, Topics: topics, Data: data, BlockNumber: number} -} - -func (l *Log) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, []interface{}{l.Address, l.Topics, l.Data}) -} - -func (l *Log) DecodeRLP(s *rlp.Stream) error { - var log struct { - Address common.Address - Topics []common.Hash - Data []byte - } - if err := s.Decode(&log); err != nil { - return err - } - l.Address, l.Topics, l.Data = log.Address, log.Topics, log.Data - return nil -} - -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 (r *Log) MarshalJSON() ([]byte, error) { - return json.Marshal(&jsonLog{ - Address: &r.Address, - Topics: &r.Topics, - Data: (*hexutil.Bytes)(&r.Data), - BlockNumber: (*hexutil.Uint64)(&r.BlockNumber), - TxIndex: (*hexutil.Uint)(&r.TxIndex), - TxHash: &r.TxHash, - BlockHash: &r.BlockHash, - Index: (*hexutil.Uint)(&r.Index), - }) -} - -// UnmarshalJSON implements json.Umarshaler. -func (r *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.BlockNumber == nil || - dec.TxIndex == nil || dec.TxHash == nil || dec.BlockHash == nil || dec.Index == nil { - return errMissingLogFields - } - *r = Log{ - Address: *dec.Address, - Topics: *dec.Topics, - Data: *dec.Data, - BlockNumber: uint64(*dec.BlockNumber), - TxHash: *dec.TxHash, - TxIndex: uint(*dec.TxIndex), - BlockHash: *dec.BlockHash, - Index: uint(*dec.Index), - } - return nil -} - -type Logs []*Log - -// LogForStorage is a wrapper around a Log that flattens and parses the entire -// content of a log, as opposed to only the consensus fields originally (by hiding -// the rlp interface methods). -type LogForStorage Log diff --git a/core/vm/log_test.go b/core/vm/log_test.go deleted file mode 100644 index 4d31895580..0000000000 --- a/core/vm/log_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -import ( - "encoding/json" - "testing" -) - -var unmarshalLogTests = map[string]struct { - input string - wantError error -}{ - "ok": { - input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`, - }, - "empty data": { - input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`, - }, - "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) { - for name, test := range unmarshalLogTests { - var log *Log - err := json.Unmarshal([]byte(test.input), &log) - checkError(t, name, err, test.wantError) - } -} - -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 -} diff --git a/core/vm/logger.go b/core/vm/logger.go index 1df003bc7e..db207109fa 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -45,7 +45,7 @@ type LogConfig struct { Limit int // maximum length of output, but zero means unlimited } -// StructLog is emitted to the Environment each cycle and lists information about the current internal state +// StructLog is emitted to the EVM each cycle and lists information about the current internal state // prior to the execution of the statement. type StructLog struct { Pc uint64 @@ -65,7 +65,7 @@ type StructLog struct { // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. type Tracer interface { - CaptureState(env Environment, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error + CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error } // StructLogger is an EVM state logger and implements Tracer. @@ -94,10 +94,10 @@ func NewStructLogger(cfg *LogConfig) *StructLogger { // captureState logs a new structured log message and pushes it out to the environment // // captureState also tracks SSTORE ops to track dirty values. -func (l *StructLogger) CaptureState(env Environment, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { +func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { // check if already accumulated the specified number of logs if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { - return TraceLimitReachedError + return ErrTraceLimitReached } // initialise new changed values storage container for this contract @@ -144,7 +144,7 @@ func (l *StructLogger) CaptureState(env Environment, pc uint64, op OpCode, gas, storage = make(Storage) // Get the contract account and loop over each storage entry. This may involve looping over // the trie and is a very expensive process. - env.Db().GetAccount(contract.Address()).ForEachStorage(func(key, value common.Hash) bool { + env.StateDB.GetAccount(contract.Address()).ForEachStorage(func(key, value common.Hash) bool { storage[key] = value // Return true, indicating we'd like to continue. return true @@ -155,7 +155,7 @@ func (l *StructLogger) CaptureState(env Environment, pc uint64, op OpCode, gas, } } // create a new snaptshot of the EVM. - log := StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, env.Depth(), err} + log := StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, env.depth, err} l.logs = append(l.logs, log) return nil diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 2f61841720..a5d7f233d4 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -21,16 +21,17 @@ import ( "testing" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/params" ) type dummyContractRef struct { calledForEach bool } -func (dummyContractRef) ReturnGas(*big.Int, *big.Int) {} -func (dummyContractRef) Address() common.Address { return common.Address{} } -func (dummyContractRef) Value() *big.Int { return new(big.Int) } -func (dummyContractRef) SetCode(common.Hash, []byte) {} +func (dummyContractRef) ReturnGas(*big.Int) {} +func (dummyContractRef) Address() common.Address { return common.Address{} } +func (dummyContractRef) Value() *big.Int { return new(big.Int) } +func (dummyContractRef) SetCode(common.Hash, []byte) {} func (d *dummyContractRef) ForEachStorage(callback func(key, value common.Hash) bool) { d.calledForEach = true } @@ -40,28 +41,22 @@ func (d *dummyContractRef) SetBalance(*big.Int) {} func (d *dummyContractRef) SetNonce(uint64) {} func (d *dummyContractRef) Balance() *big.Int { return new(big.Int) } -type dummyEnv struct { - *Env +type dummyStateDB struct { + NoopStateDB ref *dummyContractRef } -func newDummyEnv(ref *dummyContractRef) *dummyEnv { - return &dummyEnv{ - Env: NewEnv(&Config{EnableJit: false, ForceJit: false}), - ref: ref, - } -} -func (d dummyEnv) GetAccount(common.Address) Account { +func (d dummyStateDB) GetAccount(common.Address) Account { return d.ref } func TestStoreCapture(t *testing.T) { var ( - env = NewEnv(&Config{EnableJit: false, ForceJit: false}) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) logger = NewStructLogger(nil) mem = NewMemory() stack = newstack() - contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), new(big.Int), new(big.Int)) + contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), new(big.Int)) ) stack.push(big.NewInt(1)) stack.push(big.NewInt(0)) @@ -83,8 +78,8 @@ func TestStorageCapture(t *testing.T) { t.Skip("implementing this function is difficult. it requires all sort of interfaces to be implemented which isn't trivial. The value (the actual test) isn't worth it") var ( ref = &dummyContractRef{} - contract = NewContract(ref, ref, new(big.Int), new(big.Int), new(big.Int)) - env = newDummyEnv(ref) + contract = NewContract(ref, ref, new(big.Int), new(big.Int)) + env = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) logger = NewStructLogger(nil) mem = NewMemory() stack = newstack() diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go new file mode 100644 index 0000000000..2116001d7a --- /dev/null +++ b/core/vm/memory_table.go @@ -0,0 +1,68 @@ +package vm + +import ( + "math/big" + + "github.com/ubiq/go-ubiq/common" +) + +func memorySha3(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(1)) +} + +func memoryCalldataCopy(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(2)) +} + +func memoryCodeCopy(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(2)) +} + +func memoryExtCodeCopy(stack *Stack) *big.Int { + return calcMemSize(stack.Back(1), stack.Back(3)) +} + +func memoryMLoad(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), big.NewInt(32)) +} + +func memoryMStore8(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), big.NewInt(1)) +} + +func memoryMStore(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), big.NewInt(32)) +} + +func memoryCreate(stack *Stack) *big.Int { + return calcMemSize(stack.Back(1), stack.Back(2)) +} + +func memoryCall(stack *Stack) *big.Int { + x := calcMemSize(stack.Back(5), stack.Back(6)) + y := calcMemSize(stack.Back(3), stack.Back(4)) + + return common.BigMax(x, y) +} + +func memoryCallCode(stack *Stack) *big.Int { + x := calcMemSize(stack.Back(5), stack.Back(6)) + y := calcMemSize(stack.Back(3), stack.Back(4)) + + return common.BigMax(x, y) +} +func memoryDelegateCall(stack *Stack) *big.Int { + x := calcMemSize(stack.Back(4), stack.Back(5)) + y := calcMemSize(stack.Back(2), stack.Back(3)) + + return common.BigMax(x, y) +} + +func memoryReturn(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(1)) +} + +func memoryLog(stack *Stack) *big.Int { + mSize, mStart := stack.Back(1), stack.Back(0) + return calcMemSize(mStart, mSize) +} diff --git a/core/vm/noop.go b/core/vm/noop.go new file mode 100644 index 0000000000..fb3f6dd73d --- /dev/null +++ b/core/vm/noop.go @@ -0,0 +1,69 @@ +// 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 . + +package vm + +import ( + "math/big" + + "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/core/types" +) + +func NoopCanTransfer(db StateDB, from common.Address, balance *big.Int) bool { + return true +} +func NoopTransfer(db StateDB, from, to common.Address, amount *big.Int) {} + +type NoopEVMCallContext struct{} + +func (NoopEVMCallContext) Call(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) { + return nil, nil +} +func (NoopEVMCallContext) CallCode(caller ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) { + return nil, nil +} +func (NoopEVMCallContext) Create(caller ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) { + return nil, common.Address{}, nil +} +func (NoopEVMCallContext) DelegateCall(me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) { + return nil, nil +} + +type NoopStateDB struct{} + +func (NoopStateDB) GetAccount(common.Address) Account { return nil } +func (NoopStateDB) CreateAccount(common.Address) Account { return nil } +func (NoopStateDB) SubBalance(common.Address, *big.Int) {} +func (NoopStateDB) AddBalance(common.Address, *big.Int) {} +func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil } +func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 } +func (NoopStateDB) SetNonce(common.Address, uint64) {} +func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} } +func (NoopStateDB) GetCode(common.Address) []byte { return nil } +func (NoopStateDB) SetCode(common.Address, []byte) {} +func (NoopStateDB) GetCodeSize(common.Address) int { return 0 } +func (NoopStateDB) AddRefund(*big.Int) {} +func (NoopStateDB) GetRefund() *big.Int { return nil } +func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} } +func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {} +func (NoopStateDB) Suicide(common.Address) bool { return false } +func (NoopStateDB) HasSuicided(common.Address) bool { return false } +func (NoopStateDB) Exist(common.Address) bool { return false } +func (NoopStateDB) Empty(common.Address) bool { return false } +func (NoopStateDB) RevertToSnapshot(int) {} +func (NoopStateDB) Snapshot() int { return 0 } +func (NoopStateDB) AddLog(*types.Log) {} diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 5db661943a..c803cdab98 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -23,92 +23,22 @@ import ( "github.com/ubiq/go-ubiq/core" "github.com/ubiq/go-ubiq/core/state" "github.com/ubiq/go-ubiq/core/vm" - "github.com/ubiq/go-ubiq/params" ) -// Env is a basic runtime environment required for running the EVM. -type Env struct { - chainConfig *params.ChainConfig - depth int - state *state.StateDB +func NewEnv(cfg *Config, state *state.StateDB) *vm.EVM { + context := vm.Context{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + GetHash: func(uint64) common.Hash { return common.Hash{} }, - origin common.Address - coinbase common.Address - - number *big.Int - time *big.Int - difficulty *big.Int - gasLimit *big.Int - - getHashFn func(uint64) common.Hash - - evm *vm.EVM -} - -// NewEnv returns a new vm.Environment -func NewEnv(cfg *Config, state *state.StateDB) vm.Environment { - env := &Env{ - chainConfig: cfg.ChainConfig, - state: state, - origin: cfg.Origin, - coinbase: cfg.Coinbase, - number: cfg.BlockNumber, - time: cfg.Time, - difficulty: cfg.Difficulty, - gasLimit: cfg.GasLimit, + Origin: cfg.Origin, + Coinbase: cfg.Coinbase, + BlockNumber: cfg.BlockNumber, + Time: cfg.Time, + Difficulty: cfg.Difficulty, + GasLimit: cfg.GasLimit, + GasPrice: new(big.Int), } - env.evm = vm.New(env, vm.Config{ - Debug: cfg.Debug, - EnableJit: !cfg.DisableJit, - ForceJit: !cfg.DisableJit, - }) - return env -} - -func (self *Env) ChainConfig() *params.ChainConfig { return self.chainConfig } -func (self *Env) Vm() vm.Vm { return self.evm } -func (self *Env) Origin() common.Address { return self.origin } -func (self *Env) BlockNumber() *big.Int { return self.number } -func (self *Env) Coinbase() common.Address { return self.coinbase } -func (self *Env) Time() *big.Int { return self.time } -func (self *Env) Difficulty() *big.Int { return self.difficulty } -func (self *Env) Db() vm.Database { return self.state } -func (self *Env) GasLimit() *big.Int { return self.gasLimit } -func (self *Env) VmType() vm.Type { return vm.StdVmTy } -func (self *Env) GetHash(n uint64) common.Hash { - return self.getHashFn(n) -} -func (self *Env) AddLog(log *vm.Log) { - self.state.AddLog(log) -} -func (self *Env) Depth() int { return self.depth } -func (self *Env) SetDepth(i int) { self.depth = i } -func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool { - return self.state.GetBalance(from).Cmp(balance) >= 0 -} -func (self *Env) SnapshotDatabase() int { - return self.state.Snapshot() -} -func (self *Env) RevertToSnapshot(snapshot int) { - self.state.RevertToSnapshot(snapshot) -} - -func (self *Env) Transfer(from, to vm.Account, amount *big.Int) { - core.Transfer(from, to, amount) -} - -func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return core.Call(self, caller, addr, data, gas, price, value) -} -func (self *Env) 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 *Env) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - return core.DelegateCall(self, me, addr, data, gas, price) -} - -func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - return core.Create(self, caller, data, gas, price, value) + return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index d6452aa8be..c1c5261439 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -22,19 +22,12 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core/state" + "github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/params" ) -// The default, always homestead, rule set for the vm env -type ruleSet struct{} - -func (ruleSet) IsHomestead(*big.Int) bool { return true } -func (ruleSet) GasTable(*big.Int) params.GasTable { - return params.GasTableHomesteadGasRepriceFork -} - // Config is a basic type specifying certain configuration flags for running // the EVM. type Config struct { @@ -49,6 +42,7 @@ type Config struct { Value *big.Int DisableJit bool // "disable" so it's enabled by default Debug bool + EVMConfig vm.Config State *state.StateDB GetHashFn func(n uint64) common.Hash @@ -121,13 +115,37 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { receiver.Address(), input, cfg.GasLimit, - cfg.GasPrice, cfg.Value, ) return ret, cfg.State, err } +// Create executes the code using the EVM create method +func Create(input []byte, cfg *Config) ([]byte, common.Address, error) { + if cfg == nil { + cfg = new(Config) + } + setDefaults(cfg) + + if cfg.State == nil { + db, _ := ethdb.NewMemDatabase() + cfg.State, _ = state.New(common.Hash{}, db) + } + var ( + vmenv = NewEnv(cfg, cfg.State) + sender = cfg.State.CreateAccount(cfg.Origin) + ) + + // Call the code with the given configuration. + return vmenv.Create( + sender, + input, + cfg.GasLimit, + cfg.Value, + ) +} + // Call executes the code given by the contract's address. It will return the // EVM's return value or an error if it failed. // @@ -145,7 +163,6 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) { address, input, cfg.GasLimit, - cfg.GasPrice, cfg.Value, ) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 0a65ef8ef3..1b281482c8 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -56,7 +56,7 @@ func TestDefaults(t *testing.T) { } } -func TestEnvironment(t *testing.T) { +func TestEVM(t *testing.T) { defer func() { if r := recover(); r != nil { t.Fatalf("crashed with: %v", r) diff --git a/core/vm/segments.go b/core/vm/segments.go deleted file mode 100644 index 648d8a04a1..0000000000 --- a/core/vm/segments.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package vm - -import "math/big" - -type jumpSeg struct { - pos uint64 - err error - gas *big.Int -} - -func (j jumpSeg) do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - if !contract.UseGas(j.gas) { - return nil, OutOfGasError - } - if j.err != nil { - return nil, j.err - } - *pc = j.pos - return nil, nil -} -func (s jumpSeg) halts() bool { return false } -func (s jumpSeg) Op() OpCode { return 0 } - -type pushSeg struct { - data []*big.Int - gas *big.Int -} - -func (s pushSeg) do(program *Program, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // Use the calculated gas. When insufficient gas is present, use all gas and return an - // Out Of Gas error - if !contract.UseGas(s.gas) { - return nil, OutOfGasError - } - - for _, d := range s.data { - stack.push(new(big.Int).Set(d)) - } - *pc += uint64(len(s.data)) - return nil, nil -} - -func (s pushSeg) halts() bool { return false } -func (s pushSeg) Op() OpCode { return 0 } diff --git a/core/vm/stack.go b/core/vm/stack.go index f6c1f76e45..2d1b7bb82d 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -68,6 +68,11 @@ func (st *Stack) peek() *big.Int { return st.data[st.len()-1] } +// Back returns the n'th item in stack +func (st *Stack) Back(n int) *big.Int { + return st.data[st.len()-n-1] +} + func (st *Stack) require(n int) error { if st.len() < n { return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n) diff --git a/core/vm/stack_table.go b/core/vm/stack_table.go new file mode 100644 index 0000000000..5ce3f2c489 --- /dev/null +++ b/core/vm/stack_table.go @@ -0,0 +1,20 @@ +package vm + +import ( + "fmt" + + "github.com/ubiq/go-ubiq/params" +) + +func makeStackFunc(pop, push int) stackValidationFunc { + return func(stack *Stack) error { + if err := stack.require(pop); err != nil { + return err + } + + if push > 0 && int64(stack.len()-pop+push) > params.StackLimit.Int64() { + return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64()) + } + return nil + } +} diff --git a/core/vm/vm.go b/core/vm/vm.go index 64b5418197..0384897aa4 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -19,6 +19,7 @@ package vm import ( "fmt" "math/big" + "sync/atomic" "time" "github.com/ubiq/go-ubiq/common" @@ -28,43 +29,61 @@ import ( "github.com/ubiq/go-ubiq/params" ) -// Config are the configuration options for the EVM +// Config are the configuration options for the Interpreter type Config struct { - Debug bool + // Debug enabled debugging Interpreter options + Debug bool + // EnableJit enabled the JIT VM EnableJit bool - ForceJit bool - Tracer Tracer + // ForceJit forces the JIT VM + ForceJit bool + // Tracer is the op code logger + Tracer Tracer + // NoRecursion disabled Interpreter call, callcode, + // delegate call and create. + NoRecursion bool + // Disable gas metering + DisableGasMetering bool + // JumpTable contains the EVM instruction table. This + // may me left uninitialised and will be set the default + // table. + JumpTable [256]operation } -// EVM is used to run Ethereum based contracts and will utilise the +// Interpreter is used to run Ethereum based contracts and will utilise the // passed environment to query external sources for state information. -// The EVM will run the byte code VM or JIT VM based on the passed +// The Interpreter will run the byte code VM or JIT VM based on the passed // configuration. -type EVM struct { - env Environment - jumpTable vmJumpTable - cfg Config - gasTable params.GasTable +type Interpreter struct { + env *EVM + cfg Config + gasTable params.GasTable } -// New returns a new instance of the EVM. -func New(env Environment, cfg Config) *EVM { - return &EVM{ - env: env, - jumpTable: newJumpTable(env.ChainConfig(), env.BlockNumber()), - cfg: cfg, - gasTable: env.ChainConfig().GasTable(env.BlockNumber()), +// NewInterpreter returns a new instance of the Interpreter. +func NewInterpreter(env *EVM, cfg Config) *Interpreter { + // We use the STOP instruction whether to see + // the jump table was initialised. If it was not + // we'll set the default jump table. + if !cfg.JumpTable[STOP].valid { + cfg.JumpTable = defaultJumpTable + } + + return &Interpreter{ + env: env, + cfg: cfg, + gasTable: env.ChainConfig().GasTable(env.BlockNumber), } } // Run loops and evaluates the contract's code with the given input data -func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { - evm.env.SetDepth(evm.env.Depth() + 1) - defer evm.env.SetDepth(evm.env.Depth() - 1) +func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) { + evm.env.depth++ + defer func() { evm.env.depth-- }() if contract.CodeAddr != nil { - if p := Precompiled[contract.CodeAddr.Str()]; p != nil { - return evm.RunPrecompiled(p, input, contract) + if p := PrecompiledContracts[*contract.CodeAddr]; p != nil { + return RunPrecompiledContract(p, input, contract) } } @@ -77,385 +96,91 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { if codehash == (common.Hash{}) { codehash = crypto.Keccak256Hash(contract.Code) } - var program *Program - if false { - // JIT disabled due to JIT not being Homestead gas reprice ready. - - // If the JIT is enabled check the status of the JIT program, - // if it doesn't exist compile a new program in a separate - // goroutine or wait for compilation to finish if the JIT is - // forced. - switch GetProgramStatus(codehash) { - case progReady: - return RunProgram(GetProgram(codehash), evm.env, contract, input) - case progUnknown: - if evm.cfg.ForceJit { - // Create and compile program - program = NewProgram(contract.Code) - perr := CompileProgram(program) - if perr == nil { - return RunProgram(program, evm.env, contract, input) - } - glog.V(logger.Info).Infoln("error compiling program", err) - } else { - // create and compile the program. Compilation - // is done in a separate goroutine - program = NewProgram(contract.Code) - go func() { - err := CompileProgram(program) - if err != nil { - glog.V(logger.Info).Infoln("error compiling program", err) - return - } - }() - } - } - } var ( - caller = contract.caller - code = contract.Code - instrCount = 0 - - op OpCode // current opcode - mem = NewMemory() // bound memory - stack = newstack() // local stack - statedb = evm.env.Db() // current state + op OpCode // current opcode + mem = NewMemory() // bound memory + stack = newstack() // local stack // For optimisation reason we're using uint64 as the program counter. // It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible. - pc = uint64(0) // program counter - - // jump evaluates and checks whether the given jump destination is a valid one - // if valid move the `pc` otherwise return an error. - jump = func(from uint64, to *big.Int) error { - if !contract.jumpdests.has(codehash, code, to) { - nop := contract.GetOp(to.Uint64()) - return fmt.Errorf("invalid jump destination (%v) %v", nop, to) - } - - pc = to.Uint64() - - return nil - } - - newMemSize *big.Int - cost *big.Int + pc = uint64(0) // program counter + cost *big.Int ) contract.Input = input // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return. defer func() { if err != nil && evm.cfg.Debug { - evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), err) + evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err) } }() if glog.V(logger.Debug) { - glog.Infof("running byte VM %x\n", codehash[:4]) + glog.Infof("evm running: %x\n", codehash[:4]) tstart := time.Now() defer func() { - glog.Infof("byte VM %x done. time: %v instrc: %v\n", codehash[:4], time.Since(tstart), instrCount) + glog.Infof("evm done: %x. time: %v\n", codehash[:4], time.Since(tstart)) }() } - for ; ; instrCount++ { - /* - if EnableJit && it%100 == 0 { - if program != nil && progStatus(atomic.LoadInt32(&program.status)) == progReady { - // move execution - fmt.Println("moved", it) - glog.V(logger.Info).Infoln("Moved execution to JIT") - return runProgram(program, pc, mem, stack, evm.env, contract, input) - } - } - */ - + // The Interpreter main run loop (contextual). This loop runs until either an + // explicit STOP, RETURN or SUICIDE is executed, an error accured during + // the execution of one of the operations or until the evm.done is set by + // the parent context.Context. + for atomic.LoadInt32(&evm.env.abort) == 0 { // Get the memory location of pc op = contract.GetOp(pc) - //fmt.Printf("OP %d %v\n", op, op) - // calculate the new memory size and gas price for the current executing opcode - newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack) - if err != nil { + + // get the operation from the jump table matching the opcode + operation := evm.cfg.JumpTable[op] + + // if the op is invalid abort the process and return an error + if !operation.valid { + return nil, fmt.Errorf("invalid opcode %x", op) + } + + // validate the stack and make sure there enough stack items available + // to perform the operation + if err := operation.validateStack(stack); err != nil { return nil, err } - // Use the calculated gas. When insufficient gas is present, use all gas and return an - // Out Of Gas error - if !contract.UseGas(cost) { - return nil, OutOfGasError + var memorySize *big.Int + // calculate the new memory size and expand the memory to fit + // the operation + if operation.memorySize != nil { + memorySize = operation.memorySize(stack) + // memory is expanded in words of 32 bytes. Gas + // is also calculated in words. + memorySize.Mul(toWordSize(memorySize), big.NewInt(32)) + } + + if !evm.cfg.DisableGasMetering { + // consume the gas and return an error if not enough gas is available. + // cost is explicitly set so that the capture state defer method cas get the proper cost + cost = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize) + if !contract.UseGas(cost) { + return nil, ErrOutOfGas + } + } + if memorySize != nil { + mem.Resize(memorySize.Uint64()) } - // Resize the memory calculated previously - mem.Resize(newMemSize.Uint64()) - // Add a log message if evm.cfg.Debug { - err = evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), nil) - if err != nil { - return nil, err - } + evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err) } - if opPtr := evm.jumpTable[op]; opPtr.valid { - if opPtr.fn != nil { - opPtr.fn(instruction{}, &pc, evm.env, contract, mem, stack) - } else { - switch op { - case PC: - opPc(instruction{data: new(big.Int).SetUint64(pc)}, &pc, evm.env, contract, mem, stack) - case JUMP: - if err := jump(pc, stack.pop()); err != nil { - return nil, err - } - - continue - case JUMPI: - pos, cond := stack.pop(), stack.pop() - - if cond.Cmp(common.BigTrue) >= 0 { - if err := jump(pc, pos); err != nil { - return nil, err - } - - continue - } - case RETURN: - offset, size := stack.pop(), stack.pop() - ret := mem.GetPtr(offset.Int64(), size.Int64()) - - return ret, nil - case SUICIDE: - opSuicide(instruction{}, nil, evm.env, contract, mem, stack) - - fallthrough - case STOP: // Stop the contract - return nil, nil - } - } - } else { - return nil, fmt.Errorf("Invalid opcode %x", op) + // execute the operation + res, err := operation.execute(&pc, evm.env, contract, mem, stack) + switch { + case err != nil: + return nil, err + case operation.halts: + return res, nil + case !operation.jumps: + pc++ } - - pc++ - - } -} - -// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for -// the operation. This does not reduce gas or resizes the memory. -func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) { - var ( - gas = new(big.Int) - newMemSize *big.Int = new(big.Int) - ) - err := baseCheck(op, stack, gas) - if err != nil { - return nil, nil, err - } - - // stack Check, memory resize & gas phase - switch op { - case SUICIDE: - // EIP150 homestead gas reprice fork: - if gasTable.CreateBySuicide != nil { - gas.Set(gasTable.Suicide) - var ( - address = common.BigToAddress(stack.data[len(stack.data)-1]) - eip158 = env.ChainConfig().IsEIP158(env.BlockNumber()) - ) - - if eip158 { - // if empty and transfers value - if env.Db().Empty(address) && statedb.GetBalance(contract.Address()).BitLen() > 0 { - gas.Add(gas, gasTable.CreateBySuicide) - } - } else if !env.Db().Exist(address) { - gas.Add(gas, gasTable.CreateBySuicide) - } - } - - if !statedb.HasSuicided(contract.Address()) { - statedb.AddRefund(params.SuicideRefundGas) - } - case EXTCODESIZE: - gas.Set(gasTable.ExtcodeSize) - case BALANCE: - gas.Set(gasTable.Balance) - case SLOAD: - gas.Set(gasTable.SLoad) - case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: - n := int(op - SWAP1 + 2) - err := stack.require(n) - if err != nil { - return nil, nil, err - } - gas.Set(GasFastestStep) - case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: - n := int(op - DUP1 + 1) - err := stack.require(n) - if err != nil { - return nil, nil, err - } - gas.Set(GasFastestStep) - case LOG0, LOG1, LOG2, LOG3, LOG4: - n := int(op - LOG0) - err := stack.require(n + 2) - if err != nil { - return nil, nil, err - } - - mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] - - gas.Add(gas, params.LogGas) - gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas)) - gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas)) - - newMemSize = calcMemSize(mStart, mSize) - - quadMemGas(mem, newMemSize, gas) - case EXP: - expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8) - gas.Add(gas, new(big.Int).Mul(big.NewInt(expByteLen), gasTable.ExpByte)) - case SSTORE: - err := stack.require(2) - if err != nil { - return nil, nil, err - } - - var g *big.Int - y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] - val := statedb.GetState(contract.Address(), common.BigToHash(x)) - - // This checks for 3 scenario's and calculates gas accordingly - // 1. From a zero-value address to a non-zero value (NEW VALUE) - // 2. From a non-zero value address to a zero-value address (DELETE) - // 3. From a non-zero to a non-zero (CHANGE) - if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { - // 0 => non 0 - g = params.SstoreSetGas - } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { - statedb.AddRefund(params.SstoreRefundGas) - - g = params.SstoreClearGas - } else { - // non 0 => non 0 (or 0 => 0) - g = params.SstoreResetGas - } - gas.Set(g) - case MLOAD: - newMemSize = calcMemSize(stack.peek(), u256(32)) - quadMemGas(mem, newMemSize, gas) - case MSTORE8: - newMemSize = calcMemSize(stack.peek(), u256(1)) - quadMemGas(mem, newMemSize, gas) - case MSTORE: - newMemSize = calcMemSize(stack.peek(), u256(32)) - quadMemGas(mem, newMemSize, gas) - case RETURN: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) - quadMemGas(mem, newMemSize, gas) - case SHA3: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) - - words := toWordSize(stack.data[stack.len()-2]) - gas.Add(gas, words.Mul(words, params.Sha3WordGas)) - - quadMemGas(mem, newMemSize, gas) - case CALLDATACOPY: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) - - words := toWordSize(stack.data[stack.len()-3]) - gas.Add(gas, words.Mul(words, params.CopyGas)) - - quadMemGas(mem, newMemSize, gas) - case CODECOPY: - newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) - - words := toWordSize(stack.data[stack.len()-3]) - gas.Add(gas, words.Mul(words, params.CopyGas)) - - quadMemGas(mem, newMemSize, gas) - case EXTCODECOPY: - gas.Set(gasTable.ExtcodeCopy) - - newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) - - words := toWordSize(stack.data[stack.len()-4]) - gas.Add(gas, words.Mul(words, params.CopyGas)) - - quadMemGas(mem, newMemSize, gas) - case CREATE: - newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) - - quadMemGas(mem, newMemSize, gas) - case CALL, CALLCODE: - gas.Set(gasTable.Calls) - - transfersValue := stack.data[len(stack.data)-3].BitLen() > 0 - if op == CALL { - var ( - address = common.BigToAddress(stack.data[len(stack.data)-2]) - eip158 = env.ChainConfig().IsEIP158(env.BlockNumber()) - ) - if eip158 { - if env.Db().Empty(address) && transfersValue { - gas.Add(gas, params.CallNewAccountGas) - } - } else if !env.Db().Exist(address) { - gas.Add(gas, params.CallNewAccountGas) - } - } - if transfersValue { - gas.Add(gas, params.CallValueTransferGas) - } - x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) - y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5]) - - newMemSize = common.BigMax(x, y) - - quadMemGas(mem, newMemSize, gas) - - cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1]) - // Replace the stack item with the new gas calculation. This means that - // either the original item is left on the stack or the item is replaced by: - // (availableGas - gas) * 63 / 64 - // We replace the stack item so that it's available when the opCall instruction is - // called. This information is otherwise lost due to the dependency on *current* - // available gas. - stack.data[stack.len()-1] = cg - gas.Add(gas, cg) - - case DELEGATECALL: - gas.Set(gasTable.Calls) - - x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6]) - y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4]) - - newMemSize = common.BigMax(x, y) - - quadMemGas(mem, newMemSize, gas) - - cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1]) - // Replace the stack item with the new gas calculation. This means that - // either the original item is left on the stack or the item is replaced by: - // (availableGas - gas) * 63 / 64 - // We replace the stack item so that it's available when the opCall instruction is - // called. - stack.data[stack.len()-1] = cg - gas.Add(gas, cg) - - } - - return newMemSize, gas, nil -} - -// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go -func (evm *EVM) RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Contract) (ret []byte, err error) { - gas := p.Gas(len(input)) - if contract.UseGas(gas) { - ret = p.Call(input) - - return ret, nil - } else { - return nil, OutOfGasError } + return nil, nil } diff --git a/core/vm/vm_jit.go b/core/vm/vm_jit.go index 42590652a9..ae94ec8d04 100644 --- a/core/vm/vm_jit.go +++ b/core/vm/vm_jit.go @@ -44,7 +44,7 @@ import ( ) type JitVm struct { - env Environment + env EVM me ContextRef callerAddr []byte price *big.Int @@ -161,7 +161,7 @@ func assert(condition bool, message string) { } } -func NewJitVm(env Environment) *JitVm { +func NewJitVm(env EVM) *JitVm { return &JitVm{env: env} } @@ -235,7 +235,7 @@ func (self *JitVm) Endl() VirtualMachine { return self } -func (self *JitVm) Env() Environment { +func (self *JitVm) Env() EVM { return self.env } diff --git a/core/vm/vm_jit_fake.go b/core/vm/vm_jit_fake.go index 4fa98ccd9c..44b60abf6f 100644 --- a/core/vm/vm_jit_fake.go +++ b/core/vm/vm_jit_fake.go @@ -17,10 +17,3 @@ // +build !evmjit package vm - -import "fmt" - -func NewJitVm(env Environment) VirtualMachine { - fmt.Printf("Warning! EVM JIT not enabled.\n") - return New(env, Config{}) -} diff --git a/core/vm_env.go b/core/vm_env.go deleted file mode 100644 index a4fb561d41..0000000000 --- a/core/vm_env.go +++ /dev/null @@ -1,118 +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 . - -package core - -import ( - "math/big" - - "github.com/ubiq/go-ubiq/common" - "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/params" -) - -// GetHashFn returns a function for which the VM env can query block hashes through -// up to the limit defined by the Yellow Paper and uses the given block chain -// to query for information. -func GetHashFn(ref common.Hash, chain *BlockChain) func(n uint64) common.Hash { - return func(n uint64) common.Hash { - for block := chain.GetBlockByHash(ref); block != nil; block = chain.GetBlock(block.ParentHash(), block.NumberU64()-1) { - if block.NumberU64() == n { - return block.Hash() - } - } - - return common.Hash{} - } -} - -type VMEnv struct { - chainConfig *params.ChainConfig // Chain configuration - state *state.StateDB // State to use for executing - evm *vm.EVM // The Ethereum Virtual Machine - depth int // Current execution depth - msg Message // Message appliod - - header *types.Header // Header information - chain *BlockChain // Blockchain handle - getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes -} - -func NewEnv(state *state.StateDB, chainConfig *params.ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv { - env := &VMEnv{ - chainConfig: chainConfig, - chain: chain, - state: state, - header: header, - msg: msg, - getHashFn: GetHashFn(header.ParentHash, chain), - } - - env.evm = vm.New(env, cfg) - return env -} - -func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig } -func (self *VMEnv) Vm() vm.Vm { return self.evm } -func (self *VMEnv) Origin() common.Address { return self.msg.From() } -func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } -func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } -func (self *VMEnv) Time() *big.Int { return self.header.Time } -func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty } -func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit } -func (self *VMEnv) Value() *big.Int { return self.msg.Value() } -func (self *VMEnv) Db() vm.Database { return self.state } -func (self *VMEnv) Depth() int { return self.depth } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) GetHash(n uint64) common.Hash { - return self.getHashFn(n) -} - -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) SnapshotDatabase() int { - return self.state.Snapshot() -} - -func (self *VMEnv) RevertToSnapshot(snapshot int) { - self.state.RevertToSnapshot(snapshot) -} - -func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) { - Transfer(from, to, amount) -} - -func (self *VMEnv) Call(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return Call(self, me, addr, data, gas, price, value) -} -func (self *VMEnv) CallCode(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return CallCode(self, me, addr, data, gas, price, value) -} - -func (self *VMEnv) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - return DelegateCall(self, me, addr, data, gas, price) -} - -func (self *VMEnv) Create(me vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - return Create(self, me, data, gas, price, value) -} diff --git a/crypto/crypto.go b/crypto/crypto.go index 7f8c935e2d..e01ed06a4d 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -167,25 +167,19 @@ func GenerateKey() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) } +// ValidateSignatureValues verifies whether the signature values are valid with +// the given chain rules. The v value is assumed to be either 0 or 1. func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool { if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 { return false } - vint := uint32(v) // reject upper range of s values (ECDSA malleability) // see discussion in secp256k1/libsecp256k1/include/secp256k1.h if homestead && s.Cmp(secp256k1.HalfN) > 0 { return false } // Frontier: allow s to be in full N range - if s.Cmp(secp256k1.N) >= 0 { - return false - } - if r.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) { - return true - } else { - return false - } + return r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (v == 0 || v == 1) } func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { @@ -199,14 +193,13 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { } // Sign calculates an ECDSA signature. -// This function is susceptible to choosen plaintext attacks that can leak +// +// This function is susceptible to chosen plaintext attacks that can leak // information about the private key that is used for signing. Callers must -// be aware that the given hash cannot be choosen by an adversery. Common +// be aware that the given hash cannot be chosen by an adversery. Common // solution is to hash any input before calculating the signature. // -// Note: the calculated signature is not Ethereum compliant. The yellow paper -// dictates Ethereum singature to have a V value with and offset of 27 v in [27,28]. -// Use SignEthereum to get an Ethereum compliant signature. +// The produced signature is in the [R || S || V] format where V is 0 or 1. func Sign(data []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { if len(data) != 32 { return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(data)) @@ -218,20 +211,6 @@ func Sign(data []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { return } -// SignEthereum calculates an Ethereum ECDSA signature. -// This function is susceptible to choosen plaintext attacks that can leak -// information about the private key that is used for signing. Callers must -// be aware that the given hash cannot be freely choosen by an adversery. -// Common solution is to hash the message before calculating the signature. -func SignEthereum(data []byte, prv *ecdsa.PrivateKey) ([]byte, error) { - sig, err := Sign(data, prv) - if err != nil { - return nil, err - } - sig[64] += 27 // as described in the yellow paper - return sig, err -} - func Encrypt(pub *ecdsa.PublicKey, message []byte) ([]byte, error) { return ecies.Encrypt(rand.Reader, ecies.ImportECDSAPublic(pub), message, nil, nil) } diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index b44c63214a..f582971519 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -72,30 +72,15 @@ func BenchmarkSha3(b *testing.B) { fmt.Println(amount, ":", time.Since(start)) } -func Test0Key(t *testing.T) { - key := common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000") - _, err := secp256k1.GeneratePubKey(key) - if err == nil { - t.Errorf("expected error due to zero privkey") - } -} - -func testSign(signfn func([]byte, *ecdsa.PrivateKey) ([]byte, error), t *testing.T) { +func TestSign(t *testing.T) { key, _ := HexToECDSA(testPrivHex) addr := common.HexToAddress(testAddrHex) msg := Keccak256([]byte("foo")) - sig, err := signfn(msg, key) + sig, err := Sign(msg, key) if err != nil { t.Errorf("Sign error: %s", err) } - - // signfn can return a recover id of either [0,1] or [27,28]. - // In the latter case its an Ethereum signature, adjust recover id. - if sig[64] == 27 || sig[64] == 28 { - sig[64] -= 27 - } - recoveredPub, err := Ecrecover(msg, sig) if err != nil { t.Errorf("ECRecover error: %s", err) @@ -117,34 +102,15 @@ func testSign(signfn func([]byte, *ecdsa.PrivateKey) ([]byte, error), t *testing } } -func TestSign(t *testing.T) { - testSign(Sign, t) -} - -func TestSignEthereum(t *testing.T) { - testSign(SignEthereum, t) -} - -func testInvalidSign(signfn func([]byte, *ecdsa.PrivateKey) ([]byte, error), t *testing.T) { - _, err := signfn(make([]byte, 1), nil) - if err == nil { +func TestInvalidSign(t *testing.T) { + if _, err := Sign(make([]byte, 1), nil); err == nil { t.Errorf("expected sign with hash 1 byte to error") } - - _, err = signfn(make([]byte, 33), nil) - if err == nil { + if _, err := Sign(make([]byte, 33), nil); err == nil { t.Errorf("expected sign with hash 33 byte to error") } } -func TestInvalidSign(t *testing.T) { - testInvalidSign(Sign, t) -} - -func TestInvalidSignEthereum(t *testing.T) { - testInvalidSign(SignEthereum, t) -} - func TestNewContractAddress(t *testing.T) { key, _ := HexToECDSA(testPrivHex) addr := common.HexToAddress(testAddrHex) @@ -207,43 +173,43 @@ func TestValidateSignatureValues(t *testing.T) { secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1) // correct v,r,s - check(true, 27, one, one) - check(true, 28, one, one) + check(true, 0, one, one) + check(true, 1, one, one) // incorrect v, correct r,s, - check(false, 30, one, one) - check(false, 26, one, one) + check(false, 2, one, one) + check(false, 3, one, one) // incorrect v, combinations of incorrect/correct r,s at lower limit + check(false, 2, zero, zero) + check(false, 2, zero, one) + check(false, 2, one, zero) + check(false, 2, one, one) + + // correct v for any combination of incorrect r,s check(false, 0, zero, zero) check(false, 0, zero, one) check(false, 0, one, zero) - check(false, 0, one, one) - // correct v for any combination of incorrect r,s - check(false, 27, zero, zero) - check(false, 27, zero, one) - check(false, 27, one, zero) - - check(false, 28, zero, zero) - check(false, 28, zero, one) - check(false, 28, one, zero) + check(false, 1, zero, zero) + check(false, 1, zero, one) + check(false, 1, one, zero) // correct sig with max r,s - check(true, 27, secp256k1nMinus1, secp256k1nMinus1) + check(true, 0, secp256k1nMinus1, secp256k1nMinus1) // correct v, combinations of incorrect r,s at upper limit - check(false, 27, secp256k1.N, secp256k1nMinus1) - check(false, 27, secp256k1nMinus1, secp256k1.N) - check(false, 27, secp256k1.N, secp256k1.N) + check(false, 0, secp256k1.N, secp256k1nMinus1) + check(false, 0, secp256k1nMinus1, secp256k1.N) + check(false, 0, secp256k1.N, secp256k1.N) // current callers ensures r,s cannot be negative, but let's test for that too // as crypto package could be used stand-alone - check(false, 27, minusOne, one) - check(false, 27, one, minusOne) + check(false, 0, minusOne, one) + check(false, 0, one, minusOne) } func checkhash(t *testing.T, name string, f func([]byte) []byte, msg, exp []byte) { sum := f(msg) - if bytes.Compare(exp, sum) != 0 { + if !bytes.Equal(exp, sum) { t.Fatalf("hash %s mismatch: want: %x have: %x", name, exp, sum) } } diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go index 187321e7fc..e96d4351f2 100644 --- a/crypto/ecies/asn1.go +++ b/crypto/ecies/asn1.go @@ -109,7 +109,7 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool { if len(curve) != len(curve2) { return false } - for i, _ := range curve { + for i := range curve { if curve[i] != curve2[i] { return false } @@ -157,7 +157,7 @@ func (a asnAlgorithmIdentifier) Cmp(b asnAlgorithmIdentifier) bool { if len(a.Algorithm) != len(b.Algorithm) { return false } - for i, _ := range a.Algorithm { + for i := range a.Algorithm { if a.Algorithm[i] != b.Algorithm[i] { return false } @@ -306,7 +306,7 @@ func (a asnECDHAlgorithm) Cmp(b asnECDHAlgorithm) bool { if len(a.Algorithm) != len(b.Algorithm) { return false } - for i, _ := range a.Algorithm { + for i := range a.Algorithm { if a.Algorithm[i] != b.Algorithm[i] { return false } @@ -325,7 +325,7 @@ func (a asnKeyDerivationFunction) Cmp(b asnKeyDerivationFunction) bool { if len(a.Algorithm) != len(b.Algorithm) { return false } - for i, _ := range a.Algorithm { + for i := range a.Algorithm { if a.Algorithm[i] != b.Algorithm[i] { return false } @@ -360,7 +360,7 @@ func (a asnSymmetricEncryption) Cmp(b asnSymmetricEncryption) bool { if len(a.Algorithm) != len(b.Algorithm) { return false } - for i, _ := range a.Algorithm { + for i := range a.Algorithm { if a.Algorithm[i] != b.Algorithm[i] { return false } @@ -380,7 +380,7 @@ func (a asnMessageAuthenticationCode) Cmp(b asnMessageAuthenticationCode) bool { if len(a.Algorithm) != len(b.Algorithm) { return false } - for i, _ := range a.Algorithm { + for i := range a.Algorithm { if a.Algorithm[i] != b.Algorithm[i] { return false } diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 86a70261d2..2a16f20a2e 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -93,7 +93,7 @@ func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { } // Generate an elliptic curve public / private keypair. If params is nil, -// the recommended default paramters for the key will be chosen. +// the recommended default parameters for the key will be chosen. func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { pb, x, y, err := elliptic.GenerateKey(curve, rand) if err != nil { @@ -291,9 +291,8 @@ func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err e // Decrypt decrypts an ECIES ciphertext. func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err error) { - if c == nil || len(c) == 0 { - err = ErrInvalidMessage - return + if len(c) == 0 { + return nil, ErrInvalidMessage } params := prv.PublicKey.Params if params == nil { diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index db2ecdc249..1315da8df1 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -492,17 +492,17 @@ type testCase struct { } var testCases = []testCase{ - testCase{ + { Curve: elliptic.P256(), Name: "P256", Expected: true, }, - testCase{ + { Curve: elliptic.P384(), Name: "P384", Expected: true, }, - testCase{ + { Curve: elliptic.P521(), Name: "P521", Expected: true, diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index 6e44a6771f..61cad54636 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -33,7 +33,6 @@ package secp256k1 import ( "crypto/elliptic" - "io" "math/big" "sync" "unsafe" @@ -224,6 +223,7 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, if len(scalar) > 32 { panic("can't handle scalars > 256 bits") } + // NOTE: potential timing issue padded := make([]byte, 32) copy(padded[32-len(scalar):], scalar) scalar = padded @@ -257,31 +257,6 @@ func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k) } -var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f} - -//TODO: double check if it is okay -// GenerateKey returns a public/private key pair. The private key is generated -// using the given reader, which must return random data. -func (BitCurve *BitCurve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err error) { - byteLen := (BitCurve.BitSize + 7) >> 3 - priv = make([]byte, byteLen) - - for x == nil { - _, err = io.ReadFull(rand, priv) - if err != nil { - return - } - // We have to mask off any excess bits in the case that the size of the - // underlying field is not a whole number of bytes. - priv[0] &= mask[BitCurve.BitSize%8] - // This is because, in tests, rand will return all zeros and we don't - // want to get the point at infinity and loop forever. - priv[1] ^= 0x42 - x, y = BitCurve.ScalarBaseMult(priv) - } - return -} - // Marshal converts a point into the form specified in section 4.3.6 of ANSI // X9.62. func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { diff --git a/crypto/secp256k1/ext.h b/crypto/secp256k1/ext.h new file mode 100644 index 0000000000..ee759fde69 --- /dev/null +++ b/crypto/secp256k1/ext.h @@ -0,0 +1,87 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// secp256k1_context_create_sign_verify creates a context for signing and signature verification. +static secp256k1_context* secp256k1_context_create_sign_verify() { + return secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); +} + +// secp256k1_ecdsa_recover_pubkey recovers the public key of an encoded compact signature. +// +// Returns: 1: recovery was successful +// 0: recovery was not successful +// Args: ctx: pointer to a context object (cannot be NULL) +// Out: pubkey_out: the serialized 65-byte public key of the signer (cannot be NULL) +// In: sigdata: pointer to a 65-byte signature with the recovery id at the end (cannot be NULL) +// msgdata: pointer to a 32-byte message (cannot be NULL) +static int secp256k1_ecdsa_recover_pubkey( + const secp256k1_context* ctx, + unsigned char *pubkey_out, + const unsigned char *sigdata, + const unsigned char *msgdata +) { + secp256k1_ecdsa_recoverable_signature sig; + secp256k1_pubkey pubkey; + + if (!secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &sig, sigdata, (int)sigdata[64])) { + return 0; + } + if (!secp256k1_ecdsa_recover(ctx, &pubkey, &sig, msgdata)) { + return 0; + } + size_t outputlen = 65; + return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED); +} + +// secp256k1_pubkey_scalar_mul multiplies a point by a scalar in constant time. +// +// Returns: 1: multiplication was successful +// 0: scalar was invalid (zero or overflow) +// Args: ctx: pointer to a context object (cannot be NULL) +// Out: point: the multiplied point (usually secret) +// In: point: pointer to a 64-byte public point, +// encoded as two 256bit big-endian numbers. +// scalar: a 32-byte scalar with which to multiply the point +int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_fe feX, feY; + secp256k1_gej res; + secp256k1_ge ge; + secp256k1_scalar s; + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + (void)ctx; + + secp256k1_fe_set_b32(&feX, point); + secp256k1_fe_set_b32(&feY, point+32); + secp256k1_ge_set_xy(&ge, &feX, &feY); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + secp256k1_ecmult_const(&res, &ge, &s); + secp256k1_ge_set_gej(&ge, &res); + /* Note: can't use secp256k1_pubkey_save here because it is not constant time. */ + secp256k1_fe_normalize(&ge.x); + secp256k1_fe_normalize(&ge.y); + secp256k1_fe_get_b32(point, &ge.x); + secp256k1_fe_get_b32(point+32, &ge.y); + ret = 1; + } + secp256k1_scalar_clear(&s); + return ret; +} diff --git a/crypto/secp256k1/libsecp256k1/.gitignore b/crypto/secp256k1/libsecp256k1/.gitignore index e0b7b7a48a..87fea161ba 100644 --- a/crypto/secp256k1/libsecp256k1/.gitignore +++ b/crypto/secp256k1/libsecp256k1/.gitignore @@ -6,6 +6,7 @@ bench_schnorr_verify bench_recover bench_internal tests +exhaustive_tests gen_context *.exe *.so @@ -25,17 +26,24 @@ config.status libtool .deps/ .dirstamp -build-aux/ *.lo *.o *~ src/libsecp256k1-config.h src/libsecp256k1-config.h.in src/ecmult_static_context.h -m4/libtool.m4 -m4/ltoptions.m4 -m4/ltsugar.m4 -m4/ltversion.m4 -m4/lt~obsolete.m4 +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver src/stamp-h1 libsecp256k1.pc diff --git a/crypto/secp256k1/libsecp256k1/.travis.yml b/crypto/secp256k1/libsecp256k1/.travis.yml index fba0892ddb..2439529242 100644 --- a/crypto/secp256k1/libsecp256k1/.travis.yml +++ b/crypto/secp256k1/libsecp256k1/.travis.yml @@ -6,25 +6,30 @@ addons: compiler: - clang - gcc +cache: + directories: + - src/java/guava/ env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=NO RECOVERY=NO + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no + - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar matrix: - SCALAR=32bit RECOVERY=yes - - SCALAR=32bit FIELD=32bit ECDH=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes - SCALAR=64bit - FIELD=64bit RECOVERY=yes - FIELD=64bit ENDOMORPHISM=yes - - FIELD=64bit ENDOMORPHISM=yes ECDH=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit SCHNORR=yes - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 + - BUILD=check-java ECDH=yes EXPERIMENTAL=yes matrix: fast_finish: true include: @@ -54,9 +59,11 @@ matrix: packages: - gcc-multilib - libgmp-dev:i386 +before_install: mkdir -p `dirname $GUAVA_JAR` +install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD os: linux diff --git a/crypto/secp256k1/libsecp256k1/Makefile.am b/crypto/secp256k1/libsecp256k1/Makefile.am index 57524fab05..c071fbe275 100644 --- a/crypto/secp256k1/libsecp256k1/Makefile.am +++ b/crypto/secp256k1/libsecp256k1/Makefile.am @@ -1,14 +1,22 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 lib_LTLIBRARIES = libsecp256k1.la +if USE_JNI +JNI_LIB = libsecp256k1_jni.la +noinst_LTLIBRARIES = $(JNI_LIB) +else +JNI_LIB = +endif include_HEADERS = include/secp256k1.h noinst_HEADERS = noinst_HEADERS += src/scalar.h noinst_HEADERS += src/scalar_4x64.h noinst_HEADERS += src/scalar_8x32.h +noinst_HEADERS += src/scalar_low.h noinst_HEADERS += src/scalar_impl.h noinst_HEADERS += src/scalar_4x64_impl.h noinst_HEADERS += src/scalar_8x32_impl.h +noinst_HEADERS += src/scalar_low_impl.h noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h noinst_HEADERS += src/num_gmp.h @@ -32,6 +40,7 @@ noinst_HEADERS += src/field_5x52_impl.h noinst_HEADERS += src/field_5x52_int128_impl.h noinst_HEADERS += src/field_5x52_asm_impl.h noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h +noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h noinst_HEADERS += src/util.h noinst_HEADERS += src/testrand.h noinst_HEADERS += src/testrand_impl.h @@ -40,41 +49,103 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h +noinst_HEADERS += contrib/lax_der_parsing.h +noinst_HEADERS += contrib/lax_der_parsing.c +noinst_HEADERS += contrib/lax_der_privatekey_parsing.h +noinst_HEADERS += contrib/lax_der_privatekey_parsing.c + +if USE_EXTERNAL_ASM +COMMON_LIB = libsecp256k1_common.la +noinst_LTLIBRARIES = $(COMMON_LIB) +else +COMMON_LIB = +endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc -libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) -libsecp256k1_la_LIBADD = $(SECP_LIBS) +if USE_EXTERNAL_ASM +if USE_ASM_ARM +libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s +endif +endif +libsecp256k1_la_SOURCES = src/secp256k1.c +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) + +libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c +libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_verify_SOURCES = src/bench_verify.c -bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_verify_LDFLAGS = -static +bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_sign_SOURCES = src/bench_sign.c -bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_sign_LDFLAGS = -static +bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(SECP_LIBS) -bench_internal_LDFLAGS = -static -bench_internal_CPPFLAGS = $(SECP_INCLUDES) +bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) +bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) endif +TESTS = if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) -tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) +tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +if !ENABLE_COVERAGE +tests_CPPFLAGS += -DVERIFY +endif +tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) tests_LDFLAGS = -static -TESTS = tests +TESTS += tests +endif + +if USE_EXHAUSTIVE_TESTS +noinst_PROGRAMS += exhaustive_tests +exhaustive_tests_SOURCES = src/tests_exhaustive.c +exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) +if !ENABLE_COVERAGE +exhaustive_tests_CPPFLAGS += -DVERIFY +endif +exhaustive_tests_LDADD = $(SECP_LIBS) +exhaustive_tests_LDFLAGS = -static +TESTS += exhaustive_tests +endif + +JAVAROOT=src/java +JAVAORG=org/bitcoin +JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar +CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) +JAVA_FILES= \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ + $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java + +if USE_JNI + +$(JAVA_GUAVA): + @echo Guava is missing. Fetch it via: \ + wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) + @false + +.stamp-java: $(JAVA_FILES) + @echo Compiling $^ + $(AM_V_at)$(CLASSPATH_ENV) javac $^ + @touch $@ + +if USE_TESTS + +check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java + $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + +endif endif if USE_ECMULT_STATIC_PRECOMPUTATION -CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)/ +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function gen_context_OBJECTS = gen_context.o @@ -92,19 +163,15 @@ $(bench_internal_OBJECTS): src/ecmult_static_context.h src/ecmult_static_context.h: $(gen_context_BIN) ./$(gen_context_BIN) -CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java endif -EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include endif -if ENABLE_MODULE_SCHNORR -include src/modules/schnorr/Makefile.am.include -endif - if ENABLE_MODULE_RECOVERY include src/modules/recovery/Makefile.am.include endif diff --git a/crypto/secp256k1/libsecp256k1/README.md b/crypto/secp256k1/libsecp256k1/README.md index 6095db4220..8cd344ea81 100644 --- a/crypto/secp256k1/libsecp256k1/README.md +++ b/crypto/secp256k1/libsecp256k1/README.md @@ -1,7 +1,7 @@ libsecp256k1 ============ -[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1) +[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1) Optimized C library for EC operations on curve secp256k1. diff --git a/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_jni_include_dir.m4 b/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_jni_include_dir.m4 new file mode 100644 index 0000000000..1fc3627614 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_jni_include_dir.m4 @@ -0,0 +1,140 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_JNI_INCLUDE_DIR +# +# DESCRIPTION +# +# AX_JNI_INCLUDE_DIR finds include directories needed for compiling +# programs using the JNI interface. +# +# JNI include directories are usually in the Java distribution. This is +# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in +# that order. When this macro completes, a list of directories is left in +# the variable JNI_INCLUDE_DIRS. +# +# Example usage follows: +# +# AX_JNI_INCLUDE_DIR +# +# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +# do +# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" +# done +# +# If you want to force a specific compiler: +# +# - at the configure.in level, set JAVAC=yourcompiler before calling +# AX_JNI_INCLUDE_DIR +# +# - at the configure level, setenv JAVAC +# +# Note: This macro can work with the autoconf M4 macros for Java programs. +# This particular macro is not part of the original set of macros. +# +# LICENSE +# +# Copyright (c) 2008 Don Anderson +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) +AC_DEFUN([AX_JNI_INCLUDE_DIR],[ + +JNI_INCLUDE_DIRS="" + +if test "x$JAVA_HOME" != x; then + _JTOPDIR="$JAVA_HOME" +else + if test "x$JAVAC" = x; then + JAVAC=javac + fi + AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) + if test "x$_ACJNI_JAVAC" = xno; then + AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) + fi + _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") + _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` +fi + +case "$host_os" in + darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + _JINC="$_JTOPDIR/Headers";; + *) _JINC="$_JTOPDIR/include";; +esac +_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) +_AS_ECHO_LOG([_JINC=$_JINC]) + +# On Mac OS X 10.6.4, jni.h is a symlink: +# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h +# -> ../../CurrentJDK/Headers/jni.h. + +AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, +[ +if test -f "$_JINC/jni.h"; then + ac_cv_jni_header_path="$_JINC" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" +else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$_JTOPDIR/include/jni.h"; then + ac_cv_jni_header_path="$_JTOPDIR/include" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + ac_cv_jni_header_path=none + fi +fi +]) + + + +# get the likely subdirectories for system specific java includes +case "$host_os" in +bsdi*) _JNI_INC_SUBDIRS="bsdos";; +darwin*) _JNI_INC_SUBDIRS="darwin";; +freebsd*) _JNI_INC_SUBDIRS="freebsd";; +linux*) _JNI_INC_SUBDIRS="linux genunix";; +osf*) _JNI_INC_SUBDIRS="alpha";; +solaris*) _JNI_INC_SUBDIRS="solaris";; +mingw*) _JNI_INC_SUBDIRS="win32";; +cygwin*) _JNI_INC_SUBDIRS="win32";; +*) _JNI_INC_SUBDIRS="genunix";; +esac + +if test "x$ac_cv_jni_header_path" != "xnone"; then + # add any subdirectories that are present + for JINCSUBDIR in $_JNI_INC_SUBDIRS + do + if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" + fi + done +fi +]) + +# _ACJNI_FOLLOW_SYMLINKS +# Follows symbolic links on , +# finally setting variable _ACJNI_FOLLOWED +# ---------------------------------------- +AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING([symlink for $_cur]) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT([$_cur]) +done +_ACJNI_FOLLOWED="$_cur" +])# _ACJNI diff --git a/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 0000000000..77fd346a79 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/build-aux/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/crypto/secp256k1/libsecp256k1/build-aux/m4/bitcoin_secp.m4 b/crypto/secp256k1/libsecp256k1/build-aux/m4/bitcoin_secp.m4 new file mode 100644 index 0000000000..b74acb8c13 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/build-aux/m4/bitcoin_secp.m4 @@ -0,0 +1,69 @@ +dnl libsecp25k1 helper checks +AC_DEFUN([SECP_INT128_CHECK],[ +has_int128=$ac_cv_type___int128 +]) + +dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. +AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_MSG_CHECKING(for x86_64 assembly availability) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include ]],[[ + uint64_t a = 11, tmp; + __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); + ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) +AC_MSG_RESULT([$has_64bit_asm]) +]) + +dnl +AC_DEFUN([SECP_OPENSSL_CHECK],[ + has_libcrypto=no + m4_ifdef([PKG_CHECK_MODULES],[ + PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) + if test x"$has_libcrypto" = x"yes"; then + TEMP_LIBS="$LIBS" + LIBS="$LIBS $CRYPTO_LIBS" + AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no]) + LIBS="$TEMP_LIBS" + fi + ]) + if test x$has_libcrypto = xno; then + AC_CHECK_HEADER(openssl/crypto.h,[ + AC_CHECK_LIB(crypto, main,[ + has_libcrypto=yes + CRYPTO_LIBS=-lcrypto + AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) + ]) + ]) + LIBS= + fi +if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then + AC_MSG_CHECKING(for EC functions in libcrypto) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include ]],[[ + EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); + ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); + ECDSA_verify(0, NULL, 0, NULL, 0, eckey); + EC_KEY_free(eckey); + ECDSA_SIG *sig_openssl; + sig_openssl = ECDSA_SIG_new(); + (void)sig_openssl->r; + ECDSA_SIG_free(sig_openssl); + ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) + AC_MSG_RESULT([$has_openssl_ec]) +fi +]) + +dnl +AC_DEFUN([SECP_GMP_CHECK],[ +if test x"$has_gmp" != x"yes"; then + CPPFLAGS_TEMP="$CPPFLAGS" + CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS" + LIBS_TEMP="$LIBS" + LIBS="$GMP_LIBS $LIBS" + AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) + CPPFLAGS="$CPPFLAGS_TEMP" + LIBS="$LIBS_TEMP" +fi +]) diff --git a/crypto/secp256k1/libsecp256k1/configure.ac b/crypto/secp256k1/libsecp256k1/configure.ac index 786d8dcfb9..e5fcbcb4ed 100644 --- a/crypto/secp256k1/libsecp256k1/configure.ac +++ b/crypto/secp256k1/libsecp256k1/configure.ac @@ -20,7 +20,7 @@ AC_PATH_TOOL(STRIP, strip) AX_PROG_CC_FOR_BUILD if test "x$CFLAGS" = "x"; then - CFLAGS="-O3 -g" + CFLAGS="-g" fi AM_PROG_CC_C_O @@ -29,6 +29,7 @@ AC_PROG_CC_C89 if test x"$ac_cv_prog_cc_c89" = x"no"; then AC_MSG_ERROR([c89 compiler support required]) fi +AM_PROG_AS case $host_os in *darwin*) @@ -88,36 +89,56 @@ AC_ARG_ENABLE(benchmark, [use_benchmark=$enableval], [use_benchmark=no]) +AC_ARG_ENABLE(coverage, + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]), + [enable_coverage=$enableval], + [enable_coverage=no]) + AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), [use_tests=$enableval], [use_tests=yes]) +AC_ARG_ENABLE(openssl_tests, + AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), + [enable_openssl_tests=$enableval], + [enable_openssl_tests=auto]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), + [use_experimental=$enableval], + [use_experimental=no]) + +AC_ARG_ENABLE(exhaustive_tests, + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), + [use_exhaustive_tests=$enableval], + [use_exhaustive_tests=yes]) + AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), [use_endomorphism=$enableval], [use_endomorphism=no]) - + AC_ARG_ENABLE(ecmult_static_precomputation, AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), [use_ecmult_static_precomputation=$enableval], - [use_ecmult_static_precomputation=yes]) + [use_ecmult_static_precomputation=auto]) AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]), + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), [enable_module_ecdh=$enableval], [enable_module_ecdh=no]) -AC_ARG_ENABLE(module_schnorr, - AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]), - [enable_module_schnorr=$enableval], - [enable_module_schnorr=no]) - AC_ARG_ENABLE(module_recovery, AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), [enable_module_recovery=$enableval], [enable_module_recovery=no]) +AC_ARG_ENABLE(jni, + AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]), + [use_jni=$enableval], + [use_jni=auto]) + AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) @@ -127,8 +148,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], [Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto] -[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto]) +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] +[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) AC_CHECK_TYPES([__int128]) @@ -138,6 +159,42 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], [ AC_MSG_RESULT([no]) ]) +if test x"$enable_coverage" = x"yes"; then + AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) + CFLAGS="$CFLAGS -O0 --coverage" + LDFLAGS="--coverage" +else + CFLAGS="$CFLAGS -O3" +fi + +if test x"$use_ecmult_static_precomputation" != x"no"; then + save_cross_compiling=$cross_compiling + cross_compiling=no + TEMP_CC="$CC" + CC="$CC_FOR_BUILD" + AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], [return 0])], + [working_native_cc=yes], + [working_native_cc=no],[dnl]) + CC="$TEMP_CC" + cross_compiling=$save_cross_compiling + + if test x"$working_native_cc" = x"no"; then + set_precomp=no + if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + else + AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + fi + else + AC_MSG_RESULT([ok]) + set_precomp=yes + fi +else + set_precomp=no +fi + if test x"$req_asm" = x"auto"; then SECP_64BIT_ASM_CHECK if test x"$has_64bit_asm" = x"yes"; then @@ -155,6 +212,8 @@ else AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) fi ;; + arm) + ;; no) ;; *) @@ -247,10 +306,15 @@ else fi # select assembly optimization +use_external_asm=no + case $set_asm in x86_64) AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) ;; +arm) + use_external_asm=yes + ;; no) ;; *) @@ -305,16 +369,48 @@ esac if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK if test x"$has_openssl_ec" = x"yes"; then - AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) - SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" - SECP_TEST_LIBS="$CRYPTO_LIBS" + if test x"$enable_openssl_tests" != x"no"; then + AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) + SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" + SECP_TEST_LIBS="$CRYPTO_LIBS" - case $host in - *mingw*) - SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" - ;; - esac + case $host in + *mingw*) + SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" + ;; + esac + fi + else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) + fi + fi +else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) + fi +fi +if test x"$use_jni" != x"no"; then + AX_JNI_INCLUDE_DIR + have_jni_dependencies=yes + if test x"$enable_module_ecdh" = x"no"; then + have_jni_dependencies=no + fi + if test "x$JNI_INCLUDE_DIRS" = "x"; then + have_jni_dependencies=no + fi + if test "x$have_jni_dependencies" = "xno"; then + if test x"$use_jni" = x"yes"; then + AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.]) + fi + AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) + use_jni=no + else + use_jni=yes + for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do + JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" + done fi fi @@ -327,7 +423,7 @@ if test x"$use_endomorphism" = x"yes"; then AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi -if test x"$use_ecmult_static_precomputation" = x"yes"; then +if test x"$set_precomp" = x"yes"; then AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) fi @@ -335,38 +431,59 @@ if test x"$enable_module_ecdh" = x"yes"; then AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) fi -if test x"$enable_module_schnorr" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) -fi - if test x"$enable_module_recovery" = x"yes"; then AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) fi AC_C_BIGENDIAN() +if test x"$use_external_asm" = x"yes"; then + AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) +fi + +AC_MSG_NOTICE([Using static precomputation: $set_precomp]) AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) +AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage]) AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) - -AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) +AC_MSG_NOTICE([Using jni: $use_jni]) + +if test x"$enable_experimental" = x"yes"; then + AC_MSG_NOTICE([******]) + AC_MSG_NOTICE([WARNING: experimental build]) + AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) + AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) + AC_MSG_NOTICE([******]) +else + if test x"$enable_module_ecdh" = x"yes"; then + AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$set_asm" = x"arm"; then + AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) + fi +fi AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(JNI_INCLUDES) AC_SUBST(SECP_INCLUDES) AC_SUBST(SECP_LIBS) AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) +AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) +AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) -AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"]) +AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) +AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) dnl make sure nothing new is exported so that we don't break the cache PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.c b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.c new file mode 100644 index 0000000000..5b141a9948 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.c @@ -0,0 +1,150 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_parsing.h" + +int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} + diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.h b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.h new file mode 100644 index 0000000000..6d27871a7c --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_parsing.h @@ -0,0 +1,91 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file defines a function that parses DER with various errors and + * violations. This is not a part of the library itself, because the allowed + * violations are chosen arbitrarily and do not follow or establish any + * standard. + * + * In many places it matters that different implementations do not only accept + * the same set of valid signatures, but also reject the same set of signatures. + * The only means to accomplish that is by strictly obeying a standard, and not + * accepting anything else. + * + * Nonetheless, sometimes there is a need for compatibility with systems that + * use signatures which do not strictly obey DER. The snippet below shows how + * certain violations are easily supported. You may need to adapt it. + * + * Do not use this for new systems. Use well-defined DER or compact signatures + * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and + * secp256k1_ecdsa_signature_parse_compact). + * + * The supported violations are: + * - All numbers are parsed as nonnegative integers, even though X.609-0207 + * section 8.3.3 specifies that integers are always encoded as two's + * complement. + * - Integers can have length 0, even though section 8.3.1 says they can't. + * - Integers with overly long padding are accepted, violation section + * 8.3.2. + * - 127-byte long length descriptors are accepted, even though section + * 8.1.3.5.c says that they are not. + * - Trailing garbage data inside or after the signature is ignored. + * - The length descriptor of the sequence is ignored. + * + * Compared to for example OpenSSL, many violations are NOT supported: + * - Using overly long tag descriptors for the sequence or integers inside, + * violating section 8.1.2.2. + * - Encoding primitive integers as constructed values, violating section + * 8.3.1. + */ + +#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ +#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ + +#include + +# ifdef __cplusplus +extern "C" { +# endif + +/** Parse a signature in "lax DER" format + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. In addition, it will accept signatures + * which violate the DER spec in various ways. Its purpose is to allow + * validation of the Bitcoin blockchain, which includes non-DER signatures + * from before the network rules were updated to enforce DER. Note that + * the set of supported violations is a strict subset of what OpenSSL will + * accept. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +int ecdsa_signature_parse_der_lax( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.c b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.c new file mode 100644 index 0000000000..c2e63b4b8d --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.c @@ -0,0 +1,113 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_privatekey_parsing.h" + +int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + memset(out32, 0, 32); + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (!secp256k1_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + secp256k1_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 33; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 65; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} diff --git a/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.h b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.h new file mode 100644 index 0000000000..2fd088f8ab --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/contrib/lax_der_privatekey_parsing.h @@ -0,0 +1,90 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file contains code snippets that parse DER private keys with + * various errors and violations. This is not a part of the library + * itself, because the allowed violations are chosen arbitrarily and + * do not follow or establish any standard. + * + * It also contains code to serialize private keys in a compatible + * manner. + * + * These functions are meant for compatibility with applications + * that require BER encoded keys. When working with secp256k1-specific + * code, the simple 32-byte private keys normally used by the + * library are sufficient. + */ + +#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ +#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ + +#include + +# ifdef __cplusplus +extern "C" { +# endif + +/** Export a private key in DER format. + * + * Returns: 1 if the private key was valid. + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: privkey: pointer to an array for storing the private key in BER. + * Should have space for 279 bytes, and cannot be NULL. + * privkeylen: Pointer to an int where the length of the private key in + * privkey will be stored. + * In: seckey: pointer to a 32-byte secret key to export. + * compressed: 1 if the key should be exported in + * compressed format, 0 otherwise + * + * This function is purely meant for compatibility with applications that + * require BER encoded keys. When working with secp256k1-specific code, the + * simple 32-byte private keys are sufficient. + * + * Note that this function does not guarantee correct DER output. It is + * guaranteed to be parsable by secp256k1_ec_privkey_import_der + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( + const secp256k1_context* ctx, + unsigned char *privkey, + size_t *privkeylen, + const unsigned char *seckey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Import a private key in DER format. + * Returns: 1 if a private key was extracted. + * Args: ctx: pointer to a context object (cannot be NULL). + * Out: seckey: pointer to a 32-byte array for storing the private key. + * (cannot be NULL). + * In: privkey: pointer to a private key in DER format (cannot be NULL). + * privkeylen: length of the DER private key pointed to be privkey. + * + * This function will accept more than just strict DER, and even allow some BER + * violations. The public key stored inside the DER-encoded private key is not + * verified for correctness, nor are the curve parameters. Use this function + * only if you know in advance it is supposed to contain a secp256k1 private + * key. + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *privkey, + size_t privkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1.h b/crypto/secp256k1/libsecp256k1/include/secp256k1.h index 23378de1fd..f268e309d0 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1.h @@ -47,11 +47,8 @@ typedef struct secp256k1_context_struct secp256k1_context; * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage or transmission, use - * secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. - * - * Furthermore, it is guaranteed that identical public keys (ignoring - * compression) will have identical representation, so they can be memcmp'ed. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. */ typedef struct { unsigned char data[64]; @@ -62,12 +59,9 @@ typedef struct { * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage or transmission, use - * the secp256k1_ecdsa_signature_serialize_* and + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the secp256k1_ecdsa_signature_serialize_* and * secp256k1_ecdsa_signature_serialize_* functions. - * - * Furthermore, it is guaranteed to identical signatures will have identical - * representation, so they can be memcmp'ed. */ typedef struct { unsigned char data[64]; @@ -147,12 +141,23 @@ typedef int (*secp256k1_nonce_function)( # define SECP256K1_ARG_NONNULL(_x) # endif +/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) +#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) +#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) +/** The higher bits contain the actual data. Do not use directly. */ +#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) +#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) + /** Flags to pass to secp256k1_context_create. */ -# define SECP256K1_CONTEXT_VERIFY (1 << 0) -# define SECP256K1_CONTEXT_SIGN (1 << 1) +#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) +#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) /** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ -# define SECP256K1_EC_COMPRESSED (1 << 0) +#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) +#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) /** Create a secp256k1 context object. * @@ -218,7 +223,7 @@ SECP256K1_API void secp256k1_context_set_illegal_callback( * crashing. * * Args: ctx: an existing context object (cannot be NULL) - * In: fun: a pointer to a function to call when an interal error occurs, + * In: fun: a pointer to a function to call when an internal error occurs, * taking a message and an opaque pointer (NULL restores a default * handler that calls abort). * data: the opaque pointer to pass to fun above. @@ -253,15 +258,17 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( /** Serialize a pubkey object into a serialized byte sequence. * * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if - * compressed==1) byte array to place the serialized key in. - * outputlen: a pointer to an integer which will contain the serialized - * size. - * In: pubkey: a pointer to a secp256k1_pubkey containing an initialized - * public key. - * flags: SECP256K1_EC_COMPRESSED if serialization should be in - * compressed format. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key + * in. + * In/Out: outputlen: a pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key. + * flags: SECP256K1_EC_COMPRESSED if serialization should be in + * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. */ SECP256K1_API int secp256k1_ec_pubkey_serialize( const secp256k1_context* ctx, @@ -271,6 +278,27 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize( unsigned int flags ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +/** Parse an ECDSA signature in compact (64 bytes) format. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to the 64-byte array to parse + * + * The signature must consist of a 32-byte big endian R value, followed by a + * 32-byte big endian S value. If R or S fall outside of [0..order-1], the + * encoding is invalid. R and S with value 0 are allowed in the encoding. + * + * After the call, sig will always be initialized. If parsing failed or R or + * S are zero, the resulting sig value is guaranteed to fail validation for any + * message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + /** Parse a DER ECDSA signature. * * Returns: 1 when the signature could be parsed, 0 otherwise. @@ -279,7 +307,12 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize( * In: input: a pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * - * Note that this function also supports some violations of DER and even BER. + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. */ SECP256K1_API int secp256k1_ecdsa_signature_parse_der( const secp256k1_context* ctx, @@ -306,6 +339,21 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( const secp256k1_ecdsa_signature* sig ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +/** Serialize an ECDSA signature in compact (64 byte) format. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array to store the compact serialization + * In: sig: a pointer to an initialized signature object + * + * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + /** Verify an ECDSA signature. * * Returns: 1: correct signature @@ -314,6 +362,15 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( * In: sig: the signature being verified (cannot be NULL) * msg32: the 32-byte message hash being verified (cannot be NULL) * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to + * validation, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( const secp256k1_context* ctx, @@ -322,14 +379,62 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( const secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: a secp256k1 context object + * Out: sigout: a pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, + * can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_ecdsa_signature_normalize must be called before verification. + */ +SECP256K1_API int secp256k1_ecdsa_signature_normalize( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sigout, + const secp256k1_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); + /** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. */ -extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -extern const secp256k1_nonce_function secp256k1_nonce_function_default; +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; /** Create an ECDSA signature. * @@ -342,32 +447,8 @@ extern const secp256k1_nonce_function secp256k1_nonce_function_default; * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) * - * The sig always has an s value in the lower half of the range (From 0x1 - * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, - * inclusive), unlike many other implementations. - * - * With ECDSA a third-party can can forge a second distinct signature - * of the same message given a single initial signature without knowing - * the key by setting s to its additive inverse mod-order, 'flipping' the - * sign of the random point R which is not included in the signature. - * Since the forgery is of the same message this isn't universally - * problematic, but in systems where message malleability or uniqueness - * of signatures is important this can cause issues. This forgery can be - * blocked by all verifiers forcing signers to use a canonical form. The - * lower-S form reduces the size of signatures slightly on average when - * variable length encodings (such as DER) are used and is cheap to - * verify, making it a good choice. Security of always using lower-S is - * assured because anyone can trivially modify a signature after the - * fact to enforce this property. Adjusting it inside the signing - * function avoids the need to re-serialize or have curve specific - * constants outside of the library. By always using a canonical form - * even in applications where it isn't needed it becomes possible to - * impose a requirement later if a need is discovered. - * No other forms of ECDSA malleability are known and none seem likely, - * but there is no formal proof that ECDSA, even with this additional - * restriction, is free of other malleability. Commonly used serialization - * schemes will also accept various non-unique encodings, so care should - * be taken when this property is required for an application. + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. */ SECP256K1_API int secp256k1_ecdsa_sign( const secp256k1_context* ctx, @@ -404,55 +485,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Export a private key in BER format. - * - * Returns: 1 if the private key was valid. - * Args: ctx: pointer to a context object, initialized for signing (cannot - * be NULL) - * Out: privkey: pointer to an array for storing the private key in BER. - * Should have space for 279 bytes, and cannot be NULL. - * privkeylen: Pointer to an int where the length of the private key in - * privkey will be stored. - * In: seckey: pointer to a 32-byte secret key to export. - * flags: SECP256K1_EC_COMPRESSED if the key should be exported in - * compressed format. - * - * This function is purely meant for compatibility with applications that - * require BER encoded keys. When working with secp256k1-specific code, the - * simple 32-byte private keys are sufficient. - * - * Note that this function does not guarantee correct DER output. It is - * guaranteed to be parsable by secp256k1_ec_privkey_import. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export( - const secp256k1_context* ctx, - unsigned char *privkey, - size_t *privkeylen, - const unsigned char *seckey, - unsigned int flags -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Import a private key in DER format. - * Returns: 1 if a private key was extracted. - * Args: ctx: pointer to a context object (cannot be NULL). - * Out: seckey: pointer to a 32-byte array for storing the private key. - * (cannot be NULL). - * In: privkey: pointer to a private key in DER format (cannot be NULL). - * privkeylen: length of the DER private key pointed to be privkey. - * - * This function will accept more than just strict DER, and even allow some BER - * violations. The public key stored inside the DER-encoded private key is not - * verified for correctness, nor are the curve parameters. Use this function - * only if you know in advance it is supposed to contain a secp256k1 private - * key. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import( - const secp256k1_context* ctx, - unsigned char *seckey, - const unsigned char *privkey, - size_t privkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - /** Tweak a private key by adding tweak to it. * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for * uniformly random 32-byte arrays, or if the resulting private key @@ -526,18 +558,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( * Returns: 1: the sum of the public keys is valid. * 0: the sum of the public keys is not valid. * Args: ctx: pointer to a context object - * Out: out: pointer to pubkey for placing the resulting public key + * Out: out: pointer to a public key object for placing the resulting public key * (cannot be NULL) * In: ins: pointer to array of pointers to public keys (cannot be NULL) * n: the number of public keys to add together (must be at least 1) - * Use secp256k1_ec_pubkey_compress and secp256k1_ec_pubkey_decompress if the - * uncompressed format is needed. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( const secp256k1_context* ctx, secp256k1_pubkey *out, const secp256k1_pubkey * const * ins, - int n + size_t n ) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); # ifdef __cplusplus diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h index db520f4467..4b84d7a963 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_ecdh.h @@ -10,17 +10,18 @@ extern "C" { /** Compute an EC Diffie-Hellman secret in constant time * Returns: 1: exponentiation was successful * 0: scalar was invalid (zero or overflow) - * Args: ctx: pointer to a context object (cannot be NULL) - * Out: result: a 32-byte array which will be populated by an ECDH - * secret computed from the point and scalar - * In: point: pointer to a public point - * scalar: a 32-byte scalar with which to multiply the point + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: result: a 32-byte array which will be populated by an ECDH + * secret computed from the point and scalar + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key + * privkey: a 32-byte scalar with which to multiply the point */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( const secp256k1_context* ctx, unsigned char *result, - const secp256k1_pubkey *point, - const unsigned char *scalar + const secp256k1_pubkey *pubkey, + const unsigned char *privkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); # ifdef __cplusplus diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h index c9b8c0a306..0553797253 100644 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h +++ b/crypto/secp256k1/libsecp256k1/include/secp256k1_recovery.h @@ -65,7 +65,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Create a recoverable ECDSA signature. * @@ -92,7 +92,7 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable( * Returns: 1: public key successfully recovered (which guarantees a correct signature). * 0: otherwise. * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) - * Out: pubkey: pointer to the recoved public key (cannot be NULL) + * Out: pubkey: pointer to the recovered public key (cannot be NULL) * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) */ diff --git a/crypto/secp256k1/libsecp256k1/include/secp256k1_schnorr.h b/crypto/secp256k1/libsecp256k1/include/secp256k1_schnorr.h deleted file mode 100644 index 49354933da..0000000000 --- a/crypto/secp256k1/libsecp256k1/include/secp256k1_schnorr.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef _SECP256K1_SCHNORR_ -# define _SECP256K1_SCHNORR_ - -# include "secp256k1.h" - -# ifdef __cplusplus -extern "C" { -# endif - -/** Create a signature using a custom EC-Schnorr-SHA256 construction. It - * produces non-malleable 64-byte signatures which support public key recovery - * batch validation, and multiparty signing. - * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was - * invalid. - * Args: ctx: pointer to a context object, initialized for signing - * (cannot be NULL) - * Out: sig64: pointer to a 64-byte array where the signature will be - * placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation - * function (can be NULL) - */ -SECP256K1_API int secp256k1_schnorr_sign( - const secp256k1_context* ctx, - unsigned char *sig64, - const unsigned char *msg32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Verify a signature created by secp256k1_schnorr_sign. - * Returns: 1: correct signature - * 0: incorrect signature - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig64: the 64-byte signature being verified (cannot be NULL) - * msg32: the 32-byte message hash being verified (cannot be NULL) - * pubkey: the public key to verify with (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( - const secp256k1_context* ctx, - const unsigned char *sig64, - const unsigned char *msg32, - const secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Recover an EC public key from a Schnorr signature created using - * secp256k1_schnorr_sign. - * Returns: 1: public key successfully recovered (which guarantees a correct - * signature). - * 0: otherwise. - * Args: ctx: pointer to a context object, initialized for - * verification (cannot be NULL) - * Out: pubkey: pointer to a pubkey to set to the recovered public key - * (cannot be NULL). - * In: sig64: signature as 64 byte array (cannot be NULL) - * msg32: the 32-byte message hash assumed to be signed (cannot - * be NULL) - */ -SECP256K1_API int secp256k1_schnorr_recover( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey, - const unsigned char *sig64, - const unsigned char *msg32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Generate a nonce pair deterministically for use with - * secp256k1_schnorr_partial_sign. - * Returns: 1: valid nonce pair was generated. - * 0: otherwise (nonce generation function failed) - * Args: ctx: pointer to a context object, initialized for signing - * (cannot be NULL) - * Out: pubnonce: public side of the nonce (cannot be NULL) - * privnonce32: private side of the nonce (32 byte) (cannot be NULL) - * In: msg32: the 32-byte message hash assumed to be signed (cannot - * be NULL) - * sec32: the 32-byte private key (cannot be NULL) - * noncefp: pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_default is used - * noncedata: pointer to arbitrary data used by the nonce generation - * function (can be NULL) - * - * Do not use the output as a private/public key pair for signing/validation. - */ -SECP256K1_API int secp256k1_schnorr_generate_nonce_pair( - const secp256k1_context* ctx, - secp256k1_pubkey *pubnonce, - unsigned char *privnonce32, - const unsigned char *msg32, - const unsigned char *sec32, - secp256k1_nonce_function noncefp, - const void* noncedata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Produce a partial Schnorr signature, which can be combined using - * secp256k1_schnorr_partial_combine, to end up with a full signature that is - * verifiable using secp256k1_schnorr_verify. - * Returns: 1: signature created succesfully. - * 0: no valid signature exists with this combination of keys, nonces - * and message (chance around 1 in 2^128) - * -1: invalid private key, nonce, or public nonces. - * Args: ctx: pointer to context object, initialized for signing (cannot - * be NULL) - * Out: sig64: pointer to 64-byte array to put partial signature in - * In: msg32: pointer to 32-byte message to sign - * sec32: pointer to 32-byte private key - * pubnonce_others: pointer to pubkey containing the sum of the other's - * nonces (see secp256k1_ec_pubkey_combine) - * secnonce32: pointer to 32-byte array containing our nonce - * - * The intended procedure for creating a multiparty signature is: - * - Each signer S[i] with private key x[i] and public key Q[i] runs - * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of - * private/public nonces. - * - All signers communicate their public nonces to each other (revealing your - * private nonce can lead to discovery of your private key, so it should be - * considered secret). - * - All signers combine all the public nonces they received (excluding their - * own) using secp256k1_ec_pubkey_combine to obtain an - * Rall[i] = sum(R[0..i-1,i+1..n]). - * - All signers produce a partial signature using - * secp256k1_schnorr_partial_sign, passing in their own private key x[i], - * their own private nonce k[i], and the sum of the others' public nonces - * Rall[i]. - * - All signers communicate their partial signatures to each other. - * - Someone combines all partial signatures using - * secp256k1_schnorr_partial_combine, to obtain a full signature. - * - The resulting signature is validatable using secp256k1_schnorr_verify, with - * public key equal to the result of secp256k1_ec_pubkey_combine of the - * signers' public keys (sum(Q[0..n])). - * - * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine - * function take their arguments in any order, and it is possible to - * pre-combine several inputs already with one call, and add more inputs later - * by calling the function again (they are commutative and associative). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign( - const secp256k1_context* ctx, - unsigned char *sig64, - const unsigned char *msg32, - const unsigned char *sec32, - const secp256k1_pubkey *pubnonce_others, - const unsigned char *secnonce32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Combine multiple Schnorr partial signatures. - * Returns: 1: the passed signatures were succesfully combined. - * 0: the resulting signature is not valid (chance of 1 in 2^256) - * -1: some inputs were invalid, or the signatures were not created - * using the same set of nonces - * Args: ctx: pointer to a context object - * Out: sig64: pointer to a 64-byte array to place the combined signature - * (cannot be NULL) - * In: sig64sin: pointer to an array of n pointers to 64-byte input - * signatures - * n: the number of signatures to combine (at least 1) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine( - const secp256k1_context* ctx, - unsigned char *sig64, - const unsigned char * const * sig64sin, - int n -) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in b/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in index 1c72dd0003..a0d006f113 100644 --- a/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in +++ b/crypto/secp256k1/libsecp256k1/libsecp256k1.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: libsecp256k1 Description: Optimized C library for EC operations on curve secp256k1 -URL: https://github.com/bitcoin/secp256k1 +URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs.private: @SECP_LIBS@ diff --git a/crypto/secp256k1/libsecp256k1/sage/group_prover.sage b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage new file mode 100644 index 0000000000..ab580c5b23 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/sage/group_prover.sage @@ -0,0 +1,322 @@ +# This code supports verifying group implementations which have branches +# or conditional statements (like cmovs), by allowing each execution path +# to independently set assumptions on input or intermediary variables. +# +# The general approach is: +# * A constraint is a tuple of two sets of of symbolic expressions: +# the first of which are required to evaluate to zero, the second of which +# are required to evaluate to nonzero. +# - A constraint is said to be conflicting if any of its nonzero expressions +# is in the ideal with basis the zero expressions (in other words: when the +# zero expressions imply that one of the nonzero expressions are zero). +# * There is a list of laws that describe the intended behaviour, including +# laws for addition and doubling. Each law is called with the symbolic point +# coordinates as arguments, and returns: +# - A constraint describing the assumptions under which it is applicable, +# called "assumeLaw" +# - A constraint describing the requirements of the law, called "require" +# * Implementations are transliterated into functions that operate as well on +# algebraic input points, and are called once per combination of branches +# exectured. Each execution returns: +# - A constraint describing the assumptions this implementation requires +# (such as Z1=1), called "assumeFormula" +# - A constraint describing the assumptions this specific branch requires, +# but which is by construction guaranteed to cover the entire space by +# merging the results from all branches, called "assumeBranch" +# - The result of the computation +# * All combinations of laws with implementation branches are tried, and: +# - If the combination of assumeLaw, assumeFormula, and assumeBranch results +# in a conflict, it means this law does not apply to this branch, and it is +# skipped. +# - For others, we try to prove the require constraints hold, assuming the +# information in assumeLaw + assumeFormula + assumeBranch, and if this does +# not succeed, we fail. +# + To prove an expression is zero, we check whether it belongs to the +# ideal with the assumed zero expressions as basis. This test is exact. +# + To prove an expression is nonzero, we check whether each of its +# factors is contained in the set of nonzero assumptions' factors. +# This test is not exact, so various combinations of original and +# reduced expressions' factors are tried. +# - If we succeed, we print out the assumptions from assumeFormula that +# weren't implied by assumeLaw already. Those from assumeBranch are skipped, +# as we assume that all constraints in it are complementary with each other. +# +# Based on the sage verification scripts used in the Explicit-Formulas Database +# by Tanja Lange and others, see http://hyperelliptic.org/EFD + +class fastfrac: + """Fractions over rings.""" + + def __init__(self,R,top,bot=1): + """Construct a fractional, given a ring, a numerator, and denominator.""" + self.R = R + if parent(top) == ZZ or parent(top) == R: + self.top = R(top) + self.bot = R(bot) + elif top.__class__ == fastfrac: + self.top = top.top + self.bot = top.bot * bot + else: + self.top = R(numerator(top)) + self.bot = R(denominator(top)) * bot + + def iszero(self,I): + """Return whether this fraction is zero given an ideal.""" + return self.top in I and self.bot not in I + + def reduce(self,assumeZero): + zero = self.R.ideal(map(numerator, assumeZero)) + return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) + + def __add__(self,other): + """Add two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top + self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __sub__(self,other): + """Subtract two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top - self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __neg__(self): + """Return the negation of a fraction.""" + return fastfrac(self.R,-self.top,self.bot) + + def __mul__(self,other): + """Multiply two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.top,self.bot * other.bot) + return NotImplemented + + def __rmul__(self,other): + """Multiply something else with a fraction.""" + return self.__mul__(other) + + def __div__(self,other): + """Divide two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top,self.bot * other) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot,self.bot * other.top) + return NotImplemented + + def __pow__(self,other): + """Compute a power of a fraction.""" + if parent(other) == ZZ: + if other < 0: + # Negative powers require flipping top and bottom + return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) + else: + return fastfrac(self.R,self.top ^ other,self.bot ^ other) + return NotImplemented + + def __str__(self): + return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" + def __repr__(self): + return "%s" % self + + def numerator(self): + return self.top + +class constraints: + """A set of constraints, consisting of zero and nonzero expressions. + + Constraints can either be used to express knowledge or a requirement. + + Both the fields zero and nonzero are maps from expressions to description + strings. The expressions that are the keys in zero are required to be zero, + and the expressions that are the keys in nonzero are required to be nonzero. + + Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in + nonzero could be multiplied into a single key. This is often much less + efficient to work with though, so we keep them separate inside the + constraints. This allows higher-level code to do fast checks on the individual + nonzero elements, or combine them if needed for stronger checks. + + We can't multiply the different zero elements, as it would suffice for one of + the factors to be zero, instead of all of them. Instead, the zero elements are + typically combined into an ideal first. + """ + + def __init__(self, **kwargs): + if 'zero' in kwargs: + self.zero = dict(kwargs['zero']) + else: + self.zero = dict() + if 'nonzero' in kwargs: + self.nonzero = dict(kwargs['nonzero']) + else: + self.nonzero = dict() + + def negate(self): + return constraints(zero=self.nonzero, nonzero=self.zero) + + def __add__(self, other): + zero = self.zero.copy() + zero.update(other.zero) + nonzero = self.nonzero.copy() + nonzero.update(other.nonzero) + return constraints(zero=zero, nonzero=nonzero) + + def __str__(self): + return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) + + def __repr__(self): + return "%s" % self + + +def conflicts(R, con): + """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" + zero = R.ideal(map(numerator, con.zero)) + if 1 in zero: + return True + # First a cheap check whether any of the individual nonzero terms conflict on + # their own. + for nonzero in con.nonzero: + if nonzero.iszero(zero): + return True + # It can be the case that entries in the nonzero set do not individually + # conflict with the zero set, but their combination does. For example, knowing + # that either x or y is zero is equivalent to having x*y in the zero set. + # Having x or y individually in the nonzero set is not a conflict, but both + # simultaneously is, so that is the right thing to check for. + if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): + return True + return False + + +def get_nonzero_set(R, assume): + """Calculate a simple set of nonzero expressions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = set() + for nz in map(numerator, assume.nonzero): + for (f,n) in nz.factor(): + nonzero.add(f) + rnz = zero.reduce(nz) + for (f,n) in rnz.factor(): + nonzero.add(f) + return nonzero + + +def prove_nonzero(R, exprs, assume): + """Check whether an expression is provably nonzero, given assumptions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = get_nonzero_set(R, assume) + expl = set() + ok = True + for expr in exprs: + if numerator(expr) in zero: + return (False, [exprs[expr]]) + allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) + for (f, n) in allexprs.factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for (f, n) in zero.reduce(numerator(allexprs)).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in numerator(expr).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in zero.reduce(numerator(expr)).factor(): + if f not in nonzero: + expl.add(exprs[expr]) + if expl: + return (False, list(expl)) + else: + return (True, None) + + +def prove_zero(R, exprs, assume): + """Check whether all of the passed expressions are provably zero, given assumptions""" + r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) + if not r: + return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) + zero = R.ideal(map(numerator, assume.zero)) + nonzero = prod(x for x in assume.nonzero) + expl = [] + for expr in exprs: + if not expr.iszero(zero): + expl.append(exprs[expr]) + if not expl: + return (True, None) + return (False, expl) + + +def describe_extra(R, assume, assumeExtra): + """Describe what assumptions are added, given existing assumptions""" + zerox = assume.zero.copy() + zerox.update(assumeExtra.zero) + zero = R.ideal(map(numerator, assume.zero)) + zeroextra = R.ideal(map(numerator, zerox)) + nonzero = get_nonzero_set(R, assume) + ret = set() + # Iterate over the extra zero expressions + for base in assumeExtra.zero: + if base not in zero: + add = [] + for (f, n) in numerator(base).factor(): + if f not in nonzero: + add += ["%s" % f] + if add: + ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) + # Iterate over the extra nonzero expressions + for nz in assumeExtra.nonzero: + nzr = zeroextra.reduce(numerator(nz)) + if nzr not in zeroextra: + for (f,n) in nzr.factor(): + if zeroextra.reduce(f) not in nonzero: + ret.add("%s != 0" % zeroextra.reduce(f)) + return ", ".join(x for x in ret) + + +def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): + """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" + assume = assumeLaw + assumeAssert + assumeBranch + + if conflicts(R, assume): + # This formula does not apply + return None + + describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + + ok, msg = prove_zero(R, require.zero, assume) + if not ok: + return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + + res, expl = prove_nonzero(R, require.nonzero, assume) + if not res: + return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + + if describe != "": + return "OK (assuming %s)" % describe + else: + return "OK" + + +def concrete_verify(c): + for k in c.zero: + if k != 0: + return (False, c.zero[k]) + for k in c.nonzero: + if k == 0: + return (False, c.nonzero[k]) + return (True, None) diff --git a/crypto/secp256k1/libsecp256k1/sage/secp256k1.sage b/crypto/secp256k1/libsecp256k1/sage/secp256k1.sage new file mode 100644 index 0000000000..a97e732f7f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/sage/secp256k1.sage @@ -0,0 +1,306 @@ +# Test libsecp256k1' group operation implementations using prover.sage + +import sys + +load("group_prover.sage") +load("weierstrass_prover.sage") + +def formula_secp256k1_gej_double_var(a): + """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" + rz = a.Z * a.Y + rz = rz * 2 + t1 = a.X^2 + t1 = t1 * 3 + t2 = t1^2 + t3 = a.Y^2 + t3 = t3 * 2 + t4 = t3^2 + t4 = t4 * 2 + t3 = t3 * a.X + rx = t3 + rx = rx * 4 + rx = -rx + rx = rx + t2 + t2 = -t2 + t3 = t3 * 6 + t3 = t3 + t2 + ry = t1 * t3 + t2 = -t4 + ry = ry + t2 + return jacobianpoint(rx, ry, rz) + +def formula_secp256k1_gej_add_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_var""" + if branch == 0: + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z22 = b.Z^2 + z12 = a.Z^2 + u1 = a.X * z22 + u2 = b.X * z12 + s1 = a.Y * z22 + s1 = s1 * b.Z + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) + if branch == 3: + return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h2 * h + h = h * b.Z + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" + if branch == 0: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z12 = a.Z^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if (branch == 2): + r = formula_secp256k1_gej_double_var(a) + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if (branch == 3): + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_zinv_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_zinv_var""" + bzinv = b.Z^(-1) + if branch == 0: + return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) + if branch == 1: + bzinv2 = bzinv^2 + bzinv3 = bzinv2 * bzinv + rx = b.X * bzinv2 + ry = b.Y * bzinv3 + rz = 1 + return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + azz = a.Z * bzinv + z12 = azz^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * azz + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if branch == 3: + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z + rz = rz * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge""" + zeroes = {} + nonzeroes = {} + a_infinity = False + if (branch & 4) != 0: + nonzeroes.update({a.Infinity : 'a_infinite'}) + a_infinity = True + else: + zeroes.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + rr = t^2 + m_alt = -u2 + tt = u1 * m_alt + rr = rr + tt + degenerate = (branch & 3) == 3 + if (branch & 1) != 0: + zeroes.update({m : 'm_zero'}) + else: + nonzeroes.update({m : 'm_nonzero'}) + if (branch & 2) != 0: + zeroes.update({rr : 'rr_zero'}) + else: + nonzeroes.update({rr : 'rr_nonzero'}) + rr_alt = s1 + rr_alt = rr_alt * 2 + m_alt = m_alt + u1 + if not degenerate: + rr_alt = rr + m_alt = m + n = m_alt^2 + q = n * t + n = n^2 + if degenerate: + n = m + t = rr_alt^2 + rz = a.Z * m_alt + infinity = False + if (branch & 8) != 0: + if not a_infinity: + infinity = True + zeroes.update({rz : 'r.z=0'}) + else: + nonzeroes.update({rz : 'r.z!=0'}) + rz = rz * 2 + q = -q + t = t + q + rx = t + t = t * 2 + t = t + q + t = t * rr_alt + t = t + n + ry = -t + rx = rx * 4 + ry = ry * 4 + if a_infinity: + rx = b.X + ry = b.Y + rz = 1 + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_old(branch, a, b): + """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" + a_infinity = (branch & 1) != 0 + zero = {} + nonzero = {} + if a_infinity: + nonzero.update({a.Infinity : 'a_infinite'}) + else: + zero.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + z = a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + n = m^2 + q = n * t + n = n^2 + rr = t^2 + t = u1 * u2 + t = -t + rr = rr + t + t = rr^2 + rz = m * z + infinity = False + if (branch & 2) != 0: + if not a_infinity: + infinity = True + else: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) + zero.update({rz : 'r.z=0'}) + else: + nonzero.update({rz : 'r.z!=0'}) + rz = rz * (0 if a_infinity else 2) + rx = t + q = -q + rx = rx + q + q = q * 3 + t = t * 2 + t = t + q + t = t * rr + t = t + n + ry = -t + rx = rx * (0 if a_infinity else 4) + ry = ry * (0 if a_infinity else 4) + t = b.X + t = t * (1 if a_infinity else 0) + rx = rx + t + t = b.Y + t = t * (1 if a_infinity else 0) + ry = ry + t + t = (1 if a_infinity else 0) + rz = rz + t + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) + +if __name__ == "__main__": + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) + + if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) diff --git a/crypto/secp256k1/libsecp256k1/sage/weierstrass_prover.sage b/crypto/secp256k1/libsecp256k1/sage/weierstrass_prover.sage new file mode 100644 index 0000000000..03ef2ec901 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/sage/weierstrass_prover.sage @@ -0,0 +1,264 @@ +# Prover implementation for Weierstrass curves of the form +# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws +# operating on affine and Jacobian coordinates, including the point at infinity +# represented by a 4th variable in coordinates. + +load("group_prover.sage") + + +class affinepoint: + def __init__(self, x, y, infinity=0): + self.x = x + self.y = y + self.infinity = infinity + def __str__(self): + return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) + + +class jacobianpoint: + def __init__(self, x, y, z, infinity=0): + self.X = x + self.Y = y + self.Z = z + self.Infinity = infinity + def __str__(self): + return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) + + +def point_at_infinity(): + return jacobianpoint(1, 1, 1, 1) + + +def negate(p): + if p.__class__ == affinepoint: + return affinepoint(p.x, -p.y) + if p.__class__ == jacobianpoint: + return jacobianpoint(p.X, -p.Y, p.Z) + assert(False) + + +def on_weierstrass_curve(A, B, p): + """Return a set of zero-expressions for an affine point to be on the curve""" + return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) + + +def tangential_to_weierstrass_curve(A, B, p12, p3): + """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" + return constraints(zero={ + (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' + }) + + +def colinear(p1, p2, p3): + """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" + return constraints(zero={ + (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', + (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', + (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' + }) + + +def good_affine_point(p): + return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) + + +def good_jacobian_point(p): + return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) + + +def good_point(p): + return constraints(nonzero={p.Z^6 : 'nonzero_X'}) + + +def finite(p, *affine_fns): + con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) + if p.Z != 0: + return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) + else: + return con + +def infinite(p): + return constraints(nonzero={p.Infinity : 'infinite_point'}) + + +def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(nonzero={pa.x - pb.x : 'different_x'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + colinear(pa, pb, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) + require = infinite(pC) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pb) + + infinite(pA) + + finite(pB)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + infinite(pB) + + finite(pA)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + infinite(pA) + + infinite(pB)) + require = infinite(pC) + return (assumeLaw, require) + + +laws_jacobian_weierstrass = { + 'add': law_jacobian_weierstrass_add, + 'double': law_jacobian_weierstrass_double, + 'add_opposite': law_jacobian_weierstrass_add_opposites, + 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, + 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, + 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab +} + + +def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" + F = Integers(p) + print "Formula %s on Z%i:" % (name, p) + points = [] + for x in xrange(0, p): + for y in xrange(0, p): + point = affinepoint(F(x), F(y)) + r, e = concrete_verify(on_weierstrass_curve(A, B, point)) + if r: + points.append(point) + + for za in xrange(1, p): + for zb in xrange(1, p): + for pa in points: + for pb in points: + for ia in xrange(2): + for ib in xrange(2): + pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) + pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) + for branch in xrange(0, branches): + assumeAssert, assumeBranch, pC = formula(branch, pA, pB) + pC.X = F(pC.X) + pC.Y = F(pC.Y) + pC.Z = F(pC.Z) + pC.Infinity = F(pC.Infinity) + r, e = concrete_verify(assumeAssert + assumeBranch) + if r: + match = False + for key in laws_jacobian_weierstrass: + assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) + r, e = concrete_verify(assumeLaw) + if r: + if match: + print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + else: + match = True + r, e = concrete_verify(require) + if not r: + print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) + print + + +def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): + assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) + return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) + +def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" + R. = PolynomialRing(QQ,8,order='invlex') + lift = lambda x: fastfrac(R,x) + ax = lift(ax) + ay = lift(ay) + Az = lift(Az) + bx = lift(bx) + by = lift(by) + Bz = lift(Bz) + Ai = lift(Ai) + Bi = lift(Bi) + + pa = affinepoint(ax, ay, Ai) + pb = affinepoint(bx, by, Bi) + pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) + pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) + + res = {} + + for key in laws_jacobian_weierstrass: + res[key] = [] + + print ("Formula " + name + ":") + count = 0 + for branch in xrange(branches): + assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + pC.X = lift(pC.X) + pC.Y = lift(pC.Y) + pC.Z = lift(pC.Z) + pC.Infinity = lift(pC.Infinity) + + for key in laws_jacobian_weierstrass: + res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + + for key in res: + print " %s:" % key + val = res[key] + for x in val: + if x[0] is not None: + print " branch %i: %s" % (x[1], x[0]) + + print diff --git a/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s b/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s new file mode 100644 index 0000000000..5df561f2fc --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/asm/field_10x26_arm.s @@ -0,0 +1,919 @@ +@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: +/********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +/* +ARM implementation of field_10x26 inner loops. + +Note: + +- To avoid unnecessary loads and make use of available registers, two + 'passes' have every time been interleaved, with the odd passes accumulating c' and d' + which will be added to c and d respectively in the the even passes + +*/ + + .syntax unified + .arch armv7-a + @ eabi attributes - see readelf -A + .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes + .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no + .eabi_attribute 10, 0 @ Tag_FP_arch = none + .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte + .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed + .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 + .text + + @ Field constants + .set field_R0, 0x3d10 + .set field_R1, 0x400 + .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff + + .align 2 + .global secp256k1_fe_mul_inner + .type secp256k1_fe_mul_inner, %function + @ Arguments: + @ r0 r Restrict: can overlap with a, not with b + @ r1 a + @ r2 b + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_mul_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r7,r8 scratch + r1 a (pointer) + r2 b (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + + /* A - interleaved with B */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #9*4] @ b[9] + ldr r0, [r1, #1*4] @ a[1] + umull r5, r6, r7, r8 @ d = a[0] * b[9] + ldr r14, [r2, #8*4] @ b[8] + umull r9, r10, r0, r8 @ d' = a[1] * b[9] + ldr r7, [r1, #2*4] @ a[2] + umlal r5, r6, r0, r14 @ d += a[1] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r14 @ d' += a[2] * b[8] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r8 @ d += a[2] * b[7] + ldr r14, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r8 @ d' += a[3] * b[7] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r14 @ d += a[3] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r14 @ d' += a[4] * b[6] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r8 @ d += a[4] * b[5] + ldr r14, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r8 @ d' += a[5] * b[5] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r14 @ d += a[5] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r14 @ d' += a[6] * b[4] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[3] + ldr r14, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r8 @ d' += a[7] * b[3] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[7] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r9, r10, r7, r14 @ d' += a[8] * b[2] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r8 @ d += a[8] * b[1] + ldr r14, [r2, #0*4] @ b[0] + umlal r9, r10, r0, r8 @ d' += a[9] * b[1] + ldr r7, [r1, #0*4] @ a[0] + umlal r5, r6, r0, r14 @ d += a[9] * b[0] + @ r7,r14 used in B + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 4*9] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + umull r3, r4, r7, r14 @ c = a[0] * b[0] + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C - interleaved with D */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #2*4] @ b[2] + ldr r14, [r2, #1*4] @ b[1] + umull r11, r12, r7, r8 @ c' = a[0] * b[2] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[1] * b[1] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[2] * b[0] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r14 @ d += a[2] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[3] * b[9] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r8 @ d += a[3] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[4] * b[8] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r14 @ d += a[4] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[5] * b[7] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r8 @ d += a[5] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r8 @ d' += a[6] * b[6] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r14 @ d' += a[7] * b[5] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r8 @ d' += a[8] * b[4] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r14 @ d' += a[9] * b[3] + umlal r5, r6, r0, r8 @ d += a[9] * b[2] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E - interleaved with F */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #4*4] @ b[4] + umull r11, r12, r7, r8 @ c' = a[0] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r3, r4, r7, r8 @ c += a[0] * b[3] + ldr r7, [r1, #1*4] @ a[1] + umlal r11, r12, r7, r8 @ c' += a[1] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r3, r4, r7, r8 @ c += a[1] * b[2] + ldr r7, [r1, #2*4] @ a[2] + umlal r11, r12, r7, r8 @ c' += a[2] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r3, r4, r7, r8 @ c += a[2] * b[1] + ldr r7, [r1, #3*4] @ a[3] + umlal r11, r12, r7, r8 @ c' += a[3] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r3, r4, r7, r8 @ c += a[3] * b[0] + ldr r7, [r1, #4*4] @ a[4] + umlal r11, r12, r7, r8 @ c' += a[4] * b[0] + ldr r8, [r2, #9*4] @ b[9] + umlal r5, r6, r7, r8 @ d += a[4] * b[9] + ldr r7, [r1, #5*4] @ a[5] + umull r9, r10, r7, r8 @ d' = a[5] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umlal r5, r6, r7, r8 @ d += a[5] * b[8] + ldr r7, [r1, #6*4] @ a[6] + umlal r9, r10, r7, r8 @ d' += a[6] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[7] + ldr r7, [r1, #7*4] @ a[7] + umlal r9, r10, r7, r8 @ d' += a[7] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r5, r6, r7, r8 @ d += a[7] * b[6] + ldr r7, [r1, #8*4] @ a[8] + umlal r9, r10, r7, r8 @ d' += a[8] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r5, r6, r7, r8 @ d += a[8] * b[5] + ldr r7, [r1, #9*4] @ a[9] + umlal r9, r10, r7, r8 @ d' += a[9] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r5, r6, r7, r8 @ d += a[9] * b[4] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G - interleaved with H */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #6*4] @ b[6] + ldr r14, [r2, #5*4] @ b[5] + umull r11, r12, r7, r8 @ c' = a[0] * b[6] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[1] * b[5] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[2] * b[4] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[3] * b[3] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[4] * b[2] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[5] * b[1] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[6] * b[0] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[7] * b[9] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[8] * b[8] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[9] * b[7] + umlal r5, r6, r0, r8 @ d += a[9] * b[6] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I - interleaved with J */ + ldr r8, [r2, #8*4] @ b[8] + ldr r7, [r1, #0*4] @ a[0] + ldr r14, [r2, #7*4] @ b[7] + umull r11, r12, r7, r8 @ c' = a[0] * b[8] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r11, r12, r0, r14 @ c' += a[1] * b[7] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r11, r12, r7, r8 @ c' += a[2] * b[6] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[3] * b[5] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[4] * b[4] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[5] * b[3] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[6] * b[2] + ldr r0, [r1, #7*4] @ a[7] + umlal r3, r4, r7, r14 @ c += a[6] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[7] * b[1] + ldr r7, [r1, #8*4] @ a[8] + umlal r3, r4, r0, r8 @ c += a[7] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[8] * b[0] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[9] * b[9] + umlal r5, r6, r0, r8 @ d += a[9] * b[8] + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner + + .align 2 + .global secp256k1_fe_sqr_inner + .type secp256k1_fe_sqr_inner, %function + @ Arguments: + @ r0 r Can overlap with a + @ r1 a + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_sqr_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r2,r7,r8 scratch + r1 a (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + /* A interleaved with B */ + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r7, [r1, #0*4] @ a[0] + mov r0, r0, asl #1 + ldr r14, [r1, #9*4] @ a[9] + umull r3, r4, r7, r7 @ c = a[0] * a[0] + ldr r8, [r1, #8*4] @ a[8] + mov r7, r7, asl #1 + umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] + ldr r7, [r1, #2*4] @ a[2]*2 + umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #3*4] @ a[3]*2 + umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] + ldr r14, [r1, #5*4] @ a[5] + mov r7, r7, asl #1 + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] + umlal r9, r10, r14, r14 @ d' += a[5] * a[5] + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 9*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C interleaved with D */ + ldr r0, [r1, #0*4] @ a[0]*2 + ldr r14, [r1, #1*4] @ a[1] + mov r0, r0, asl #1 + ldr r8, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] + mov r7, r8, asl #1 @ a[2]*2 + umull r11, r12, r14, r14 @ c' = a[1] * a[1] + ldr r14, [r1, #9*4] @ a[9] + umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] + ldr r0, [r1, #3*4] @ a[3]*2 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] + umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] + umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] + umlal r9, r10, r8, r8 @ d' += a[6] * a[6] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E interleaved with F */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r14, [r1, #2*4] @ a[2] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + ldr r2, [r1, #4*4] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] + mov r2, r2, asl #1 @ a[4]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] + ldr r8, [r1, #9*4] @ a[9] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r11, r12, r14, r14 @ c' += a[2] * a[2] + ldr r14, [r1, #8*4] @ a[8] + mov r0, r0, asl #1 + umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] + ldr r7, [r1, #6*4] @ a[6]*2 + umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] + umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] + umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] + umlal r9, r10, r8, r8 @ d' += a[7] * a[7] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G interleaved with H */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #5*4] @ a[5] + ldr r2, [r1, #6*4] @ a[6] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] + mov r0, r2, asl #1 @ a[6]*2 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] + ldr r14, [r1, #9*4] @ a[9] + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] + ldr r7, [r1, #7*4] @ a[7]*2 + umlal r11, r12, r8, r8 @ c' += a[3] * a[3] + mov r7, r7, asl #1 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] + umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] + umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] + umlal r9, r10, r8, r8 @ d' += a[8] * a[8] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I interleaved with J */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + ldr r2, [r1, #8*4] @ a[8] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] + ldr r14, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] + ldr r8, [r1, #5*4] @ a[5] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] + ldr r0, [r1, #3*4] @ a[3]*2 + mov r7, r7, asl #1 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] + mov r2, r2, asl #1 @ a[8]*2 + umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] + umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] + umlal r11, r12, r14, r14 @ c' += a[4] * a[4] + ldr r8, [r1, #9*4] @ a[9] + umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] + @ r8 will be used in J + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + umlal r5, r6, r8, r8 @ d += a[9] * a[9] + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + diff --git a/crypto/secp256k1/libsecp256k1/src/bench_ecdh.c b/crypto/secp256k1/libsecp256k1/src/bench_ecdh.c index 5a7c6376e0..cde5e2dbb4 100644 --- a/crypto/secp256k1/libsecp256k1/src/bench_ecdh.c +++ b/crypto/secp256k1/libsecp256k1/src/bench_ecdh.c @@ -28,7 +28,8 @@ static void bench_ecdh_setup(void* arg) { 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f }; - data->ctx = secp256k1_context_create(0); + /* create a context with no capabilities */ + data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); for (i = 0; i < 32; i++) { data->scalar[i] = i + 1; } diff --git a/crypto/secp256k1/libsecp256k1/src/bench_internal.c b/crypto/secp256k1/libsecp256k1/src/bench_internal.c index 7809f5f8cf..0809f77bda 100644 --- a/crypto/secp256k1/libsecp256k1/src/bench_internal.c +++ b/crypto/secp256k1/libsecp256k1/src/bench_internal.c @@ -181,12 +181,12 @@ void bench_field_inverse_var(void* arg) { } } -void bench_field_sqrt_var(void* arg) { +void bench_field_sqrt(void* arg) { int i; bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 20000; i++) { - secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x); + secp256k1_fe_sqrt(&data->fe_x, &data->fe_x); secp256k1_fe_add(&data->fe_x, &data->fe_y); } } @@ -227,6 +227,15 @@ void bench_group_add_affine_var(void* arg) { } } +void bench_group_jacobi_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_gej_has_quad_y_var(&data->gej_x); + } +} + void bench_ecmult_wnaf(void* arg) { int i; bench_inv_t *data = (bench_inv_t*)arg; @@ -299,6 +308,21 @@ void bench_context_sign(void* arg) { } } +#ifndef USE_NUM_NONE +void bench_num_jacobi(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_num nx, norder; + + secp256k1_scalar_get_num(&nx, &data->scalar_x); + secp256k1_scalar_order_get_num(&norder); + secp256k1_scalar_get_num(&norder, &data->scalar_y); + + for (i = 0; i < 200000; i++) { + secp256k1_num_jacobi(&nx, &norder); + } +} +#endif int have_flag(int argc, char** argv, char *flag) { char** argm = argv + argc; @@ -333,12 +357,13 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); @@ -350,5 +375,8 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); +#ifndef USE_NUM_NONE + if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000); +#endif return 0; } diff --git a/crypto/secp256k1/libsecp256k1/src/bench_verify.c b/crypto/secp256k1/libsecp256k1/src/bench_verify.c index 0cafbdc4e6..418defa0aa 100644 --- a/crypto/secp256k1/libsecp256k1/src/bench_verify.c +++ b/crypto/secp256k1/libsecp256k1/src/bench_verify.c @@ -11,6 +11,12 @@ #include "util.h" #include "bench.h" +#ifdef ENABLE_OPENSSL_TESTS +#include +#include +#include +#endif + typedef struct { secp256k1_context *ctx; unsigned char msg[32]; @@ -19,6 +25,9 @@ typedef struct { size_t siglen; unsigned char pubkey[33]; size_t pubkeylen; +#ifdef ENABLE_OPENSSL_TESTS + EC_GROUP* ec_group; +#endif } benchmark_verify_t; static void benchmark_verify(void* arg) { @@ -40,6 +49,36 @@ static void benchmark_verify(void* arg) { } } +#ifdef ENABLE_OPENSSL_TESTS +static void benchmark_verify_openssl(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + { + EC_KEY *pkey = EC_KEY_new(); + const unsigned char *pubkey = &data->pubkey[0]; + int result; + + CHECK(pkey != NULL); + result = EC_KEY_set_group(pkey, data->ec_group); + CHECK(result); + result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL; + CHECK(result); + result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0); + CHECK(result); + EC_KEY_free(pkey); + } + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} +#endif + int main(void) { int i; secp256k1_pubkey pubkey; @@ -58,9 +97,15 @@ int main(void) { CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); + data.pubkeylen = 33; CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); +#ifdef ENABLE_OPENSSL_TESTS + data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1); + run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); + EC_GROUP_free(data.ec_group); +#endif secp256k1_context_destroy(data.ctx); return 0; diff --git a/crypto/secp256k1/libsecp256k1/src/ecdsa.h b/crypto/secp256k1/libsecp256k1/src/ecdsa.h index 4c0a4a89e0..54ae101b92 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecdsa.h +++ b/crypto/secp256k1/libsecp256k1/src/ecdsa.h @@ -17,6 +17,5 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, c static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid); #endif diff --git a/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h b/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h index 4a172b3c51..453bb11880 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -46,66 +46,133 @@ static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CON 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); +static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { + int lenleft, b1; + size_t ret = 0; + if (*sigp >= sigend) { + return -1; + } + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return -1; + } + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + return b1; + } + if (b1 == 0x80) { + /* Indefinite length is not allowed in DER. */ + return -1; + } + /* X.690-207 8.1.3.5 long form length octets */ + lenleft = b1 & 0x7F; + if (lenleft > sigend - *sigp) { + return -1; + } + if (**sigp == 0) { + /* Not the shortest possible length encoding. */ + return -1; + } + if ((size_t)lenleft > sizeof(size_t)) { + /* The resulting length would exceed the range of a size_t, so + * certainly longer than the passed array size. + */ + return -1; + } + while (lenleft > 0) { + if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) { + } + ret = (ret << 8) | **sigp; + if (ret + lenleft > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. */ + return -1; + } + (*sigp)++; + lenleft--; + } + if (ret < 128) { + /* Not the shortest possible length encoding. */ + return -1; + } + return ret; +} + +static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { + int overflow = 0; + unsigned char ra[32] = {0}; + int rlen; + + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ + return 0; + } + (*sig)++; + rlen = secp256k1_der_read_len(sig, sigend); + if (rlen <= 0 || (*sig) + rlen > sigend) { + /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ + return 0; + } + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ + return 0; + } + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ + return 0; + } + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; + } + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; + } + if (rlen > 32) { + overflow = 1; + } + if (!overflow) { + memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_scalar_set_b32(r, ra, &overflow); + } + if (overflow) { + secp256k1_scalar_set_int(r, 0); + } + (*sig) += rlen; + return 1; +} + static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { - unsigned char ra[32] = {0}, sa[32] = {0}; - const unsigned char *rp; - const unsigned char *sp; - size_t lenr; - size_t lens; - int overflow; - if (sig[0] != 0x30) { + const unsigned char *sigend = sig + size; + int rlen; + if (sig == sigend || *(sig++) != 0x30) { + /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ return 0; } - lenr = sig[3]; - if (5+lenr >= size) { + rlen = secp256k1_der_read_len(&sig, sigend); + if (rlen < 0 || sig + rlen > sigend) { + /* Tuple exceeds bounds */ return 0; } - lens = sig[lenr+5]; - if (sig[1] != lenr+lens+4) { + if (sig + rlen != sigend) { + /* Garbage after tuple. */ return 0; } - if (lenr+lens+6 > size) { + + if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { return 0; } - if (sig[2] != 0x02) { + if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { return 0; } - if (lenr == 0) { - return 0; - } - if (sig[lenr+4] != 0x02) { - return 0; - } - if (lens == 0) { - return 0; - } - sp = sig + 6 + lenr; - while (lens > 0 && sp[0] == 0) { - lens--; - sp++; - } - if (lens > 32) { - return 0; - } - rp = sig + 4; - while (lenr > 0 && rp[0] == 0) { - lenr--; - rp++; - } - if (lenr > 32) { - return 0; - } - memcpy(ra + 32 - lenr, rp, lenr); - memcpy(sa + 32 - lens, sp, lens); - overflow = 0; - secp256k1_scalar_set_b32(rr, ra, &overflow); - if (overflow) { - return 0; - } - secp256k1_scalar_set_b32(rs, sa, &overflow); - if (overflow) { + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ return 0; } + return 1; } @@ -136,7 +203,9 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { unsigned char c[32]; secp256k1_scalar sn, u1, u2; +#if !defined(EXHAUSTIVE_TEST_ORDER) secp256k1_fe xr; +#endif secp256k1_gej pubkeyj; secp256k1_gej pr; @@ -152,6 +221,19 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const if (secp256k1_gej_is_infinity(&pr)) { return 0; } + +#if defined(EXHAUSTIVE_TEST_ORDER) +{ + secp256k1_scalar computed_r; + secp256k1_ge pr_ge; + secp256k1_ge_set_gej(&pr_ge, &pr); + secp256k1_fe_normalize(&pr_ge.x); + + secp256k1_fe_get_b32(c, &pr_ge.x); + secp256k1_scalar_set_b32(&computed_r, c, NULL); + return secp256k1_scalar_eq(sigr, &computed_r); +} +#else secp256k1_scalar_get_b32(c, sigr); secp256k1_fe_set_b32(&xr, c); @@ -172,11 +254,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. */ if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */ + /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ return 1; } if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - /* xr + p >= n, so we can skip testing the second case. */ + /* xr + n >= p, so we can skip testing the second case. */ return 0; } secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); @@ -185,39 +267,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const return 1; } return 0; -} - -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { - unsigned char brx[32]; - secp256k1_fe fx; - secp256k1_ge x; - secp256k1_gej xj; - secp256k1_scalar rn, u1, u2; - secp256k1_gej qj; - - if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { - return 0; - } - - secp256k1_scalar_get_b32(brx, sigr); - VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ - if (recid & 2) { - if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - return 0; - } - secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); - } - if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { - return 0; - } - secp256k1_gej_set_ge(&xj, &x); - secp256k1_scalar_inverse_var(&rn, sigr); - secp256k1_scalar_mul(&u1, &rn, message); - secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, sigs); - secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); - secp256k1_ge_set_gej_var(pubkey, &qj); - return !secp256k1_gej_is_infinity(&qj); +#endif } static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { @@ -233,13 +283,14 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); secp256k1_scalar_set_b32(sigr, b, &overflow); - if (secp256k1_scalar_is_zero(sigr)) { - /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */ - secp256k1_gej_clear(&rp); - secp256k1_ge_clear(&r); - return 0; - } + /* These two conditions should be checked before calling */ + VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr)); + VERIFY_CHECK(overflow == 0); + if (recid) { + /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log + * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. + */ *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); } secp256k1_scalar_mul(&n, sigr, seckey); diff --git a/crypto/secp256k1/libsecp256k1/src/eckey.h b/crypto/secp256k1/libsecp256k1/src/eckey.h index 71c4096dfb..42739a3bea 100644 --- a/crypto/secp256k1/libsecp256k1/src/eckey.h +++ b/crypto/secp256k1/libsecp256k1/src/eckey.h @@ -15,10 +15,7 @@ #include "ecmult_gen.h" static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, unsigned int flags); - -static int secp256k1_eckey_privkey_parse(secp256k1_scalar *key, const unsigned char *privkey, size_t privkeylen); -static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context *ctx, unsigned char *privkey, size_t *privkeylen, const secp256k1_scalar *key, unsigned int flags); +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); diff --git a/crypto/secp256k1/libsecp256k1/src/eckey_impl.h b/crypto/secp256k1/libsecp256k1/src/eckey_impl.h index ae44240152..ce38071ac2 100644 --- a/crypto/secp256k1/libsecp256k1/src/eckey_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/eckey_impl.h @@ -33,14 +33,14 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char } } -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, unsigned int flags) { +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { if (secp256k1_ge_is_infinity(elem)) { return 0; } secp256k1_fe_normalize_var(&elem->x); secp256k1_fe_normalize_var(&elem->y); secp256k1_fe_get_b32(&pub[1], &elem->x); - if (flags & SECP256K1_EC_COMPRESSED) { + if (compressed) { *size = 33; pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); } else { @@ -51,109 +51,6 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p return 1; } -static int secp256k1_eckey_privkey_parse(secp256k1_scalar *key, const unsigned char *privkey, size_t privkeylen) { - unsigned char c[32] = {0}; - const unsigned char *end = privkey + privkeylen; - int lenb = 0; - int len = 0; - int overflow = 0; - /* sequence header */ - if (end < privkey+1 || *privkey != 0x30) { - return 0; - } - privkey++; - /* sequence length constructor */ - if (end < privkey+1 || !(*privkey & 0x80)) { - return 0; - } - lenb = *privkey & ~0x80; privkey++; - if (lenb < 1 || lenb > 2) { - return 0; - } - if (end < privkey+lenb) { - return 0; - } - /* sequence length */ - len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); - privkey += lenb; - if (end < privkey+len) { - return 0; - } - /* sequence element 0: version number (=1) */ - if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { - return 0; - } - privkey += 3; - /* sequence element 1: octet string, up to 32 bytes */ - if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { - return 0; - } - memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]); - secp256k1_scalar_set_b32(key, c, &overflow); - memset(c, 0, 32); - return !overflow; -} - -static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context *ctx, unsigned char *privkey, size_t *privkeylen, const secp256k1_scalar *key, unsigned int flags) { - secp256k1_gej rp; - secp256k1_ge r; - size_t pubkeylen = 0; - secp256k1_ecmult_gen(ctx, &rp, key); - secp256k1_ge_set_gej(&r, &rp); - if (flags & SECP256K1_EC_COMPRESSED) { - static const unsigned char begin[] = { - 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } else { - static const unsigned char begin[] = { - 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, - 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, - 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } - return 1; -} - static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { secp256k1_scalar_add(key, key, tweak); if (secp256k1_scalar_is_zero(key)) { diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h index 90ac94770e..0db314c48e 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_const_impl.h @@ -58,25 +58,27 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { int global_sign; int skew = 0; int word = 0; + /* 1 2 3 */ int u_last; int u; -#ifdef USE_ENDOMORPHISM int flip; int bit; secp256k1_scalar neg_s; int not_neg_one; - /* If we are using the endomorphism, we cannot handle even numbers by negating - * them, since we are working with 128-bit numbers whose negations would be 256 - * bits, eliminating the performance advantage. Instead we use a technique from + /* Note that we cannot handle even numbers by negating them to be odd, as is + * done in other implementations, since if our scalars were specified to have + * width < 256 for performance reasons, their negations would have width 256 + * and we'd lose any performance benefit. Instead, we use a technique from * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) - * or 2 (for odd) to the number we are encoding, then compensating after the - * multiplication. */ - /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */ + * or 2 (for odd) to the number we are encoding, returning a skew value indicating + * this, and having the caller compensate after doing the multiplication. */ + + /* Negative numbers will be negated to keep their bit representation below the maximum width */ flip = secp256k1_scalar_is_high(&s); /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ - bit = flip ^ (s.d[0] & 1); + bit = flip ^ !secp256k1_scalar_is_even(&s); /* We check for negative one, since adding 2 to it will cause an overflow */ secp256k1_scalar_negate(&neg_s, &s); not_neg_one = !secp256k1_scalar_is_one(&neg_s); @@ -89,11 +91,6 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { global_sign = secp256k1_scalar_cond_negate(&s, flip); global_sign *= not_neg_one * 2 - 1; skew = 1 << bit; -#else - /* Otherwise, we just negate to force oddness */ - int is_even = secp256k1_scalar_is_even(&s); - global_sign = secp256k1_scalar_cond_negate(&s, is_even); -#endif /* 4 */ u_last = secp256k1_scalar_shr_int(&s, w); @@ -127,15 +124,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons secp256k1_ge tmpa; secp256k1_fe Z; + int skew_1; + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; #ifdef USE_ENDOMORPHISM secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; - int skew_1; int skew_lam; secp256k1_scalar q_1, q_lam; -#else - int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)]; #endif int i; @@ -145,18 +140,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons #ifdef USE_ENDOMORPHISM /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); - /* no need for zero correction when using endomorphism since even - * numbers have one added to them anyway */ skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); #else - int is_zero = secp256k1_scalar_is_zero(scalar); - /* the wNAF ladder cannot handle zero, so bump this to one .. we will - * correct the result after the fact */ - sc.d[0] += is_zero; - VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc)); - - secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1); + skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1); #endif /* Calculate odd multiples of a. @@ -179,21 +166,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons /* first loop iteration (separated out so we can directly set r, rather * than having it start at infinity, get doubled several times, then have * its new value added to it) */ -#ifdef USE_ENDOMORPHISM i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; VERIFY_CHECK(i != 0); ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); secp256k1_gej_set_ge(r, &tmpa); - +#ifdef USE_ENDOMORPHISM i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)]; VERIFY_CHECK(i != 0); ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); secp256k1_gej_add_ge(r, r, &tmpa); -#else - i = wnaf[WNAF_SIZE(WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); - secp256k1_gej_set_ge(r, &tmpa); #endif /* remaining loop iterations */ for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { @@ -202,59 +183,57 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons for (j = 0; j < WINDOW_A - 1; ++j) { secp256k1_gej_double_nonzero(r, r, NULL); } -#ifdef USE_ENDOMORPHISM + n = wnaf_1[i]; ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); VERIFY_CHECK(n != 0); secp256k1_gej_add_ge(r, r, &tmpa); - +#ifdef USE_ENDOMORPHISM n = wnaf_lam[i]; ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); VERIFY_CHECK(n != 0); secp256k1_gej_add_ge(r, r, &tmpa); -#else - n = wnaf[i]; - VERIFY_CHECK(n != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - secp256k1_gej_add_ge(r, r, &tmpa); #endif } secp256k1_fe_mul(&r->z, &r->z, &Z); -#ifdef USE_ENDOMORPHISM { /* Correct for wNAF skew */ secp256k1_ge correction = *a; secp256k1_ge_storage correction_1_stor; +#ifdef USE_ENDOMORPHISM secp256k1_ge_storage correction_lam_stor; +#endif secp256k1_ge_storage a2_stor; secp256k1_gej tmpj; secp256k1_gej_set_ge(&tmpj, &correction); secp256k1_gej_double_var(&tmpj, &tmpj, NULL); secp256k1_ge_set_gej(&correction, &tmpj); secp256k1_ge_to_storage(&correction_1_stor, a); +#ifdef USE_ENDOMORPHISM secp256k1_ge_to_storage(&correction_lam_stor, a); +#endif secp256k1_ge_to_storage(&a2_stor, &correction); /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); +#ifdef USE_ENDOMORPHISM secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); +#endif /* Apply the correction */ secp256k1_ge_from_storage(&correction, &correction_1_stor); secp256k1_ge_neg(&correction, &correction); secp256k1_gej_add_ge(r, r, &correction); +#ifdef USE_ENDOMORPHISM secp256k1_ge_from_storage(&correction, &correction_lam_stor); secp256k1_ge_neg(&correction, &correction); secp256k1_ge_mul_lambda(&correction, &correction); secp256k1_gej_add_ge(r, r, &correction); - } -#else - /* correct for zero */ - r->infinity |= is_zero; #endif + } } #endif diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h index 2ee27377f1..35f2546077 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_gen_impl.h @@ -40,8 +40,13 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; secp256k1_fe nums_x; secp256k1_ge nums_ge; - VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); - VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0)); + int r; + r = secp256k1_fe_set_b32(&nums_x, nums_b32); + (void)r; + VERIFY_CHECK(r); + r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); + (void)r; + VERIFY_CHECK(r); secp256k1_gej_set_ge(&nums_gej, &nums_ge); /* Add G to make the bits in x uniformly distributed. */ secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); @@ -72,7 +77,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); } } - secp256k1_ge_set_all_gej_var(1024, prec, precj, cb); + secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb); } for (j = 0; j < 64; j++) { for (i = 0; i < 16; i++) { @@ -182,7 +187,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); retry = !secp256k1_fe_set_b32(&s, nonce32); retry |= secp256k1_fe_is_zero(&s); - } while (retry); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ /* Randomize the projection to defend against multiplier sidechannels. */ secp256k1_gej_rescale(&ctx->initial, &s); secp256k1_fe_clear(&s); @@ -191,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_scalar_set_b32(&b, nonce32, &retry); /* A blinding value of 0 works, but would undermine the projection hardening. */ retry |= secp256k1_scalar_is_zero(&b); - } while (retry); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ secp256k1_rfc6979_hmac_sha256_finalize(&rng); memset(nonce32, 0, 32); secp256k1_ecmult_gen(ctx, &gb, &b); diff --git a/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h b/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h index e6e5f47188..4e40104ad4 100644 --- a/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/ecmult_impl.h @@ -7,13 +7,29 @@ #ifndef _SECP256K1_ECMULT_IMPL_H_ #define _SECP256K1_ECMULT_IMPL_H_ +#include + #include "group.h" #include "scalar.h" #include "ecmult.h" +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to lower these values for exhaustive tests because + * the tables cannot have infinities in them (this breaks the + * affine-isomorphism stuff which tracks z-ratios) */ +# if EXHAUSTIVE_TEST_ORDER > 128 +# define WINDOW_A 5 +# define WINDOW_G 8 +# elif EXHAUSTIVE_TEST_ORDER > 8 +# define WINDOW_A 4 +# define WINDOW_G 4 +# else +# define WINDOW_A 2 +# define WINDOW_G 2 +# endif +#else /* optimal for 128-bit and 256-bit exponents. */ #define WINDOW_A 5 - /** larger numbers may result in slightly better performance, at the cost of exponentially larger precomputed tables. */ #ifdef USE_ENDOMORPHISM @@ -23,6 +39,7 @@ /** One table for window size 16: 1.375 MiB. */ #define WINDOW_G 16 #endif +#endif /** The number of entries a table with precomputed multiples needs to have. */ #define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) @@ -101,7 +118,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge /* Compute the odd multiples in Jacobian form. */ secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); /* Convert them in batch to affine coordinates. */ - secp256k1_ge_set_table_gej_var(n, prea, prej, zr); + secp256k1_ge_set_table_gej_var(prea, prej, zr, n); /* Convert them to compact storage form. */ for (i = 0; i < n; i++) { secp256k1_ge_to_storage(&pre[i], &prea[i]); diff --git a/crypto/secp256k1/libsecp256k1/src/field.h b/crypto/secp256k1/libsecp256k1/src/field.h index 311329b927..bbb1ee866c 100644 --- a/crypto/secp256k1/libsecp256k1/src/field.h +++ b/crypto/secp256k1/libsecp256k1/src/field.h @@ -10,7 +10,7 @@ /** Field element module. * * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properaties into account: + * it (and implementations) need to take certain properties into account: * - Each field element can be normalized or not. * - Each field element has a magnitude, which represents how far away * its representation is away from normalization. Normalized elements @@ -30,6 +30,8 @@ #error "Please select field implementation" #endif +#include "util.h" + /** Normalize a field element. */ static void secp256k1_fe_normalize(secp256k1_fe *r); @@ -50,6 +52,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); /** Set a field element equal to a small integer. Resulting field element is normalized. */ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); +/** Sets a field element equal to zero, initializing all fields. */ +static void secp256k1_fe_clear(secp256k1_fe *a); + /** Verify whether a field element is zero. Requires the input to be normalized. */ static int secp256k1_fe_is_zero(const secp256k1_fe *a); @@ -57,6 +62,9 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a); static int secp256k1_fe_is_odd(const secp256k1_fe *a); /** Compare two field elements. Requires magnitude-1 inputs. */ +static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Same as secp256k1_fe_equal, but may be variable time. */ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ @@ -87,10 +95,15 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2 * The output magnitude is 1 (but not guaranteed to be normalized). */ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); -/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the - * input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be - * normalized). Return value indicates whether a square root was found. */ -static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a); +/** If a has a square root, it is computed in r and 1 is returned. If a does not + * have a square root, the root of its negation is computed and 0 is returned. + * The input's magnitude can be at most 8. The output magnitude is 1 (but not + * guaranteed to be normalized). The result in r will always be a square + * itself. */ +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); + +/** Checks whether a field element is a quadratic residue. */ +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a); /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ @@ -102,7 +115,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); /** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and * outputs must not overlap in memory. */ -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a); +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len); /** Convert a field element to the storage type. */ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); diff --git a/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h b/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h index 212cc5396a..5fb092f1be 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_10x26_impl.h @@ -7,8 +7,6 @@ #ifndef _SECP256K1_FIELD_REPR_IMPL_H_ #define _SECP256K1_FIELD_REPR_IMPL_H_ -#include -#include #include "util.h" #include "num.h" #include "field.h" @@ -40,10 +38,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { } VERIFY_CHECK(r == 1); } -#else -static void secp256k1_fe_verify(const secp256k1_fe *a) { - (void)a; -} #endif static void secp256k1_fe_normalize(secp256k1_fe *r) { @@ -429,6 +423,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f #endif } +#if defined(USE_EXTERNAL_ASM) + +/* External assembler implementation */ +void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); +void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); + +#else + #ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) #else @@ -1037,7 +1039,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t VERIFY_BITS(r[2], 27); /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } - +#endif static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY diff --git a/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h b/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h index b31e24ab81..dd88f38c77 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_5x52_impl.h @@ -11,7 +11,6 @@ #include "libsecp256k1-config.h" #endif -#include #include "util.h" #include "num.h" #include "field.h" @@ -50,10 +49,6 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { } VERIFY_CHECK(r == 1); } -#else -static void secp256k1_fe_verify(const secp256k1_fe *a) { - (void)a; -} #endif static void secp256k1_fe_normalize(secp256k1_fe *r) { diff --git a/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h b/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h index 9280bb5ea2..0bf22bdd3e 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_5x52_int128_impl.h @@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t VERIFY_BITS(r[2], 52); VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; @@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; diff --git a/crypto/secp256k1/libsecp256k1/src/field_impl.h b/crypto/secp256k1/libsecp256k1/src/field_impl.h index 551a6243e2..5127b279bc 100644 --- a/crypto/secp256k1/libsecp256k1/src/field_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/field_impl.h @@ -21,6 +21,13 @@ #error "Please select field implementation" #endif +SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero(&na); +} + SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe na; secp256k1_fe_negate(&na, a, 1); @@ -28,7 +35,16 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const return secp256k1_fe_normalizes_to_zero_var(&na); } -static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) { +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j; @@ -114,7 +130,7 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - return secp256k1_fe_equal_var(&t1, a); + return secp256k1_fe_equal(&t1, a); } static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { @@ -224,6 +240,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F }; unsigned char b[32]; + int res; secp256k1_fe c = *a; secp256k1_fe_normalize_var(&c); secp256k1_fe_get_b32(b, &c); @@ -231,7 +248,9 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_num_set_bin(&m, prime, 32); secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); - VERIFY_CHECK(secp256k1_fe_set_b32(r, b)); + res = secp256k1_fe_set_b32(r, b); + (void)res; + VERIFY_CHECK(res); /* Verify the result is the (unique) valid inverse using non-GMP code. */ secp256k1_fe_mul(&c, &c, r); secp256k1_fe_add(&c, &negone); @@ -241,7 +260,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { #endif } -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) { +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) { secp256k1_fe u; size_t i; if (len < 1) { @@ -268,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k r[0] = u; } +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) { +#ifndef USE_NUM_NONE + unsigned char b[32]; + secp256k1_num n; + secp256k1_num m; + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; + + secp256k1_fe c = *a; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_set_bin(&m, prime, 32); + return secp256k1_num_jacobi(&n, &m) >= 0; +#else + secp256k1_fe r; + return secp256k1_fe_sqrt(&r, a); +#endif +} + #endif diff --git a/crypto/secp256k1/libsecp256k1/src/group.h b/crypto/secp256k1/libsecp256k1/src/group.h index 89b079d5c6..4957b248fe 100644 --- a/crypto/secp256k1/libsecp256k1/src/group.h +++ b/crypto/secp256k1/libsecp256k1/src/group.h @@ -40,12 +40,15 @@ typedef struct { #define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) -/** Set a group element equal to the point at infinity */ -static void secp256k1_ge_set_infinity(secp256k1_ge *r); - /** Set a group element equal to the point with given X and Y coordinates */ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); +/** Set a group element (affine) equal to the point with the given X coordinate + * and a Y coordinate that is a quadratic residue modulo p. The return value + * is true iff a coordinate with the given X coordinate exists. + */ +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x); + /** Set a group element (affine) equal to the point with the given X coordinate, and given oddness * for Y. Return value indicates whether the result is valid. */ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); @@ -62,12 +65,12 @@ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); /** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb); +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb); /** Set a batch of group elements equal to the inputs given in jacobian * coordinates (with known z-ratios). zr must contain the known z-ratios such * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ -static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr); +static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len); /** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to * the same global z "denominator". zr must contain the known z-ratios such @@ -79,9 +82,6 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp /** Set a group element (jacobian) equal to the point at infinity. */ static void secp256k1_gej_set_infinity(secp256k1_gej *r); -/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */ -static void secp256k1_gej_set_xy(secp256k1_gej *r, const secp256k1_fe *x, const secp256k1_fe *y); - /** Set a group element (jacobian) equal to another which is given in affine coordinates. */ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); @@ -94,6 +94,9 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); /** Check whether a group element is the point at infinity. */ static int secp256k1_gej_is_infinity(const secp256k1_gej *a); +/** Check whether a group element's y coordinate is a quadratic residue. */ +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a); + /** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). * a may not be zero. Constant time. */ static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); diff --git a/crypto/secp256k1/libsecp256k1/src/group_impl.h b/crypto/secp256k1/libsecp256k1/src/group_impl.h index fe0a35929c..7d723532ff 100644 --- a/crypto/secp256k1/libsecp256k1/src/group_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/group_impl.h @@ -7,12 +7,57 @@ #ifndef _SECP256K1_GROUP_IMPL_H_ #define _SECP256K1_GROUP_IMPL_H_ -#include - #include "num.h" #include "field.h" #include "group.h" +/* These points can be generated in sage as follows: + * + * 0. Setup a worksheet with the following parameters. + * b = 4 # whatever CURVE_B will be set to + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (b)]) + * + * 1. Determine all the small orders available to you. (If there are + * no satisfactory ones, go back and change b.) + * print C.order().factor(limit=1000) + * + * 2. Choose an order as one of the prime factors listed in the above step. + * (You can also multiply some to get a composite order, though the + * tests will crash trying to invert scalars during signing.) We take a + * random point and scale it to drop its order to the desired value. + * There is some probability this won't work; just try again. + * order = 199 + * P = C.random_point() + * P = (int(P.order()) / int(order)) * P + * assert(P.order() == order) + * + * 3. Print the values. You'll need to use a vim macro or something to + * split the hex output into 4-byte chunks. + * print "%x %x" % P.xy() + */ +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 199 +const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069, + 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18, + 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868, + 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED +); + +const int CURVE_B = 4; +# elif EXHAUSTIVE_TEST_ORDER == 13 +const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0, + 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15, + 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e, + 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac +); +const int CURVE_B = 2; +# else +# error No known generator for the specified exhaustive test group order. +# endif +#else /** Generator for secp256k1, value 'g' defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ @@ -23,8 +68,11 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL ); +const int CURVE_B = 7; +#endif + static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { - secp256k1_fe zi2; + secp256k1_fe zi2; secp256k1_fe zi3; secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi); @@ -33,10 +81,6 @@ static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, c r->infinity = a->infinity; } -static void secp256k1_ge_set_infinity(secp256k1_ge *r) { - r->infinity = 1; -} - static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { r->infinity = 0; r->x = *x; @@ -82,7 +126,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { r->y = a->y; } -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) { +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) { secp256k1_fe *az; secp256k1_fe *azi; size_t i; @@ -95,7 +139,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp } azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); - secp256k1_fe_inv_all_var(count, azi, az); + secp256k1_fe_inv_all_var(azi, az, count); free(az); count = 0; @@ -108,7 +152,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp free(azi); } -static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) { +static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) { size_t i = len - 1; secp256k1_fe zi; @@ -151,16 +195,9 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp static void secp256k1_gej_set_infinity(secp256k1_gej *r) { r->infinity = 1; - secp256k1_fe_set_int(&r->x, 0); - secp256k1_fe_set_int(&r->y, 0); - secp256k1_fe_set_int(&r->z, 0); -} - -static void secp256k1_gej_set_xy(secp256k1_gej *r, const secp256k1_fe *x, const secp256k1_fe *y) { - r->infinity = 0; - r->x = *x; - r->y = *y; - secp256k1_fe_set_int(&r->z, 1); + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); + secp256k1_fe_clear(&r->z); } static void secp256k1_gej_clear(secp256k1_gej *r) { @@ -176,15 +213,19 @@ static void secp256k1_ge_clear(secp256k1_ge *r) { secp256k1_fe_clear(&r->y); } -static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) { secp256k1_fe x2, x3, c; r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; - secp256k1_fe_set_int(&c, 7); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&c, &x3); - if (!secp256k1_fe_sqrt_var(&r->y, &c)) { + return secp256k1_fe_sqrt(&r->y, &c); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + if (!secp256k1_ge_set_xquad(r, x)) { return 0; } secp256k1_fe_normalize_var(&r->y); @@ -192,6 +233,7 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o secp256k1_fe_negate(&r->y, &r->y, 1); } return 1; + } static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { @@ -236,7 +278,7 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); secp256k1_fe_sqr(&z2, &a->z); secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); - secp256k1_fe_mul_int(&z6, 7); + secp256k1_fe_mul_int(&z6, CURVE_B); secp256k1_fe_add(&x3, &z6); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); @@ -250,18 +292,30 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { /* y^2 = x^3 + 7 */ secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_set_int(&c, 7); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&x3, &c); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); } static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { - /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */ + /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate. + * + * Note that there is an implementation described at + * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + * which trades a multiply for a square, but in practice this is actually slower, + * mainly because it requires more normalizations. + */ secp256k1_fe t1,t2,t3,t4; /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). */ r->infinity = a->infinity; if (r->infinity) { @@ -629,4 +683,18 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { } #endif +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { + secp256k1_fe yz; + + if (a->infinity) { + return 0; + } + + /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as + * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z + is */ + secp256k1_fe_mul(&yz, &a->y, &a->z); + return secp256k1_fe_is_quad_var(&yz); +} + #endif diff --git a/crypto/secp256k1/libsecp256k1/src/hash.h b/crypto/secp256k1/libsecp256k1/src/hash.h index 0ff01e63fa..fca98cab9f 100644 --- a/crypto/secp256k1/libsecp256k1/src/hash.h +++ b/crypto/secp256k1/libsecp256k1/src/hash.h @@ -11,7 +11,7 @@ #include typedef struct { - uint32_t s[32]; + uint32_t s[8]; uint32_t buf[16]; /* In big endian */ size_t bytes; } secp256k1_sha256_t; diff --git a/crypto/secp256k1/libsecp256k1/src/hash_impl.h b/crypto/secp256k1/libsecp256k1/src/hash_impl.h index ae55df6d8a..b47e65f830 100644 --- a/crypto/secp256k1/libsecp256k1/src/hash_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/hash_impl.h @@ -269,15 +269,13 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 rng->retry = 0; } - +#undef BE32 #undef Round -#undef sigma0 #undef sigma1 -#undef Sigma0 +#undef sigma0 #undef Sigma1 -#undef Ch +#undef Sigma0 #undef Maj -#undef ReadBE32 -#undef WriteBE32 +#undef Ch #endif diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java index 90a498eaa2..1c67802fba 100644 --- a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java +++ b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -1,60 +1,446 @@ +/* + * Copyright 2013 Google Inc. + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.bitcoin; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.math.BigInteger; import com.google.common.base.Preconditions; - +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import static org.bitcoin.NativeSecp256k1Util.*; /** - * This class holds native methods to handle ECDSA verification. - * You can find an example library that can be used for this at - * https://github.com/sipa/secp256k1 + *

This class holds native methods to handle ECDSA verification.

+ * + *

You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1

+ * + *

To build secp256k1 for use with bitcoinj, run + * `./configure --enable-jni --enable-experimental --enable-module-ecdh` + * and `make` then copy `.libs/libsecp256k1.so` to your system library path + * or point the JVM to the folder containing it with -Djava.library.path + *

*/ public class NativeSecp256k1 { - public static final boolean enabled; - static { - boolean isEnabled = true; - try { - System.loadLibrary("javasecp256k1"); - } catch (UnsatisfiedLinkError e) { - isEnabled = false; - } - enabled = isEnabled; - } - + + private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private static final Lock r = rwl.readLock(); + private static final Lock w = rwl.writeLock(); private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); /** * Verifies the given secp256k1 signature in native code. * Calling when enabled == false is undefined (probably library not loaded) - * + * * @param data The data which was signed, must be exactly 32 bytes * @param signature The signature * @param pub The public key which did the signing */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub) { + public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); + if (byteBuff == null || byteBuff.capacity() < 520) { + byteBuff = ByteBuffer.allocateDirect(520); byteBuff.order(ByteOrder.nativeOrder()); nativeECDSABuffer.set(byteBuff); } byteBuff.rewind(); byteBuff.put(data); - byteBuff.putInt(signature.length); - byteBuff.putInt(pub.length); byteBuff.put(signature); byteBuff.put(pub); - return secp256k1_ecdsa_verify(byteBuff) == 1; + + byte[][] retByteArray; + + r.lock(); + try { + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; + } finally { + r.unlock(); + } } /** - * @param byteBuff signature format is byte[32] data, - * native-endian int signatureLength, native-endian int pubkeyLength, - * byte[signatureLength] signature, byte[pubkeyLength] pub - * @returns 1 for valid signature, anything else for invalid + * libsecp256k1 Create an ECDSA signature. + * + * @param data Message hash, 32 bytes + * @param key Secret key, 32 bytes + * + * Return values + * @param sig byte array of signature */ - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); + public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && sec.length <= 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + 32) { + byteBuff = ByteBuffer.allocateDirect(32 + 32); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(sec); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] sigArr = retByteArray[0]; + int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(sigArr.length, sigLen, "Got bad signature length."); + + return retVal == 0 ? new byte[0] : sigArr; + } + + /** + * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid + * + * @param seckey ECDSA Secret key, 32 bytes + */ + public static boolean secKeyVerify(byte[] seckey) { + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + r.lock(); + try { + return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; + } finally { + r.unlock(); + } + } + + + /** + * libsecp256k1 Compute Pubkey - computes public key from secret key + * + * @param seckey ECDSA Secret key, 32 bytes + * + * Return values + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + //TODO add a 'compressed' arg + public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + return retVal == 0 ? new byte[0]: pubArr; + } + + /** + * libsecp256k1 Cleanup - This destroys the secp256k1 context object + * This should be called at the end of the program for proper cleanup of the context. + */ + public static synchronized void cleanup() { + w.lock(); + try { + secp256k1_destroy_context(Secp256k1Context.getContext()); + } finally { + w.unlock(); + } + } + + public static long cloneContext() { + r.lock(); + try { + return secp256k1_ctx_clone(Secp256k1Context.getContext()); + } finally { r.unlock(); } + } + + /** + * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 create ECDH secret - constant time ECDH calculation + * + * @param seckey byte array of secret key used in exponentiaion + * @param pubkey byte array of public key used in exponentiaion + */ + public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { + byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + byteBuff.put(pubkey); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] resArr = retByteArray[0]; + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + + assertEquals(resArr.length, 32, "Got bad result length."); + assertEquals(retVal, 1, "Failed return value check."); + + return resArr; + } + + /** + * libsecp256k1 randomize - updates the context randomization + * + * @param seed 32-byte random seed + */ + public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ + Preconditions.checkArgument(seed.length == 32 || seed == null); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seed.length) { + byteBuff = ByteBuffer.allocateDirect(seed.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seed); + + w.lock(); + try { + return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; + } finally { + w.unlock(); + } + } + + private static native long secp256k1_ctx_clone(long context); + + private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); + + private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); + + private static native void secp256k1_destroy_context(long context); + + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); + + private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); + + private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + + private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); + } diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java new file mode 100644 index 0000000000..c00d08899b --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -0,0 +1,226 @@ +package org.bitcoin; + +import com.google.common.io.BaseEncoding; +import java.util.Arrays; +import java.math.BigInteger; +import javax.xml.bind.DatatypeConverter; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + * This class holds test cases defined for testing this library. + */ +public class NativeSecp256k1Test { + + //TODO improve comments/add more tests + /** + * This tests verify() for a valid signature + */ + public static void testVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + assertEquals( result, true , "testVerifyPos"); + } + + /** + * This tests verify() for a non-valid signature + */ + public static void testVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testVerifyNeg"); + } + + /** + * This tests secret key verify() for a valid secretkey + */ + public static void testSecKeyVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, true , "testSecKeyVerifyPos"); + } + + /** + * This tests secret key verify() for a invalid secretkey + */ + public static void testSecKeyVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testSecKeyVerifyNeg"); + } + + /** + * This tests public key create() for a valid secretkey + */ + public static void testPubKeyCreatePos() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); + } + + /** + * This tests public key create() for a invalid secretkey + */ + public static void testPubKeyCreateNeg() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); + } + + /** + * This tests sign() for a valid secretkey + */ + public static void testSignPos() throws AssertFailException{ + + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); + } + + /** + * This tests sign() for a invalid secretkey + */ + public static void testSignNeg() throws AssertFailException{ + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "" , "testSignNeg"); + } + + /** + * This tests private key tweak-add + */ + public static void testPrivKeyTweakAdd_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); + } + + /** + * This tests private key tweak-mul + */ + public static void testPrivKeyTweakMul_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); + } + + /** + * This tests private key tweak-add uncompressed + */ + public static void testPrivKeyTweakAdd_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); + } + + /** + * This tests private key tweak-mul uncompressed + */ + public static void testPrivKeyTweakMul_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); + } + + /** + * This tests seed randomization + */ + public static void testRandomize() throws AssertFailException { + byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" + boolean result = NativeSecp256k1.randomize(seed); + assertEquals( result, true, "testRandomize"); + } + + public static void testCreateECDHSecret() throws AssertFailException{ + + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); + String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); + } + + public static void main(String[] args) throws AssertFailException{ + + + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); + + assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); + + //Test verify() success/fail + testVerifyPos(); + testVerifyNeg(); + + //Test secKeyVerify() success/fail + testSecKeyVerifyPos(); + testSecKeyVerifyNeg(); + + //Test computePubkey() success/fail + testPubKeyCreatePos(); + testPubKeyCreateNeg(); + + //Test sign() success/fail + testSignPos(); + testSignNeg(); + + //Test privKeyTweakAdd() 1 + testPrivKeyTweakAdd_1(); + + //Test privKeyTweakMul() 2 + testPrivKeyTweakMul_1(); + + //Test privKeyTweakAdd() 3 + testPrivKeyTweakAdd_2(); + + //Test privKeyTweakMul() 4 + testPrivKeyTweakMul_2(); + + //Test randomize() + testRandomize(); + + //Test ECDH + testCreateECDHSecret(); + + NativeSecp256k1.cleanup(); + + System.out.println(" All tests passed." ); + + } +} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java new file mode 100644 index 0000000000..04732ba044 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +public class NativeSecp256k1Util{ + + public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + } + + public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ + if( !val.equals(val2) ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static class AssertFailException extends Exception { + public AssertFailException(String message) { + super( message ); + } + } +} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/Secp256k1Context.java b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/Secp256k1Context.java new file mode 100644 index 0000000000..216c986a8b --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/Secp256k1Context.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +/** + * This class holds the context reference used in native methods + * to handle ECDSA operations. + */ +public class Secp256k1Context { + private static final boolean enabled; //true if the library is loaded + private static final long context; //ref to pointer to context obj + + static { //static initializer + boolean isEnabled = true; + long contextRef = -1; + try { + System.loadLibrary("secp256k1"); + contextRef = secp256k1_init_context(); + } catch (UnsatisfiedLinkError e) { + System.out.println("UnsatisfiedLinkError: " + e.toString()); + isEnabled = false; + } + enabled = isEnabled; + context = contextRef; + } + + public static boolean isEnabled() { + return enabled; + } + + public static long getContext() { + if(!enabled) return -1; //sanity check + return context; + } + + private static native long secp256k1_init_context(); +} diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c index bb4cd70728..bcef7b32ce 100644 --- a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,23 +1,377 @@ +#include +#include +#include #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "include/secp256k1_recovery.h" -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) { - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int sigLen = *((int*)(data + 32)); - int pubLen = *((int*)(data + 32 + 4)); + const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); + + (void)classObject;(void)env; + + return ctx_clone_l; - return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); } -static void __javasecp256k1_attach(void) __attribute__((constructor)); -static void __javasecp256k1_detach(void) __attribute__((destructor)); +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_context_randomize(ctx, seed); -static void __javasecp256k1_attach(void) { - secp256k1_start(SECP256K1_START_VERIFY); } -static void __javasecp256k1_detach(void) { - secp256k1_stop(); +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + secp256k1_context_destroy(ctx); + + (void)classObject;(void)env; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* sigdata = { (unsigned char*) (data + 32) }; + const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; + + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pubkey; + + int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); + + if( ret ) { + ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if( ret ) { + ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); + } + } + + (void)classObject; + + return ret; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[2]; + + secp256k1_ecdsa_signature sig[72]; + + int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); + + unsigned char outputSer[72]; + size_t outputLen = 72; + + if( ret ) { + int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + sigArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_ec_seckey_verify(ctx, secKey); +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + secp256k1_pubkey pubkey; + + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); + + unsigned char outputSer[65]; + size_t outputLen = 65; + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubkeyArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; + +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; +/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if( ret ) { + ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if ( ret ) { + ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) +{ + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; + + return 0; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* pubdata = (const unsigned char*) (secdata + 32); + + jobjectArray retArray; + jbyteArray outArray, intsByteArray; + unsigned char intsarray[1]; + secp256k1_pubkey pubkey; + unsigned char nonce_res[32]; + size_t outputLen = 32; + + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if (ret) { + ret = secp256k1_ecdh( + ctx, + nonce_res, + &pubkey, + secdata + ); + } + + intsarray[0] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + outArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); + (*env)->SetObjectArrayElement(env, retArray, 0, outArray); + + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; } diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h index d7fb004fa8..fe613c9e9e 100644 --- a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h +++ b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -1,5 +1,6 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include +#include "include/secp256k1.h" /* Header for class org_bitcoin_NativeSecp256k1 */ #ifndef _Included_org_bitcoin_NativeSecp256k1 @@ -9,11 +10,108 @@ extern "C" { #endif /* * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;)I + * Method: secp256k1_ctx_clone + * Signature: (J)J */ -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject); +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_context_randomize + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_destroy_context + * Signature: (J)V + */ +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_verify + * Signature: (Ljava/nio/ByteBuffer;JII)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv *, jclass, jobject, jlong, jint, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_seckey_verify + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_create + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_parse + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdh + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen); + #ifdef __cplusplus } diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.c b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.c new file mode 100644 index 0000000000..a52939e7e7 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.c @@ -0,0 +1,15 @@ +#include +#include +#include "org_bitcoin_Secp256k1Context.h" +#include "include/secp256k1.h" + +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (uintptr_t)ctx; +} + diff --git a/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.h b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.h new file mode 100644 index 0000000000..0d2bc84b7f --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/java/org_bitcoin_Secp256k1Context.h @@ -0,0 +1,22 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_Secp256k1Context */ + +#ifndef _Included_org_bitcoin_Secp256k1Context +#define _Included_org_bitcoin_Secp256k1Context +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_Secp256k1Context + * Method: secp256k1_init_context + * Signature: ()J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include index 8ef3aff92f..e3088b4697 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/Makefile.am.include @@ -4,6 +4,5 @@ noinst_HEADERS += src/modules/ecdh/tests_impl.h if USE_BENCHMARK noinst_PROGRAMS += bench_ecdh bench_ecdh_SOURCES = src/bench_ecdh.c -bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_ecdh_LDFLAGS = -static +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h index c23e4f82f7..9e30fb73dd 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/main_impl.h @@ -16,10 +16,10 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se secp256k1_gej res; secp256k1_ge pt; secp256k1_scalar s; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(result != NULL); ARG_CHECK(point != NULL); ARG_CHECK(scalar != NULL); - (void)ctx; secp256k1_pubkey_load(ctx, &pt, point); secp256k1_scalar_set_b32(&s, scalar, &overflow); diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h index 7badc9033f..85a5d0a9a6 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/tests_impl.h @@ -7,6 +7,35 @@ #ifndef _SECP256K1_MODULE_ECDH_TESTS_ #define _SECP256K1_MODULE_ECDH_TESTS_ +void test_ecdh_api(void) { + /* Setup context that just counts errors */ + secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_pubkey point; + unsigned char res[32]; + unsigned char s_one[32] = { 0 }; + int32_t ecount = 0; + s_one[31] = 1; + + secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1); + + /* Check all NULLs are detected */ + CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); + CHECK(ecount == 3); + + /* Cleanup */ + secp256k1_context_destroy(tctx); +} + void test_ecdh_generator_basepoint(void) { unsigned char s_one[32] = { 0 }; secp256k1_pubkey point[2]; @@ -68,6 +97,7 @@ void test_bad_scalar(void) { } void run_ecdh_tests(void) { + test_ecdh_api(); test_ecdh_generator_basepoint(); test_bad_scalar(); } diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include index 754469eeb2..bf23c26e71 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/Makefile.am.include @@ -4,6 +4,5 @@ noinst_HEADERS += src/modules/recovery/tests_impl.h if USE_BENCHMARK noinst_PROGRAMS += bench_recover bench_recover_SOURCES = src/bench_recover.c -bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_recover_LDFLAGS = -static +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h old mode 100644 new mode 100755 index 75b6958940..c6fbe23981 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/main_impl.h @@ -63,6 +63,7 @@ int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_cont (void)ctx; ARG_CHECK(output64 != NULL); ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); secp256k1_scalar_get_b32(&output64[0], &r); @@ -83,6 +84,42 @@ int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, return 1; } +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { + unsigned char brx[32]; + secp256k1_fe fx; + secp256k1_ge x; + secp256k1_gej xj; + secp256k1_scalar rn, u1, u2; + secp256k1_gej qj; + int r; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_get_b32(brx, sigr); + r = secp256k1_fe_set_b32(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); + } + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_gej_set_ge(&xj, &x); + secp256k1_scalar_inverse_var(&rn, sigr); + secp256k1_scalar_mul(&u1, &rn, message); + secp256k1_scalar_negate(&u1, &u1); + secp256k1_scalar_mul(&u2, &rn, sigs); + secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_ge_set_gej_var(pubkey, &qj); + return !secp256k1_gej_is_infinity(&qj); +} + int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { secp256k1_scalar r, s; secp256k1_scalar sec, non, msg; @@ -101,16 +138,15 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; unsigned int count = 0; secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, seckey, msg32, NULL, (void*)noncedata, count); + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); if (!secp256k1_scalar_is_zero(&non) && !overflow) { if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { break; @@ -118,6 +154,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd } count++; } + memset(nonce32, 0, 32); secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); @@ -142,7 +179,7 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk ARG_CHECK(pubkey != NULL); secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); - ARG_CHECK(recid >= 0 && recid < 4); + VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ secp256k1_scalar_set_b32(&m, msg32, NULL); if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { secp256k1_pubkey_save(pubkey, &q); diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h index 5a78fae921..765c7dd81e 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/tests_impl.h @@ -7,6 +7,146 @@ #ifndef _SECP256K1_MODULE_RECOVERY_TESTS_ #define _SECP256K1_MODULE_RECOVERY_TESTS_ +static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + + /* On the first run, return 0 to force a second run */ + if (counter == 0) { + memset(nonce32, 0, 32); + return 1; + } + /* On the second run, return an overflow to force a third run */ + if (counter == 1) { + memset(nonce32, 0xff, 32); + return 1; + } + /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ + memset(nonce32, 1, 32); + return secp256k1_rand_bits(1); +} + +void test_ecdsa_recovery_api(void) { + /* Setup contexts that just count errors */ + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + secp256k1_ecdsa_signature normal_sig; + secp256k1_ecdsa_recoverable_signature recsig; + unsigned char privkey[32] = { 1 }; + unsigned char message[32] = { 2 }; + int32_t ecount = 0; + int recid = 0; + unsigned char sig[74]; + unsigned char zero_privkey[32] = { 0 }; + unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Check bad contexts and NULLs for signing */ + ecount = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); + CHECK(ecount == 5); + /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ + secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); + CHECK(ecount == 5); + /* These will all fail, but not in ARG_CHECK way */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); + /* This one will succeed. */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 5); + + /* Check signing with a goofy nonce function */ + + /* Check bad contexts and NULLs for recovery */ + ecount = 0; + CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); + CHECK(ecount == 5); + + /* Check NULLs for conversion */ + CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); + + /* Check NULLs for de/serialization */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); + CHECK(ecount == 7); + /* overflow in signature will fail but not affect ecount */ + memcpy(sig, over_privkey, 32); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); + CHECK(ecount == 7); + + /* cleanup */ + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + void test_ecdsa_recovery_end_to_end(void) { unsigned char extra[32] = {0x00}; unsigned char privkey[32]; @@ -34,6 +174,7 @@ void test_ecdsa_recovery_end_to_end(void) { /* Serialize/parse compact and verify/recover. */ extra[0] = 0; CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); extra[31] = 1; @@ -43,6 +184,7 @@ void test_ecdsa_recovery_end_to_end(void) { CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(memcmp(&signature[4], &signature[0], 64) == 0); CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); memset(&rsignature[4], 0, sizeof(rsignature[4])); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); @@ -54,7 +196,7 @@ void test_ecdsa_recovery_end_to_end(void) { CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); /* Serialize/destroy/parse signature and verify again. */ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - sig[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); + sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); @@ -161,25 +303,24 @@ void test_ecdsa_recovery_edge_cases(void) { CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); } /* DER parsing tests. */ /* Zero length r/s. */ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); /* Leading zeros. */ - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); - CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); - sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); - sigbderalt4[7] = 1; CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); /* Damage signature. */ sigbder[7]++; CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); @@ -240,6 +381,9 @@ void test_ecdsa_recovery_edge_cases(void) { void run_recovery_tests(void) { int i; + for (i = 0; i < count; i++) { + test_ecdsa_recovery_api(); + } for (i = 0; i < 64*count; i++) { test_ecdsa_recovery_end_to_end(); } diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/Makefile.am.include b/crypto/secp256k1/libsecp256k1/src/modules/schnorr/Makefile.am.include deleted file mode 100644 index bad4cb7c5b..0000000000 --- a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/Makefile.am.include +++ /dev/null @@ -1,11 +0,0 @@ -include_HEADERS += include/secp256k1_schnorr.h -noinst_HEADERS += src/modules/schnorr/main_impl.h -noinst_HEADERS += src/modules/schnorr/schnorr.h -noinst_HEADERS += src/modules/schnorr/schnorr_impl.h -noinst_HEADERS += src/modules/schnorr/tests_impl.h -if USE_BENCHMARK -noinst_PROGRAMS += bench_schnorr_verify -bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c -bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_schnorr_verify_LDFLAGS = -static -endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/main_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorr/main_impl.h deleted file mode 100644 index c10fd259f2..0000000000 --- a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/main_impl.h +++ /dev/null @@ -1,164 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORR_MAIN -#define SECP256K1_MODULE_SCHNORR_MAIN - -#include "include/secp256k1_schnorr.h" -#include "modules/schnorr/schnorr_impl.h" - -static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { - secp256k1_sha256_t sha; - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, r32, 32); - secp256k1_sha256_write(&sha, msg32, 32); - secp256k1_sha256_finalize(&sha, h32); -} - -static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 "; - -int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar sec, non; - int ret = 0; - int overflow = 0; - unsigned int count = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - secp256k1_scalar_set_b32(&sec, seckey, NULL); - while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) { - break; - } - } - count++; - } - if (!ret) { - memset(sig64, 0, 64); - } - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - return ret; -} - -int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { - secp256k1_ge q; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(pubkey != NULL); - - secp256k1_pubkey_load(ctx, &q, pubkey); - return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32); -} - -int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) { - secp256k1_ge q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(pubkey != NULL); - - if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) { - secp256k1_pubkey_save(pubkey, &q); - return 1; - } else { - memset(pubkey, 0, sizeof(*pubkey)); - return 0; - } -} - -int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) { - int count = 0; - int ret = 1; - secp256k1_gej Qj; - secp256k1_ge Q; - secp256k1_scalar sec; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sec32 != NULL); - ARG_CHECK(pubnonce != NULL); - ARG_CHECK(privnonce32 != NULL); - - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - do { - int overflow; - ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&sec, privnonce32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&sec)) { - continue; - } - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec); - secp256k1_ge_set_gej(&Q, &Qj); - - secp256k1_pubkey_save(pubnonce, &Q); - break; - } while(1); - - secp256k1_scalar_clear(&sec); - if (!ret) { - memset(pubnonce, 0, sizeof(*pubnonce)); - } - return ret; -} - -int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) { - int overflow = 0; - secp256k1_scalar sec, non; - secp256k1_ge pubnon; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(sec32 != NULL); - ARG_CHECK(secnonce32 != NULL); - ARG_CHECK(pubnonce_others != NULL); - - secp256k1_scalar_set_b32(&sec, sec32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&sec)) { - return -1; - } - secp256k1_scalar_set_b32(&non, secnonce32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&non)) { - return -1; - } - secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others); - return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32); -} - -int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, int n) { - ARG_CHECK(sig64 != NULL); - ARG_CHECK(n >= 1); - ARG_CHECK(sig64sin != NULL); - return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); -} - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/schnorr.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorr/schnorr.h deleted file mode 100644 index d227433d48..0000000000 --- a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/schnorr.h +++ /dev/null @@ -1,20 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php. * - ***********************************************************************/ - -#ifndef _SECP256K1_MODULE_SCHNORR_H_ -#define _SECP256K1_MODULE_SCHNORR_H_ - -#include "scalar.h" -#include "group.h" - -typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); - -static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32); -static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); -static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); -static int secp256k1_schnorr_sig_combine(unsigned char *sig64, int n, const unsigned char * const *sig64ins); - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/schnorr_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorr/schnorr_impl.h deleted file mode 100644 index ed70390bba..0000000000 --- a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/schnorr_impl.h +++ /dev/null @@ -1,207 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php. * - ***********************************************************************/ - -#ifndef _SECP256K1_SCHNORR_IMPL_H_ -#define _SECP256K1_SCHNORR_IMPL_H_ - -#include - -#include "schnorr.h" -#include "num.h" -#include "field.h" -#include "group.h" -#include "ecmult.h" -#include "ecmult_gen.h" - -/** - * Custom Schnorr-based signature scheme. They support multiparty signing, public key - * recovery and batch validation. - * - * Rationale for verifying R's y coordinate: - * In order to support batch validation and public key recovery, the full R point must - * be known to verifiers, rather than just its x coordinate. In order to not risk - * being more strict in batch validation than normal validation, validators must be - * required to reject signatures with incorrect y coordinate. This is only possible - * by including a (relatively slow) field inverse, or a field square root. However, - * batch validation offers potentially much higher benefits than this cost. - * - * Rationale for having an implicit y coordinate oddness: - * If we commit to having the full R point known to verifiers, there are two mechanism. - * Either include its oddness in the signature, or give it an implicit fixed value. - * As the R y coordinate can be flipped by a simple negation of the nonce, we choose the - * latter, as it comes with nearly zero impact on signing or validation performance, and - * saves a byte in the signature. - * - * Signing: - * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0) - * - * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce). - * Compute 32-byte r, the serialization of R's x coordinate. - * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order. - * Compute scalar s = k - h * x. - * The signature is (r, s). - * - * - * Verification: - * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s) - * - * Signature is invalid if s >= order. - * Signature is invalid if r >= p. - * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order. - * Option 1 (faster for single verification): - * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd. - * Signature is valid if the serialization of R's x coordinate equals r. - * Option 2 (allows batch validation and pubkey recovery): - * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve. - * Signature is valid if R + h * Q + s * G == 0. - */ - -static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { - secp256k1_gej Rj; - secp256k1_ge Ra; - unsigned char h32[32]; - secp256k1_scalar h, s; - int overflow; - secp256k1_scalar n; - - if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { - return 0; - } - n = *nonce; - - secp256k1_ecmult_gen(ctx, &Rj, &n); - if (pubnonce != NULL) { - secp256k1_gej_add_ge(&Rj, &Rj, pubnonce); - } - secp256k1_ge_set_gej(&Ra, &Rj); - secp256k1_fe_normalize(&Ra.y); - if (secp256k1_fe_is_odd(&Ra.y)) { - /* R's y coordinate is odd, which is not allowed (see rationale above). - Force it to be even by negating the nonce. Note that this even works - for multiparty signing, as the R point is known to all participants, - which can all decide to flip the sign in unison, resulting in the - overall R point to be negated too. */ - secp256k1_scalar_negate(&n, &n); - } - secp256k1_fe_normalize(&Ra.x); - secp256k1_fe_get_b32(sig64, &Ra.x); - hash(h32, sig64, msg32); - overflow = 0; - secp256k1_scalar_set_b32(&h, h32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&h)) { - secp256k1_scalar_clear(&n); - return 0; - } - secp256k1_scalar_mul(&s, &h, key); - secp256k1_scalar_negate(&s, &s); - secp256k1_scalar_add(&s, &s, &n); - secp256k1_scalar_clear(&n); - secp256k1_scalar_get_b32(sig64 + 32, &s); - return 1; -} - -static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { - secp256k1_gej Qj, Rj; - secp256k1_ge Ra; - secp256k1_fe Rx; - secp256k1_scalar h, s; - unsigned char hh[32]; - int overflow; - - if (secp256k1_ge_is_infinity(pubkey)) { - return 0; - } - hash(hh, sig64, msg32); - overflow = 0; - secp256k1_scalar_set_b32(&h, hh, &overflow); - if (overflow || secp256k1_scalar_is_zero(&h)) { - return 0; - } - overflow = 0; - secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); - if (overflow) { - return 0; - } - if (!secp256k1_fe_set_b32(&Rx, sig64)) { - return 0; - } - secp256k1_gej_set_ge(&Qj, pubkey); - secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); - if (secp256k1_gej_is_infinity(&Rj)) { - return 0; - } - secp256k1_ge_set_gej_var(&Ra, &Rj); - secp256k1_fe_normalize_var(&Ra.y); - if (secp256k1_fe_is_odd(&Ra.y)) { - return 0; - } - return secp256k1_fe_equal_var(&Rx, &Ra.x); -} - -static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { - secp256k1_gej Qj, Rj; - secp256k1_ge Ra; - secp256k1_fe Rx; - secp256k1_scalar h, s; - unsigned char hh[32]; - int overflow; - - hash(hh, sig64, msg32); - overflow = 0; - secp256k1_scalar_set_b32(&h, hh, &overflow); - if (overflow || secp256k1_scalar_is_zero(&h)) { - return 0; - } - overflow = 0; - secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); - if (overflow) { - return 0; - } - if (!secp256k1_fe_set_b32(&Rx, sig64)) { - return 0; - } - if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) { - return 0; - } - secp256k1_gej_set_ge(&Rj, &Ra); - secp256k1_scalar_inverse_var(&h, &h); - secp256k1_scalar_negate(&s, &s); - secp256k1_scalar_mul(&s, &s, &h); - secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s); - if (secp256k1_gej_is_infinity(&Qj)) { - return 0; - } - secp256k1_ge_set_gej(pubkey, &Qj); - return 1; -} - -static int secp256k1_schnorr_sig_combine(unsigned char *sig64, int n, const unsigned char * const *sig64ins) { - secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - int i; - for (i = 0; i < n; i++) { - secp256k1_scalar si; - int overflow; - secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow); - if (overflow) { - return -1; - } - if (i) { - if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) { - return -1; - } - } - secp256k1_scalar_add(&s, &s, &si); - } - if (secp256k1_scalar_is_zero(&s)) { - return 0; - } - memcpy(sig64, sig64ins[0], 32); - secp256k1_scalar_get_b32(sig64 + 32, &s); - secp256k1_scalar_clear(&s); - return 1; -} - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/tests_impl.h b/crypto/secp256k1/libsecp256k1/src/modules/schnorr/tests_impl.h deleted file mode 100644 index 79737f7487..0000000000 --- a/crypto/secp256k1/libsecp256k1/src/modules/schnorr/tests_impl.h +++ /dev/null @@ -1,175 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php.* - **********************************************************************/ - -#ifndef SECP256K1_MODULE_SCHNORR_TESTS -#define SECP256K1_MODULE_SCHNORR_TESTS - -#include "include/secp256k1_schnorr.h" - -void test_schnorr_end_to_end(void) { - unsigned char privkey[32]; - unsigned char message[32]; - unsigned char schnorr_signature[64]; - secp256k1_pubkey pubkey, recpubkey; - - /* Generate a random key and message. */ - { - secp256k1_scalar key; - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - secp256k1_rand256_test(message); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Schnorr sign. */ - CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); - CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1); - CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); - /* Destroy signature and verify again. */ - schnorr_signature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0); - CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 || - memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); -} - -/** Horribly broken hash function. Do not use for anything but tests. */ -void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { - int i; - for (i = 0; i < 32; i++) { - h32[i] = r32[i] ^ msg32[i]; - } -} - -void test_schnorr_sign_verify(void) { - unsigned char msg32[32]; - unsigned char sig64[3][64]; - secp256k1_gej pubkeyj[3]; - secp256k1_ge pubkey[3]; - secp256k1_scalar nonce[3], key[3]; - int i = 0; - int k; - - secp256k1_rand256_test(msg32); - - for (k = 0; k < 3; k++) { - random_scalar_order_test(&key[k]); - - do { - random_scalar_order_test(&nonce[k]); - if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) { - break; - } - } while(1); - - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]); - secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]); - CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32)); - - for (i = 0; i < 4; i++) { - int pos = secp256k1_rand32() % 64; - int mod = 1 + (secp256k1_rand32() % 255); - sig64[k][pos] ^= mod; - CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0); - sig64[k][pos] ^= mod; - } - } -} - -void test_schnorr_threshold(void) { - unsigned char msg[32]; - unsigned char sec[5][32]; - secp256k1_pubkey pub[5]; - unsigned char nonce[5][32]; - secp256k1_pubkey pubnonce[5]; - unsigned char sig[5][64]; - const unsigned char* sigs[5]; - unsigned char allsig[64]; - const secp256k1_pubkey* pubs[5]; - secp256k1_pubkey allpub; - int n, i; - int damage; - int ret = 0; - - damage = (secp256k1_rand32() % 2) ? (1 + (secp256k1_rand32() % 4)) : 0; - secp256k1_rand256_test(msg); - n = 2 + (secp256k1_rand32() % 4); - for (i = 0; i < n; i++) { - do { - secp256k1_rand256_test(sec[i]); - } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); - CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); - pubs[i] = &pub[i]; - } - if (damage == 1) { - nonce[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); - } else if (damage == 2) { - sec[secp256k1_rand32() % n][secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); - } - for (i = 0; i < n; i++) { - secp256k1_pubkey allpubnonce; - const secp256k1_pubkey *pubnonces[4]; - int j; - for (j = 0; j < i; j++) { - pubnonces[j] = &pubnonce[j]; - } - for (j = i + 1; j < n; j++) { - pubnonces[j - 1] = &pubnonce[j]; - } - CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); - ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; - sigs[i] = sig[i]; - } - if (damage == 3) { - sig[secp256k1_rand32() % n][secp256k1_rand32() % 64] ^= 1 + (secp256k1_rand32() % 255); - } - ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; - if ((ret & 1) == 0) { - ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; - } - if (damage == 4) { - allsig[secp256k1_rand32() % 32] ^= 1 + (secp256k1_rand32() % 255); - } - if ((ret & 7) == 0) { - ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; - } - CHECK((ret == 0) == (damage == 0)); -} - -void test_schnorr_recovery(void) { - unsigned char msg32[32]; - unsigned char sig64[64]; - secp256k1_ge Q; - - secp256k1_rand256_test(msg32); - secp256k1_rand256_test(sig64); - secp256k1_rand256_test(sig64 + 32); - if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) { - CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1); - } -} - -void run_schnorr_tests(void) { - int i; - for (i = 0; i < 32*count; i++) { - test_schnorr_end_to_end(); - } - for (i = 0; i < 32 * count; i++) { - test_schnorr_sign_verify(); - } - for (i = 0; i < 16 * count; i++) { - test_schnorr_recovery(); - } - for (i = 0; i < 10 * count; i++) { - test_schnorr_threshold(); - } -} - -#endif diff --git a/crypto/secp256k1/libsecp256k1/src/num.h b/crypto/secp256k1/libsecp256k1/src/num.h index ebfa71eb44..7bb9c5be8c 100644 --- a/crypto/secp256k1/libsecp256k1/src/num.h +++ b/crypto/secp256k1/libsecp256k1/src/num.h @@ -32,6 +32,9 @@ static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsi /** Compute a modular inverse. The input must be less than the modulus. */ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m); +/** Compute the jacobi symbol (a|b). b must be positive and odd. */ +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b); + /** Compare the absolute value of two numbers. */ static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b); @@ -57,6 +60,9 @@ static void secp256k1_num_shift(secp256k1_num *r, int bits); /** Check whether a number is zero. */ static int secp256k1_num_is_zero(const secp256k1_num *a); +/** Check whether a number is one. */ +static int secp256k1_num_is_one(const secp256k1_num *a); + /** Check whether a number is strictly negative. */ static int secp256k1_num_is_neg(const secp256k1_num *a); diff --git a/crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h b/crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h index f43e7a56cc..3a46495eea 100644 --- a/crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/num_gmp_impl.h @@ -70,6 +70,7 @@ static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, cons static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); + (void)c; VERIFY_CHECK(c == 0); r->limbs = a->limbs; while (r->limbs > 1 && r->data[r->limbs-1]==0) { @@ -125,6 +126,7 @@ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, } sn = NUM_LIMBS+1; gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + (void)gn; VERIFY_CHECK(gn == 1); VERIFY_CHECK(g[0] == 1); r->neg = a->neg ^ m->neg; @@ -142,6 +144,32 @@ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, memset(v, 0, sizeof(v)); } +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) { + int ret; + mpz_t ga, gb; + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1)); + + mpz_inits(ga, gb, NULL); + + mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data); + mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data); + if (a->neg) { + mpz_neg(ga, ga); + } + + ret = mpz_jacobi(ga, gb); + + mpz_clears(ga, gb, NULL); + + return ret; +} + +static int secp256k1_num_is_one(const secp256k1_num *a) { + return (a->limbs == 1 && a->data[0] == 1); +} + static int secp256k1_num_is_zero(const secp256k1_num *a) { return (a->limbs == 1 && a->data[0] == 0); } diff --git a/crypto/secp256k1/libsecp256k1/src/scalar.h b/crypto/secp256k1/libsecp256k1/src/scalar.h index b590ccd6dd..27e9d8375e 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar.h @@ -13,7 +13,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32.h" diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h b/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h index cbec34d716..56e7bd82af 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_4x64_impl.h @@ -282,8 +282,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq 56(%%rsi), %%r14\n" /* Initialize r8,r9,r10 */ "movq 0(%%rsi), %%r8\n" - "movq $0, %%r9\n" - "movq $0, %%r10\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" /* (r8,r9) += n0 * c0 */ "movq %8, %%rax\n" "mulq %%r11\n" @@ -291,7 +291,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq %%rdx, %%r9\n" /* extract m0 */ "movq %%r8, %q0\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10) += l1 */ "addq 8(%%rsi), %%r9\n" "adcq $0, %%r10\n" @@ -309,7 +309,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r8\n" /* extract m1 */ "movq %%r9, %q1\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r10,r8,r9) += l2 */ "addq 16(%%rsi), %%r10\n" "adcq $0, %%r8\n" @@ -332,7 +332,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r9\n" /* extract m2 */ "movq %%r10, %q2\n" - "movq $0, %%r10\n" + "xorq %%r10, %%r10\n" /* (r8,r9,r10) += l3 */ "addq 24(%%rsi), %%r8\n" "adcq $0, %%r9\n" @@ -355,7 +355,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r10\n" /* extract m3 */ "movq %%r8, %q3\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10,r8) += n3 * c1 */ "movq %9, %%rax\n" "mulq %%r14\n" @@ -387,8 +387,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq %q11, %%r13\n" /* Initialize (r8,r9,r10) */ "movq %q5, %%r8\n" - "movq $0, %%r9\n" - "movq $0, %%r10\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" /* (r8,r9) += m4 * c0 */ "movq %12, %%rax\n" "mulq %%r11\n" @@ -396,7 +396,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq %%rdx, %%r9\n" /* extract p0 */ "movq %%r8, %q0\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10) += m1 */ "addq %q6, %%r9\n" "adcq $0, %%r10\n" @@ -414,7 +414,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r8\n" /* extract p1 */ "movq %%r9, %q1\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r10,r8,r9) += m2 */ "addq %q7, %%r10\n" "adcq $0, %%r8\n" @@ -472,7 +472,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq %%rax, 0(%q6)\n" /* Move to (r8,r9) */ "movq %%rdx, %%r8\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r8,r9) += p1 */ "addq %q2, %%r8\n" "adcq $0, %%r9\n" @@ -483,7 +483,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq %%rdx, %%r9\n" /* Extract r1 */ "movq %%r8, 8(%q6)\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r8) += p4 */ "addq %%r10, %%r9\n" "adcq $0, %%r8\n" @@ -492,7 +492,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r8\n" /* Extract r2 */ "movq %%r9, 16(%q6)\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r8,r9) += p3 */ "addq %q4, %%r8\n" "adcq $0, %%r9\n" @@ -912,6 +912,7 @@ static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) secp256k1_scalar_reduce_512(r, l); } +#ifdef USE_ENDOMORPHISM static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { r1->d[0] = a->d[0]; r1->d[1] = a->d[1]; @@ -922,6 +923,7 @@ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r r2->d[2] = 0; r2->d[3] = 0; } +#endif SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_impl.h b/crypto/secp256k1/libsecp256k1/src/scalar_impl.h index 88ea97de86..f5b2376407 100644 --- a/crypto/secp256k1/libsecp256k1/src/scalar_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/scalar_impl.h @@ -7,8 +7,6 @@ #ifndef _SECP256K1_SCALAR_IMPL_H_ #define _SECP256K1_SCALAR_IMPL_H_ -#include - #include "group.h" #include "scalar.h" @@ -16,7 +14,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low_impl.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64_impl.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32_impl.h" @@ -33,17 +33,37 @@ static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a /** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ static void secp256k1_scalar_order_get_num(secp256k1_num *r) { +#if defined(EXHAUSTIVE_TEST_ORDER) + static const unsigned char order[32] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER + }; +#else static const unsigned char order[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 }; +#endif secp256k1_num_set_bin(r, order, 32); } #endif static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { +#if defined(EXHAUSTIVE_TEST_ORDER) + int i; + *r = 0; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) + *r = i; + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(*r != 0); +} +#else secp256k1_scalar *t; int i; /* First compute x ^ (2^N - 1) for some values of N. */ @@ -235,9 +255,9 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar } SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - /* d[0] is present and is the lowest word for all representations */ return !(a->d[0] & 1); } +#endif static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { #if defined(USE_SCALAR_INV_BUILTIN) @@ -261,6 +281,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc } #ifdef USE_ENDOMORPHISM +#if defined(EXHAUSTIVE_TEST_ORDER) +/** + * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the + * full case we don't bother making k1 and k2 be small, we just want them to be + * nontrivial to get full test coverage for the exhaustive tests. We therefore + * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. + */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER; + *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; +} +#else /** * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, @@ -333,5 +365,6 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar secp256k1_scalar_add(r1, r1, a); } #endif +#endif #endif diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_low.h b/crypto/secp256k1/libsecp256k1/src/scalar_low.h new file mode 100644 index 0000000000..5574c44c7a --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/scalar_low.h @@ -0,0 +1,15 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef uint32_t secp256k1_scalar; + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/scalar_low_impl.h b/crypto/secp256k1/libsecp256k1/src/scalar_low_impl.h new file mode 100644 index 0000000000..4f94441f49 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/scalar_low_impl.h @@ -0,0 +1,114 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +#include "scalar.h" + +#include + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + return !(*a & 1); +} + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; } +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; } + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + if (offset < 32) + return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); + else + return 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + return secp256k1_scalar_get_bits(a, offset, count); +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + return *r < *b; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + if (flag && bit < 32) + *r += (1 << bit); +#ifdef VERIFY + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; + int i; + *r = 0; + for (i = 0; i < 32; i++) { + *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; + } + /* just deny overflow, it basically always happens */ + if (overflow) *overflow = 0; +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + memset(bin, 0, 32); + bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + return *a == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + if (*a == 0) { + *r = 0; + } else { + *r = EXHAUSTIVE_TEST_ORDER - *a; + } +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + return *a == 1; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + return *a > EXHAUSTIVE_TEST_ORDER / 2; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + if (flag) secp256k1_scalar_negate(r, r); + return flag ? -1 : 1; +} + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; +} + +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = *r & ((1 << n) - 1); + *r >>= n; + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; +} + +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + *r1 = *a; + *r2 = 0; +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + return *a == *b; +} + +#endif diff --git a/crypto/secp256k1/libsecp256k1/src/secp256k1.c b/crypto/secp256k1/libsecp256k1/src/secp256k1.c old mode 100644 new mode 100755 index 203f880af4..fb8b882faa --- a/crypto/secp256k1/libsecp256k1/src/secp256k1.c +++ b/crypto/secp256k1/libsecp256k1/src/secp256k1.c @@ -4,8 +4,6 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#define SECP256K1_BUILD (1) - #include "include/secp256k1.h" #include "util.h" @@ -62,13 +60,20 @@ secp256k1_context* secp256k1_context_create(unsigned int flags) { ret->illegal_callback = default_illegal_callback; ret->error_callback = default_error_callback; + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_callback_call(&ret->illegal_callback, + "Invalid flags"); + free(ret); + return NULL; + } + secp256k1_ecmult_context_init(&ret->ecmult_ctx); secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); - if (flags & SECP256K1_CONTEXT_SIGN) { + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); } - if (flags & SECP256K1_CONTEXT_VERIFY) { + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); } @@ -145,9 +150,11 @@ static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { secp256k1_ge Q; - (void)ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { - memset(pubkey, 0, sizeof(*pubkey)); return 0; } secp256k1_pubkey_save(pubkey, &Q); @@ -157,10 +164,25 @@ int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pu int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { secp256k1_ge Q; + size_t len; + int ret = 0; - (void)ctx; - return (secp256k1_pubkey_load(ctx, &Q, pubkey) && - secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, flags)); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; } static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { @@ -190,7 +212,7 @@ static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { secp256k1_scalar r, s; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(input != NULL); @@ -203,10 +225,31 @@ int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ } } +int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { secp256k1_scalar r, s; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(output != NULL); ARG_CHECK(outputlen != NULL); ARG_CHECK(sig != NULL); @@ -215,6 +258,38 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsign return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); } +int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { + secp256k1_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_scalar_negate(&s, &s); + } + secp256k1_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { secp256k1_ge q; secp256k1_scalar r, s; @@ -227,7 +302,8 @@ int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_s secp256k1_scalar_set_b32(&m, msg32, NULL); secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); - return (secp256k1_pubkey_load(ctx, &q, pubkey) && + return (!secp256k1_scalar_is_high(&s) && + secp256k1_pubkey_load(ctx, &q, pubkey) && secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); } @@ -239,8 +315,10 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m /* We feed a byte array to the PRNG as input, consisting of: * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. - * - optionally 16 extra bytes with the algorithm name (the extra data bytes - * are set to zeroes when not present, while the algorithm name is). + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. */ memcpy(keydata, key32, 32); memcpy(keydata + 32, msg32, 32); @@ -249,9 +327,8 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m keylen = 96; } if (algo16 != NULL) { - memset(keydata + keylen, 0, 96 - keylen); - memcpy(keydata + 96, algo16, 16); - keylen = 112; + memcpy(keydata + keylen, algo16, 16); + keylen += 16; } secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); memset(keydata, 0, sizeof(keydata)); @@ -282,16 +359,15 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; unsigned int count = 0; secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { - unsigned char nonce32[32]; ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); if (!overflow && !secp256k1_scalar_is_zero(&non)) { if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { break; @@ -299,6 +375,7 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature } count++; } + memset(nonce32, 0, 32); secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); @@ -317,7 +394,6 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char int overflow; VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); - (void)ctx; secp256k1_scalar_set_b32(&sec, seckey, &overflow); ret = !overflow && !secp256k1_scalar_is_zero(&sec); @@ -332,19 +408,19 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p int overflow; int ret = 0; VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(seckey != NULL); secp256k1_scalar_set_b32(&sec, seckey, &overflow); ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); - secp256k1_ge_set_gej(&p, &pj); - secp256k1_pubkey_save(pubkey, &p); - secp256k1_scalar_clear(&sec); - if (!ret) { - memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); + secp256k1_ge_set_gej(&p, &pj); + secp256k1_pubkey_save(pubkey, &p); } + secp256k1_scalar_clear(&sec); return ret; } @@ -356,12 +432,12 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char * VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); ARG_CHECK(tweak != NULL); - (void)ctx; secp256k1_scalar_set_b32(&term, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -382,12 +458,13 @@ int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&term, tweak, &overflow); - if (!overflow && secp256k1_pubkey_load(ctx, &p, pubkey)) { - ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); - if (ret) { + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { secp256k1_pubkey_save(pubkey, &p); } else { - memset(pubkey, 0, sizeof(*pubkey)); + ret = 0; } } @@ -402,11 +479,11 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char * VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); ARG_CHECK(tweak != NULL); - (void)ctx; secp256k1_scalar_set_b32(&factor, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -427,48 +504,19 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&factor, tweak, &overflow); - if (!overflow && secp256k1_pubkey_load(ctx, &p, pubkey)) { - ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); - if (ret) { + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { secp256k1_pubkey_save(pubkey, &p); } else { - memset(pubkey, 0, sizeof(*pubkey)); + ret = 0; } } return ret; } -int secp256k1_ec_privkey_export(const secp256k1_context* ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *seckey, unsigned int flags) { - secp256k1_scalar key; - int ret = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(seckey != NULL); - ARG_CHECK(privkey != NULL); - ARG_CHECK(privkeylen != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - - secp256k1_scalar_set_b32(&key, seckey, NULL); - ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, flags); - secp256k1_scalar_clear(&key); - return ret; -} - -int secp256k1_ec_privkey_import(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *privkey, size_t privkeylen) { - secp256k1_scalar key; - int ret = 0; - ARG_CHECK(seckey != NULL); - ARG_CHECK(privkey != NULL); - (void)ctx; - - ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen); - if (ret) { - secp256k1_scalar_get_b32(seckey, &key); - } - secp256k1_scalar_clear(&key); - return ret; -} - int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); @@ -476,12 +524,13 @@ int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *see return 1; } -int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, int n) { - int i; +int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { + size_t i; secp256k1_gej Qj; secp256k1_ge Q; ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); ARG_CHECK(n >= 1); ARG_CHECK(pubnonces != NULL); @@ -492,7 +541,6 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey * secp256k1_gej_add_ge(&Qj, &Qj, &Q); } if (secp256k1_gej_is_infinity(&Qj)) { - memset(pubnonce, 0, sizeof(*pubnonce)); return 0; } secp256k1_ge_set_gej(&Q, &Qj); diff --git a/crypto/secp256k1/libsecp256k1/src/testrand.h b/crypto/secp256k1/libsecp256k1/src/testrand.h index 041bb92c47..f8efa93c7c 100644 --- a/crypto/secp256k1/libsecp256k1/src/testrand.h +++ b/crypto/secp256k1/libsecp256k1/src/testrand.h @@ -16,13 +16,23 @@ /** Seed the pseudorandom number generator for testing. */ SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); -/** Generate a pseudorandom 32-bit number. */ +/** Generate a pseudorandom number in the range [0..2**32-1]. */ static uint32_t secp256k1_rand32(void); +/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or + * more. */ +static uint32_t secp256k1_rand_bits(int bits); + +/** Generate a pseudorandom number in the range [0..range-1]. */ +static uint32_t secp256k1_rand_int(uint32_t range); + /** Generate a pseudorandom 32-byte array. */ static void secp256k1_rand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ static void secp256k1_rand256_test(unsigned char *b32); +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); + #endif diff --git a/crypto/secp256k1/libsecp256k1/src/testrand_impl.h b/crypto/secp256k1/libsecp256k1/src/testrand_impl.h index 7c35542662..15c7b9f12d 100644 --- a/crypto/secp256k1/libsecp256k1/src/testrand_impl.h +++ b/crypto/secp256k1/libsecp256k1/src/testrand_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -16,6 +16,8 @@ static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; static uint32_t secp256k1_test_rng_precomputed[8]; static int secp256k1_test_rng_precomputed_used = 8; +static uint64_t secp256k1_test_rng_integer; +static int secp256k1_test_rng_integer_bits_left = 0; SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); @@ -29,32 +31,80 @@ SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; } +static uint32_t secp256k1_rand_bits(int bits) { + uint32_t ret; + if (secp256k1_test_rng_integer_bits_left < bits) { + secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); + secp256k1_test_rng_integer_bits_left += 32; + } + ret = secp256k1_test_rng_integer; + secp256k1_test_rng_integer >>= bits; + secp256k1_test_rng_integer_bits_left -= bits; + ret &= ((~((uint32_t)0)) >> (32 - bits)); + return ret; +} + +static uint32_t secp256k1_rand_int(uint32_t range) { + /* We want a uniform integer between 0 and range-1, inclusive. + * B is the smallest number such that range <= 2**B. + * two mechanisms implemented here: + * - generate B bits numbers until one below range is found, and return it + * - find the largest multiple M of range that is <= 2**(B+A), generate B+A + * bits numbers until one below M is found, and return it modulo range + * The second mechanism consumes A more bits of entropy in every iteration, + * but may need fewer iterations due to M being closer to 2**(B+A) then + * range is to 2**B. The array below (indexed by B) contains a 0 when the + * first mechanism is to be used, and the number A otherwise. + */ + static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; + uint32_t trange, mult; + int bits = 0; + if (range <= 1) { + return 0; + } + trange = range - 1; + while (trange > 0) { + trange >>= 1; + bits++; + } + if (addbits[bits]) { + bits = bits + addbits[bits]; + mult = ((~((uint32_t)0)) >> (32 - bits)) / range; + trange = range * mult; + } else { + trange = range; + mult = 1; + } + while(1) { + uint32_t x = secp256k1_rand_bits(bits); + if (x < trange) { + return (mult == 1) ? x : (x % range); + } + } +} + static void secp256k1_rand256(unsigned char *b32) { secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); } -static void secp256k1_rand256_test(unsigned char *b32) { - int bits=0; - uint64_t ent = 0; - int entleft = 0; - memset(b32, 0, 32); - while (bits < 256) { +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { int now; uint32_t val; - if (entleft < 12) { - ent |= ((uint64_t)secp256k1_rand32()) << entleft; - entleft += 32; - } - now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31; - val = 1 & (ent >> 11); - ent >>= 12; - entleft -= 12; - while (now > 0 && bits < 256) { - b32[bits / 8] |= val << (bits % 8); + now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; + val = secp256k1_rand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); now--; bits++; } } } +static void secp256k1_rand256_test(unsigned char *b32) { + secp256k1_rand_bytes_test(b32, 32); +} + #endif diff --git a/crypto/secp256k1/libsecp256k1/src/tests.c b/crypto/secp256k1/libsecp256k1/src/tests.c index 3366d90fca..9ae7d30281 100644 --- a/crypto/secp256k1/libsecp256k1/src/tests.c +++ b/crypto/secp256k1/libsecp256k1/src/tests.c @@ -13,8 +13,8 @@ #include -#include "include/secp256k1.h" #include "secp256k1.c" +#include "include/secp256k1.h" #include "testrand_impl.h" #ifdef ENABLE_OPENSSL_TESTS @@ -24,9 +24,39 @@ #include "openssl/obj_mac.h" #endif +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" + +#if !defined(VG_CHECK) +# if defined(VALGRIND) +# include +# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +# else +# define VG_UNDEF(x,y) +# define VG_CHECK(x,y) +# endif +#endif + static int count = 64; static secp256k1_context *ctx = NULL; +static void counting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts. */ + int32_t *p; + (void)str; + p = data; + (*p)++; +} + +static void uncounting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts (backwards). */ + int32_t *p; + (void)str; + p = data; + (*p)--; +} + void random_field_element_test(secp256k1_fe *fe) { do { unsigned char b32[32]; @@ -39,7 +69,7 @@ void random_field_element_test(secp256k1_fe *fe) { void random_field_element_magnitude(secp256k1_fe *fe) { secp256k1_fe zero; - int n = secp256k1_rand32() % 9; + int n = secp256k1_rand_int(9); secp256k1_fe_normalize(fe); if (n == 0) { return; @@ -55,7 +85,7 @@ void random_group_element_test(secp256k1_ge *ge) { secp256k1_fe fe; do { random_field_element_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) { + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { secp256k1_fe_normalize(&ge->y); break; } @@ -104,7 +134,12 @@ void random_scalar_order(secp256k1_scalar *num) { } void run_context_tests(void) { - secp256k1_context *none = secp256k1_context_create(0); + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + unsigned char ctmp[32]; + int32_t ecount; + int32_t ecount2; + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); @@ -114,6 +149,13 @@ void run_context_tests(void) { secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; + ecount = 0; + ecount2 = 10; + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /*** clone and destroy all of them to make sure cloning was complete ***/ { secp256k1_context *ctx_tmp; @@ -124,12 +166,54 @@ void run_context_tests(void) { ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); } + /* Verify that the error callback makes it across the clone. */ + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* And that it resets back to default. */ + secp256k1_context_set_error_callback(sign, NULL, NULL); + CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + /*** attempt to use them ***/ random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); + /* Verify context-type checking illegal-argument errors. */ + memset(ctmp, 1, 32); + CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); + CHECK(ecount == 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); + CHECK(ecount == 2); + VG_UNDEF(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); + VG_CHECK(&sig, sizeof(sig)); + CHECK(ecount2 == 10); + CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); + CHECK(ecount2 == 11); + CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 12); + CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 13); + CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_context_randomize(sign, NULL) == 1); + CHECK(ecount2 == 13); + secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); + secp256k1_context_set_illegal_callback(sign, NULL, NULL); + + /* This shouldn't leak memory, due to already-set tests. */ + secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); + secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); + /* obtain a working nonce */ do { random_scalar_order_test(&nonce); @@ -148,6 +232,8 @@ void run_context_tests(void) { secp256k1_context_destroy(sign); secp256k1_context_destroy(vrfy); secp256k1_context_destroy(both); + /* Defined as no-op. */ + secp256k1_context_destroy(NULL); } /***** HASH TESTS *****/ @@ -178,7 +264,7 @@ void run_sha256_tests(void) { secp256k1_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + int split = secp256k1_rand_int(strlen(inputs[i])); secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); @@ -222,7 +308,7 @@ void run_hmac_sha256_tests(void) { secp256k1_hmac_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + int split = secp256k1_rand_int(strlen(inputs[i])); secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); @@ -273,11 +359,83 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_finalize(&rng); } +/***** RANDOM TESTS *****/ + +void test_rand_bits(int rand32, int bits) { + /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to + * get a false negative chance below once in a billion */ + static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; + /* We try multiplying the results with various odd numbers, which shouldn't + * influence the uniform distribution modulo a power of 2. */ + static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; + /* We only select up to 6 bits from the output to analyse */ + unsigned int usebits = bits > 6 ? 6 : bits; + unsigned int maxshift = bits - usebits; + /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit + number, track all observed outcomes, one per bit in a uint64_t. */ + uint64_t x[6][27] = {{0}}; + unsigned int i, shift, m; + /* Multiply the output of all rand calls with the odd number m, which + should not change the uniformity of its distribution. */ + for (i = 0; i < rounds[usebits]; i++) { + uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); + CHECK((((uint64_t)r) >> bits) == 0); + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + uint32_t rm = r * mults[m]; + for (shift = 0; shift <= maxshift; shift++) { + x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); + } + } + } + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + for (shift = 0; shift <= maxshift; shift++) { + /* Test that the lower usebits bits of x[shift] are 1 */ + CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); + } + } +} + +/* Subrange must be a whole divisor of range, and at most 64 */ +void test_rand_int(uint32_t range, uint32_t subrange) { + /* (1-1/subrange)^rounds < 1/10^9 */ + int rounds = (subrange * 2073) / 100; + int i; + uint64_t x = 0; + CHECK((range % subrange) == 0); + for (i = 0; i < rounds; i++) { + uint32_t r = secp256k1_rand_int(range); + CHECK(r < range); + r = r % subrange; + x |= (((uint64_t)1) << r); + } + /* Test that the lower subrange bits of x are 1. */ + CHECK(((~x) << (64 - subrange)) == 0); +} + +void run_rand_bits(void) { + size_t b; + test_rand_bits(1, 32); + for (b = 1; b <= 32; b++) { + test_rand_bits(0, b); + } +} + +void run_rand_int(void) { + static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; + static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; + unsigned int m, s; + for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { + for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { + test_rand_int(ms[m] * ss[s], ss[s]); + } + } +} + /***** NUM TESTS *****/ #ifndef USE_NUM_NONE void random_num_negate(secp256k1_num *num) { - if (secp256k1_rand32() & 1) { + if (secp256k1_rand_bits(1)) { secp256k1_num_negate(num); } } @@ -315,16 +473,17 @@ void test_num_negate(void) { } void test_num_add_sub(void) { + int i; + secp256k1_scalar s; secp256k1_num n1; secp256k1_num n2; secp256k1_num n1p2, n2p1, n1m2, n2m1; - int r = secp256k1_rand32(); random_num_order_test(&n1); /* n1 = R1 */ - if (r & 1) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n1); } random_num_order_test(&n2); /* n2 = R2 */ - if (r & 2) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n2); } secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ @@ -341,6 +500,110 @@ void test_num_add_sub(void) { CHECK(!secp256k1_num_eq(&n2p1, &n1)); secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ CHECK(secp256k1_num_eq(&n2p1, &n1)); + + /* check is_one */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&n1, &s); + CHECK(secp256k1_num_is_one(&n1)); + /* check that 2^n + 1 is never 1 */ + secp256k1_scalar_get_num(&n2, &s); + for (i = 0; i < 250; ++i) { + secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */ + secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */ + CHECK(!secp256k1_num_is_one(&n1p2)); + } +} + +void test_num_mod(void) { + int i; + secp256k1_scalar s; + secp256k1_num order, n; + + /* check that 0 mod anything is 0 */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_set_int(&s, 0); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that anything mod 1 is 0 */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that increasing the number past 2^256 does not break this */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&n, &s); + /* multiply by 2^8, which'll test this case with high probability */ + for (i = 0; i < 8; ++i) { + secp256k1_num_add(&n, &n, &n); + } + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); +} + +void test_num_jacobi(void) { + secp256k1_scalar sqr; + secp256k1_scalar small; + secp256k1_scalar five; /* five is not a quadratic residue */ + secp256k1_num order, n; + int i; + /* squares mod 5 are 1, 4 */ + const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 }; + + /* check some small values with 5 as the order */ + secp256k1_scalar_set_int(&five, 5); + secp256k1_scalar_get_num(&order, &five); + for (i = 0; i < 10; ++i) { + secp256k1_scalar_set_int(&small, i); + secp256k1_scalar_get_num(&n, &small); + CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]); + } + + /** test large values with 5 as group order */ + secp256k1_scalar_get_num(&order, &five); + /* we first need a scalar which is not a multiple of 5 */ + do { + secp256k1_num fiven; + random_scalar_order_test(&sqr); + secp256k1_scalar_get_num(&fiven, &five); + secp256k1_scalar_get_num(&n, &sqr); + secp256k1_num_mod(&n, &fiven); + } while (secp256k1_num_is_zero(&n)); + /* next force it to be a residue. 2 is a nonresidue mod 5 so we can + * just multiply by two, i.e. add the number to itself */ + if (secp256k1_num_jacobi(&n, &order) == -1) { + secp256k1_num_add(&n, &n, &n); + } + + /* test residue */ + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_num_add(&n, &n, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + + /** test with secp group order as order */ + secp256k1_scalar_order_get_num(&order); + random_scalar_order_test(&sqr); + secp256k1_scalar_sqr(&sqr, &sqr); + /* test residue */ + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_scalar_mul(&sqr, &sqr, &five); + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + /* test multiple of the order*/ + CHECK(secp256k1_num_jacobi(&order, &order) == 0); + + /* check one less than the order */ + secp256k1_scalar_set_int(&small, 1); + secp256k1_scalar_get_num(&n, &small); + secp256k1_num_sub(&n, &order, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */ } void run_num_smalltests(void) { @@ -348,6 +611,8 @@ void run_num_smalltests(void) { for (i = 0; i < 100*count; i++) { test_num_negate(); test_num_add_sub(); + test_num_mod(); + test_num_jacobi(); } } #endif @@ -409,7 +674,7 @@ void scalar_test(void) { while (i < 256) { secp256k1_scalar t; int j; - int now = (secp256k1_rand32() % 15) + 1; + int now = secp256k1_rand_int(15) + 1; if (now + i > 256) { now = 256 - i; } @@ -437,7 +702,7 @@ void scalar_test(void) { } { - /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */ + /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ secp256k1_scalar r; secp256k1_num r2num; secp256k1_num rnum; @@ -486,7 +751,7 @@ void scalar_test(void) { secp256k1_num rnum; secp256k1_num rnum2; unsigned char cone[1] = {0x01}; - unsigned int shift = 256 + (secp256k1_rand32() % 257); + unsigned int shift = 256 + secp256k1_rand_int(257); secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); secp256k1_num_mul(&rnum, &s1num, &s2num); secp256k1_num_shift(&rnum, shift - 1); @@ -504,7 +769,7 @@ void scalar_test(void) { random_scalar_order_test(&r); for (i = 0; i < 100; ++i) { int low; - int shift = 1 + (secp256k1_rand32() % 15); + int shift = 1 + secp256k1_rand_int(15); int expected = r.d[0] % (1 << shift); low = secp256k1_scalar_shr_int(&r, shift); CHECK(expected == low); @@ -532,6 +797,10 @@ void scalar_test(void) { secp256k1_scalar_inverse(&inv, &inv); /* Inverting one must result in one. */ CHECK(secp256k1_scalar_is_one(&inv)); +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&invnum, &inv); + CHECK(secp256k1_num_is_one(&invnum)); +#endif } } @@ -548,7 +817,7 @@ void scalar_test(void) { secp256k1_scalar b; int i; /* Test add_bit. */ - int bit = secp256k1_rand32() % 256; + int bit = secp256k1_rand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); for (i = 0; i < bit; i++) { @@ -671,6 +940,600 @@ void run_scalar_tests(void) { CHECK(secp256k1_scalar_is_zero(&zero)); } #endif + + { + /* Does check_overflow check catch all ones? */ + static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + CHECK(secp256k1_scalar_check_overflow(&overflowed)); + } + + { + /* Static test vectors. + * These were reduced from ~10^12 random vectors based on comparison-decision + * and edge-case coverage on 32-bit and 64-bit implementations. + * The responses were generated with Sage 5.9. + */ + secp256k1_scalar x; + secp256k1_scalar y; + secp256k1_scalar z; + secp256k1_scalar zz; + secp256k1_scalar one; + secp256k1_scalar r1; + secp256k1_scalar r2; +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar zzv; +#endif + int overflow; + unsigned char chal[33][2][32] = { + {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, + {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, + {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, + {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, + 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, + {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, + {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, + {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, + {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, + {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, + {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, + {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, + 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, + {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, + {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} + }; + unsigned char res[33][2][32] = { + {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, + 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, + 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, + 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, + {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, + 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, + 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, + 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, + {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, + 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, + 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, + 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, + {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, + 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, + 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, + 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, + {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, + 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, + 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, + 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, + {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, + 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, + 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, + 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, + {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, + 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, + 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, + 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, + {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, + 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, + 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, + 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, + {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, + 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, + 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, + 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, + {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, + 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, + 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, + 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, + {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, + 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, + 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, + 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, + {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, + 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, + 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, + 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, + {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, + 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, + 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, + 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, + {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, + 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, + 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, + 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, + {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, + 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, + 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, + 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, + {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, + 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, + 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, + 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, + {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, + 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, + 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, + 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, + {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, + 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, + 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, + 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, + {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, + 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, + 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, + 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, + {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, + 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, + 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, + 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, + {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, + 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, + 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, + 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, + {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, + 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, + 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, + 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, + {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, + 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, + 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, + 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, + {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, + 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, + 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, + 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, + {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, + 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, + 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, + 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, + {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, + 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, + 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, + 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, + {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, + 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, + 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, + 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, + {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, + 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, + 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, + 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, + {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, + 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, + 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, + 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, + {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, + 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, + 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, + 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, + {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, + 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, + 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, + 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, + {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, + 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, + 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, + 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, + {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, + 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, + 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, + 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, + {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, + 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, + 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, + 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, + {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, + 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, + 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, + 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, + {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, + 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, + 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, + 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, + {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, + 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, + 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, + 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, + {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, + 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, + 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, + 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, + {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, + 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, + 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, + 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, + {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, + 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, + 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, + 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, + 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, + 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, + 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, + {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, + 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, + 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, + 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, + 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, + 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, + 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, + {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, + 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, + 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, + 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, + {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, + 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, + 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, + 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, + {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, + 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, + 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, + 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, + {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, + 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, + 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, + 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, + {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, + 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, + 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, + 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, + {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, + 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, + 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, + 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, + {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, + 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, + 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, + 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, + {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, + 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, + 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, + 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, + {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, + 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, + 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, + 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, + {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, + 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, + 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, + 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, + {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, + 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, + 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, + {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, + {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} + }; + secp256k1_scalar_set_int(&one, 1); + for (i = 0; i < 33; i++) { + secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_mul(&z, &x, &y); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&r1, &z)); + if (!secp256k1_scalar_is_zero(&y)) { + secp256k1_scalar_inverse(&zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar_inverse_var(&zzv, &y); + CHECK(secp256k1_scalar_eq(&zzv, &zz)); +#endif + secp256k1_scalar_mul(&z, &z, &zz); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&x, &z)); + secp256k1_scalar_mul(&zz, &zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&one, &zz)); + } + secp256k1_scalar_mul(&z, &x, &x); + CHECK(!secp256k1_scalar_check_overflow(&z)); + secp256k1_scalar_sqr(&zz, &x); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&zz, &z)); + CHECK(secp256k1_scalar_eq(&r2, &zz)); + } + } } /***** FIELD TESTS *****/ @@ -685,6 +1548,16 @@ void random_fe(secp256k1_fe *x) { } while(1); } +void random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256_test(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + void random_fe_non_zero(secp256k1_fe *nz) { int tries = 10; while (--tries >= 0) { @@ -701,7 +1574,7 @@ void random_fe_non_zero(secp256k1_fe *nz) { void random_fe_non_square(secp256k1_fe *ns) { secp256k1_fe r; random_fe_non_zero(ns); - if (secp256k1_fe_sqrt_var(&r, ns)) { + if (secp256k1_fe_sqrt(&r, ns)) { secp256k1_fe_negate(ns, ns, 1); } } @@ -860,18 +1733,18 @@ void run_field_inv_all_var(void) { secp256k1_fe x[16], xi[16], xii[16]; int i; /* Check it's safe to call for 0 elements */ - secp256k1_fe_inv_all_var(0, xi, x); + secp256k1_fe_inv_all_var(xi, x, 0); for (i = 0; i < count; i++) { size_t j; - size_t len = (secp256k1_rand32() & 15) + 1; + size_t len = secp256k1_rand_int(15) + 1; for (j = 0; j < len; j++) { random_fe_non_zero(&x[j]); } - secp256k1_fe_inv_all_var(len, xi, x); + secp256k1_fe_inv_all_var(xi, x, len); for (j = 0; j < len; j++) { CHECK(check_fe_inverse(&x[j], &xi[j])); } - secp256k1_fe_inv_all_var(len, xii, xi); + secp256k1_fe_inv_all_var(xii, xi, len); for (j = 0; j < len; j++) { CHECK(check_fe_equal(&x[j], &xii[j])); } @@ -896,7 +1769,7 @@ void run_sqr(void) { void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { secp256k1_fe r1, r2; - int v = secp256k1_fe_sqrt_var(&r1, a); + int v = secp256k1_fe_sqrt(&r1, a); CHECK((v == 0) == (k == NULL)); if (k != NULL) { @@ -1002,7 +1875,7 @@ void test_ge(void) { /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. * All magnitudes are randomized. - * All 17*17 combinations of points are added to eachother, using all applicable methods. + * All 17*17 combinations of points are added to each other, using all applicable methods. * * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. */ @@ -1057,7 +1930,7 @@ void test_ge(void) { zs[i] = gej[i].z; } } - secp256k1_fe_inv_all_var(4 * runs + 1, zinv, zs); + secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1); free(zs); } @@ -1152,7 +2025,7 @@ void test_ge(void) { gej_shuffled[i] = gej[i]; } for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + secp256k1_rand32() % (4 * runs + 1 - i); + int swap = i + secp256k1_rand_int(4 * runs + 1 - i); if (swap != i) { secp256k1_gej t = gej_shuffled[i]; gej_shuffled[i] = gej_shuffled[swap]; @@ -1177,8 +2050,8 @@ void test_ge(void) { secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); } } - secp256k1_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr); - secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback); + secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1); + secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback); for (i = 0; i < 4 * runs + 1; i++) { secp256k1_fe s; random_fe_non_zero(&s); @@ -1206,8 +2079,8 @@ void test_add_neg_y_diff_x(void) { * of the sum to be wrong (since infinity has no xy coordinates). * HOWEVER, if the x-coordinates are different, infinity is the * wrong answer, and such degeneracies are exposed. This is the - * root of https://github.com/bitcoin/secp256k1/issues/257 which - * this test is a regression test for. + * root of https://github.com/bitcoin-core/secp256k1/issues/257 + * which this test is a regression test for. * * These points were generated in sage as * # secp256k1 params @@ -1303,6 +2176,79 @@ void run_ec_combine(void) { } } +void test_group_decompress(const secp256k1_fe* x) { + /* The input itself, normalized. */ + secp256k1_fe fex = *x; + secp256k1_fe fez; + /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_quad, ge_even, ge_odd; + secp256k1_gej gej_quad; + /* Return values of the above calls. */ + int res_quad, res_even, res_odd; + + secp256k1_fe_normalize_var(&fex); + + res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex); + res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); + + CHECK(res_quad == res_even); + CHECK(res_quad == res_odd); + + if (res_quad) { + secp256k1_fe_normalize_var(&ge_quad.x); + secp256k1_fe_normalize_var(&ge_odd.x); + secp256k1_fe_normalize_var(&ge_even.x); + secp256k1_fe_normalize_var(&ge_quad.y); + secp256k1_fe_normalize_var(&ge_odd.y); + secp256k1_fe_normalize_var(&ge_even.y); + + /* No infinity allowed. */ + CHECK(!ge_quad.infinity); + CHECK(!ge_even.infinity); + CHECK(!ge_odd.infinity); + + /* Check that the x coordinates check out. */ + CHECK(secp256k1_fe_equal_var(&ge_quad.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); + + /* Check that the Y coordinate result in ge_quad is a square. */ + CHECK(secp256k1_fe_is_quad_var(&ge_quad.y)); + + /* Check odd/even Y in ge_odd, ge_even. */ + CHECK(secp256k1_fe_is_odd(&ge_odd.y)); + CHECK(!secp256k1_fe_is_odd(&ge_even.y)); + + /* Check secp256k1_gej_has_quad_y_var. */ + secp256k1_gej_set_ge(&gej_quad, &ge_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + } +} + +void run_group_decompress(void) { + int i; + for (i = 0; i < count * 4; i++) { + secp256k1_fe fe; + random_fe_test(&fe); + test_group_decompress(&fe); + } +} + /***** ECMULT TESTS *****/ void run_ecmult_chain(void) { @@ -1582,9 +2528,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, shift; int wnaf[256] = {0}; int i; -#ifdef USE_ENDOMORPHISM int skew; -#endif secp256k1_scalar num = *number; secp256k1_scalar_set_int(&x, 0); @@ -1594,10 +2538,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { for (i = 0; i < 16; ++i) { secp256k1_scalar_shr_int(&num, 8); } - skew = secp256k1_wnaf_const(wnaf, num, w); -#else - secp256k1_wnaf_const(wnaf, num, w); #endif + skew = secp256k1_wnaf_const(wnaf, num, w); for (i = WNAF_SIZE(w); i >= 0; --i) { secp256k1_scalar t; @@ -1616,10 +2558,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { } secp256k1_scalar_add(&x, &x, &t); } -#ifdef USE_ENDOMORPHISM - /* Skew num because when encoding 128-bit numbers as odd we use an offset */ + /* Skew num because when encoding numbers as odd we use an offset */ secp256k1_scalar_cadd_bit(&num, skew == 2, 1); -#endif CHECK(secp256k1_scalar_eq(&x, &num)); } @@ -1640,6 +2580,11 @@ void run_wnaf(void) { test_constant_wnaf_negate(&n); test_constant_wnaf(&n, 4 + (i % 10)); } + secp256k1_scalar_set_int(&n, 0); + CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); + CHECK(secp256k1_scalar_is_zero(&n)); + CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); + CHECK(secp256k1_scalar_is_zero(&n)); } void test_ecmult_constants(void) { @@ -1680,7 +2625,7 @@ void run_ecmult_constants(void) { } void test_ecmult_gen_blind(void) { - /* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */ + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ secp256k1_scalar key; secp256k1_scalar b; unsigned char seed32[32]; @@ -1752,6 +2697,644 @@ void run_endomorphism_tests(void) { } #endif +void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { + unsigned char pubkeyc[65]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + size_t pubkeyclen; + int32_t ecount; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { + /* Smaller sizes are tested exhaustively elsewhere. */ + int32_t i; + memcpy(&pubkeyc[1], input, 64); + VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + for (i = 0; i < 256; i++) { + /* Try all type bytes. */ + int xpass; + int ypass; + int ysign; + pubkeyc[0] = i; + /* What sign does this point have? */ + ysign = (input[63] & 1) + 2; + /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ + xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); + /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ + ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && + ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); + if (xpass || ypass) { + /* These cases must parse. */ + unsigned char pubkeyo[65]; + size_t outl; + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + ecount = 0; + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 33); + CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); + if (ypass) { + /* This test isn't always done because we decode with alternative signs, so the y won't match. */ + CHECK(pubkeyo[0] == ysign); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + secp256k1_pubkey_save(&pubkey, &ge); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 65); + CHECK(pubkeyo[0] == 4); + CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + } + CHECK(ecount == 0); + } else { + /* These cases must fail to parse. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + } + } + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void run_ec_pubkey_parse_test(void) { +#define SECP256K1_EC_PARSE_TEST_NVALID (12) + const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { + { + /* Point with leading and trailing zeros in x and y serialization. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, + 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 + }, + { + /* Point with x equal to a 3rd root of unity.*/ + 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, + 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with largest x. (1/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, + 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, + }, + { + /* Point with largest x. (2/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, + 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, + }, + { + /* Point with smallest x. (1/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with smallest x. (2/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* Point with largest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with smallest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } + }; +#define SECP256K1_EC_PARSE_TEST_NXVALID (4) + const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { + { + /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* x on curve, y is from y^2 = x^3 + 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + } + }; +#define SECP256K1_EC_PARSE_TEST_NINVALID (7) + const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { + { + /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ + 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, + 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, + 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, + 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, + 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, + 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 + } + }; + const unsigned char pubkeyc[66] = { + /* Serialization of G. */ + 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, + 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, + 0xB8, 0x00 + }; + unsigned char sout[65]; + unsigned char shortkey[2]; + secp256k1_ge ge; + secp256k1_pubkey pubkey; + size_t len; + int32_t i; + int32_t ecount; + int32_t ecount2; + ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ + VG_UNDEF(&pubkeyc[65], 1); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + /* Zero length claimed, fail, zeroize, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(shortkey, 2); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Length one claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 256 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i; + VG_UNDEF(&shortkey[1], 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + /* Length two claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 65536 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i & 255; + shortkey[1] = i >> 8; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); + CHECK(ecount == 2); + /* NULL input string. Illegal arg and zeroize output. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 1); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 2); + /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Valid parse. */ + memset(&pubkey, 0, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + VG_UNDEF(&ge, sizeof(ge)); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + VG_CHECK(&ge.x, sizeof(ge.x)); + VG_CHECK(&ge.y, sizeof(ge.y)); + VG_CHECK(&ge.infinity, sizeof(ge.infinity)); + ge_equals_ge(&secp256k1_ge_const_g, &ge); + CHECK(ecount == 0); + /* secp256k1_ec_pubkey_serialize illegal args. */ + ecount = 0; + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 1); + CHECK(len == 0); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 2); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); + VG_CHECK(sout, 65); + CHECK(ecount == 3); + CHECK(len == 0); + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); + CHECK(ecount == 4); + CHECK(len == 0); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(sout, 65); + CHECK(ecount == 4); + CHECK(len == 65); + /* Multiple illegal args. Should still set arg error only once. */ + ecount = 0; + ecount2 = 11; + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + /* Does the illegal arg callback actually change the behavior? */ + secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + CHECK(ecount2 == 10); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + /* Try a bunch of prefabbed points with all possible encodings. */ + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { + ec_pubkey_parse_pointtest(valid[i], 1, 1); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { + ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { + ec_pubkey_parse_pointtest(invalid[i], 0, 0); + } +} + +void run_eckey_edge_case_test(void) { + const unsigned char orderc[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; + unsigned char ctmp[33]; + unsigned char ctmp2[33]; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey2; + secp256k1_pubkey pubkey_one; + secp256k1_pubkey pubkey_negone; + const secp256k1_pubkey *pubkeys[3]; + size_t len; + int32_t ecount; + /* Group order is too large, reject. */ + CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Maximum value is too large, reject. */ + memset(ctmp, 255, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Zero is too small, reject. */ + memset(ctmp, 0, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* One must be accepted. */ + ctmp[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_one = pubkey; + /* Group order + 1 is too large, reject. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x42; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* -1 must be accepted. */ + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_negone = pubkey; + /* Tweak of zero leaves the value changed. */ + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); + CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + memcpy(&pubkey2, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Multiply tweak of zero zeroizes the output. */ + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Overflowing key tweak zeroizes. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Private key tweaks results in a key of zero. */ + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); + CHECK(memcmp(zeros, ctmp2, 32) == 0); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Tweak computation wraps and results in a key of 1. */ + ctmp2[31] = 2; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); + CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Tweak mul * 2 = 1+1. */ + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Test argument errors. */ + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(ecount == 0); + /* Zeroize pubkey on parse error. */ + memset(&pubkey, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + memset(&pubkey2, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + /* Plain argument errors. */ + ecount = 0; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0); + CHECK(ecount == 1); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0); + CHECK(ecount == 1); + memset(&pubkey, 1, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* secp256k1_ec_pubkey_combine tests. */ + ecount = 0; + pubkeys[0] = &pubkey_one; + VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 2); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + pubkeys[0] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Result is infinity. */ + pubkeys[0] = &pubkey_one; + pubkeys[1] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + /* Passes through infinity but comes out one. */ + pubkeys[2] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Adds to two. */ + pubkeys[1] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { secp256k1_scalar nonce; do { @@ -1771,7 +3354,7 @@ void test_ecdsa_sign_verify(void) { random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_rand32()&1; + getrec = secp256k1_rand_bits(1); random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); if (getrec) { CHECK(recid >= 0 && recid < 4); @@ -1828,7 +3411,7 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char } return 1; } - /* Retry rate of 6979 is negligible esp. as we only call this in determinstic tests. */ + /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ if (counter > 5) { return 0; @@ -1846,7 +3429,8 @@ void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; unsigned char privkey2[32]; - secp256k1_ecdsa_signature signature[5]; + secp256k1_ecdsa_signature signature[6]; + secp256k1_scalar r, s; unsigned char sig[74]; size_t siglen = 74; unsigned char pubkeyc[65]; @@ -1869,17 +3453,17 @@ void test_ecdsa_end_to_end(void) { CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); /* Verify exporting and importing public key. */ - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand32() % 2) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); memset(&pubkey, 0, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); /* Verify private key import and export. */ - CHECK(secp256k1_ec_privkey_export(ctx, seckey, &seckeylen, privkey, (secp256k1_rand32() % 2) == 1) ? SECP256K1_EC_COMPRESSED : 0); - CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1); + CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); + CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); CHECK(memcmp(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { int ret1; int ret2; unsigned char rnd[32]; @@ -1896,7 +3480,7 @@ void test_ecdsa_end_to_end(void) { } /* Optionally tweak the keys using multiplication. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { int ret1; int ret2; unsigned char rnd[32]; @@ -1933,6 +3517,22 @@ void test_ecdsa_end_to_end(void) { CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(memcmp(&signature[5], &signature[0], 64) == 0); /* Serialize/parse DER and verify again */ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); @@ -1942,7 +3542,7 @@ void test_ecdsa_end_to_end(void) { /* Serialize/destroy/parse DER and verify again. */ siglen = 74; CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); - sig[secp256k1_rand32() % siglen] += 1 + (secp256k1_rand32() % 255); + sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); } @@ -1952,23 +3552,18 @@ void test_random_pubkeys(void) { secp256k1_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - uint32_t r = secp256k1_rand32(); - size_t len = (r & 3) == 0 ? 65 : 33; - r>>=2; - if ((r & 3) == 0) { - len = (r & 252) >> 3; + size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_rand_bits(2) == 0) { + len = secp256k1_rand_bits(6); } - r>>=8; if (len == 65) { - in[0] = (r & 2) ? 4 : ((r & 1)? 6 : 7); + in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); } else { - in[0] = (r & 1) ? 2 : 3; + in[0] = secp256k1_rand_bits(1) ? 2 : 3; } - r>>=2; - if ((r & 7) == 0) { - in[0] = (r & 2040) >> 3; + if (secp256k1_rand_bits(3) == 0) { + in[0] = secp256k1_rand_bits(8); } - r>>=11; if (len > 1) { secp256k1_rand256(&in[1]); } @@ -1982,7 +3577,7 @@ void test_random_pubkeys(void) { size_t size = len; firstb = in[0]; /* If the pubkey can be parsed, it should round-trip... */ - CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, (len == 33) ? SECP256K1_EC_COMPRESSED : 0)); + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); CHECK(size == len); CHECK(memcmp(&in[1], &out[1], len-1) == 0); /* ... except for the type of hybrid inputs. */ @@ -1995,7 +3590,7 @@ void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); ge_equals_ge(&elem,&elem2); /* Check that the X9.62 hybrid type is checked. */ - in[0] = (r & 1) ? 6 : 7; + in[0] = secp256k1_rand_bits(1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { if (in[0] == firstb + 4) { @@ -2026,6 +3621,334 @@ void run_ecdsa_end_to_end(void) { } } +int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { + static const unsigned char zeroes[32] = {0}; +#ifdef ENABLE_OPENSSL_TESTS + static const unsigned char max_scalar[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 + }; +#endif + + int ret = 0; + + secp256k1_ecdsa_signature sig_der; + unsigned char roundtrip_der[2048]; + unsigned char compact_der[64]; + size_t len_der = 2048; + int parsed_der = 0, valid_der = 0, roundtrips_der = 0; + + secp256k1_ecdsa_signature sig_der_lax; + unsigned char roundtrip_der_lax[2048]; + unsigned char compact_der_lax[64]; + size_t len_der_lax = 2048; + int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; + +#ifdef ENABLE_OPENSSL_TESTS + ECDSA_SIG *sig_openssl; + const unsigned char *sigptr; + unsigned char roundtrip_openssl[2048]; + int len_openssl = 2048; + int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; +#endif + + parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + if (parsed_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; + valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + } + if (valid_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + } + + parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + if (parsed_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + } + if (valid_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + } + + if (certainly_der) { + ret |= (!parsed_der) << 2; + } + if (certainly_not_der) { + ret |= (parsed_der) << 17; + } + if (valid_der) { + ret |= (!roundtrips_der) << 3; + } + + if (valid_der) { + ret |= (!roundtrips_der_lax) << 12; + ret |= (len_der != len_der_lax) << 13; + ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + } + ret |= (roundtrips_der != roundtrips_der_lax) << 15; + if (parsed_der) { + ret |= (!parsed_der_lax) << 16; + } + +#ifdef ENABLE_OPENSSL_TESTS + sig_openssl = ECDSA_SIG_new(); + sigptr = sig; + parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); + if (parsed_openssl) { + valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + } + len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); + if (len_openssl <= 2048) { + unsigned char *ptr = roundtrip_openssl; + CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); + roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); + } else { + len_openssl = 0; + } + ECDSA_SIG_free(sig_openssl); + + ret |= (parsed_der && !parsed_openssl) << 4; + ret |= (valid_der && !valid_openssl) << 5; + ret |= (roundtrips_openssl && !parsed_der) << 6; + ret |= (roundtrips_der != roundtrips_openssl) << 7; + if (roundtrips_openssl) { + ret |= (len_der != (size_t)len_openssl) << 8; + ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; + } +#endif + return ret; +} + +static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { + size_t i; + for (i = 0; i < ptrlen; i++) { + int shift = ptrlen - 1 - i; + if (shift >= 4) { + ptr[i] = 0; + } else { + ptr[i] = (val >> shift) & 0xFF; + } + } +} + +static void damage_array(unsigned char *sig, size_t *len) { + int pos; + int action = secp256k1_rand_bits(3); + if (action < 1 && *len > 3) { + /* Delete a byte. */ + pos = secp256k1_rand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2 && *len < 2048) { + /* Insert a byte. */ + pos = secp256k1_rand_int(1 + *len); + memmove(sig + pos + 1, sig + pos, *len - pos); + sig[pos] = secp256k1_rand_bits(8); + (*len)++; + return; + } else if (action < 4) { + /* Modify a byte. */ + sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); + return; + } else { /* action < 8 */ + /* Modify a bit. */ + sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); + return; + } +} + +static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { + int der; + int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; + size_t tlen, elen, glen; + int indet; + int n; + + *len = 0; + der = secp256k1_rand_bits(2) == 0; + *certainly_der = der; + *certainly_not_der = 0; + indet = der ? 0 : secp256k1_rand_int(10) == 0; + + for (n = 0; n < 2; n++) { + /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ + nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); + /* The length of the number in bytes (the first byte of which will always be nonzero) */ + nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; + CHECK(nlen[n] <= 232); + /* The top bit of the number. */ + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); + /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); + /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8); + if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { + *certainly_not_der = 1; + } + CHECK(nlen[n] + nzlen[n] <= 300); + /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ + nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); + if (!der) { + /* nlenlen[n] max 127 bytes */ + int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + nlenlen[n] += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); + } + + /* The total length of the data to go, so far */ + tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; + CHECK(tlen <= 856); + + /* The length of the garbage inside the tuple. */ + elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; + if (elen != 0) { + *certainly_not_der = 1; + } + tlen += elen; + CHECK(tlen <= 980); + + /* The length of the garbage after the end of the tuple. */ + glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; + if (glen != 0) { + *certainly_not_der = 1; + } + CHECK(tlen + glen <= 990); + + /* Write the tuple header. */ + sig[(*len)++] = 0x30; + if (indet) { + /* Indeterminate length */ + sig[(*len)++] = 0x80; + *certainly_not_der = 1; + } else { + int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); + if (!der) { + int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + tlenlen += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + if (tlenlen == 0) { + /* Short length notation */ + sig[(*len)++] = tlen; + } else { + /* Long length notation */ + sig[(*len)++] = 128 + tlenlen; + assign_big_endian(sig + *len, tlenlen, tlen); + *len += tlenlen; + } + tlen += tlenlen; + } + tlen += 2; + CHECK(tlen + glen <= 1119); + + for (n = 0; n < 2; n++) { + /* Write the integer header. */ + sig[(*len)++] = 0x02; + if (nlenlen[n] == 0) { + /* Short length notation */ + sig[(*len)++] = nlen[n] + nzlen[n]; + } else { + /* Long length notation. */ + sig[(*len)++] = 128 + nlenlen[n]; + assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); + *len += nlenlen[n]; + } + /* Write zero padding */ + while (nzlen[n] > 0) { + sig[(*len)++] = 0x00; + nzlen[n]--; + } + if (nlen[n] == 32 && !nlow[n]) { + /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ + int i; + for (i = 0; i < 16; i++) { + sig[(*len)++] = 0xFF; + } + nlen[n] -= 16; + } + /* Write first byte of number */ + if (nlen[n] > 0) { + sig[(*len)++] = nhbyte[n]; + nlen[n]--; + } + /* Generate remaining random bytes of number */ + secp256k1_rand_bytes_test(sig + *len, nlen[n]); + *len += nlen[n]; + nlen[n] = 0; + } + + /* Generate random garbage inside tuple. */ + secp256k1_rand_bytes_test(sig + *len, elen); + *len += elen; + + /* Generate end-of-contents bytes. */ + if (indet) { + sig[(*len)++] = 0; + sig[(*len)++] = 0; + tlen += 2; + } + CHECK(tlen + glen <= 1121); + + /* Generate random garbage outside tuple. */ + secp256k1_rand_bytes_test(sig + *len, glen); + *len += glen; + tlen += glen; + CHECK(tlen <= 1121); + CHECK(tlen == *len); +} + +void run_ecdsa_der_parse(void) { + int i,j; + for (i = 0; i < 200 * count; i++) { + unsigned char buffer[2048]; + size_t buflen = 0; + int certainly_der = 0; + int certainly_not_der = 0; + random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + CHECK(buflen <= 2048); + for (j = 0; j < 16; j++) { + int ret = 0; + if (j > 0) { + damage_array(buffer, &buflen); + /* We don't know anything anymore about the DERness of the result */ + certainly_der = 0; + certainly_not_der = 0; + } + ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); + if (ret != 0) { + size_t k; + fprintf(stderr, "Failure %x on ", ret); + for (k = 0; k < buflen; k++) { + fprintf(stderr, "%02x ", buffer[k]); + } + fprintf(stderr, "\n"); + } + CHECK(ret == 0); + } + } +} + /* Tests several edge cases. */ void test_ecdsa_edge_cases(void) { int t; @@ -2047,11 +3970,159 @@ void test_ecdsa_edge_cases(void) { CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); } - /*Signature where s would be zero.*/ + /* Verify signature with r of zero fails. */ { - unsigned char signature[72]; + const unsigned char pubkey_mods_zero[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x41 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 0); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with s of zero fails. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 0); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 1); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with message 0 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02 + }; + const unsigned char pubkey2[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x43 + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 2); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message 1 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, + 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, + 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, + 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, + 0x25 + }; + const unsigned char pubkey2[33] = { + 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, + 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, + 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, + 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, + 0x62 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message -1 passes. */ + { + const unsigned char pubkey[33] = { + 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, + 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, + 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, + 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, + 0xf1 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_negate(&msg, &msg); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_set_int(&ss, 3); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Signature where s would be zero. */ + { + secp256k1_pubkey pubkey; size_t siglen; - const unsigned char nonce[32] = { + int32_t ecount; + unsigned char signature[72]; + static const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2075,15 +4146,72 @@ void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 3); CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 7); + /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); + CHECK(ecount == 8); siglen = 72; + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); + CHECK(ecount == 11); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); + CHECK(ecount == 13); siglen = 10; + /* Too little room for a signature does not fail via ARGCHECK. */ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); + CHECK(ecount == 13); + ecount = 0; + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); + CHECK(ecount == 5); + memset(signature, 255, 64); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); + CHECK(ecount == 5); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } /* Nonce function corner cases. */ @@ -2116,7 +4244,7 @@ void test_ecdsa_edge_cases(void) { CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); CHECK(!is_empty_signature(&sig2)); CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); - /* The default nonce function is determinstic. */ + /* The default nonce function is deterministic. */ CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); @@ -2147,6 +4275,34 @@ void test_ecdsa_edge_cases(void) { key[0] = 0; } + { + /* Check that optional nonce arguments do not have equivalent effect. */ + const unsigned char zeros[32] = {0}; + unsigned char nonce[32]; + unsigned char nonce2[32]; + unsigned char nonce3[32]; + unsigned char nonce4[32]; + VG_UNDEF(nonce,32); + VG_UNDEF(nonce2,32); + VG_UNDEF(nonce3,32); + VG_UNDEF(nonce4,32); + CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); + VG_CHECK(nonce,32); + CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); + VG_CHECK(nonce2,32); + CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); + VG_CHECK(nonce3,32); + CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); + VG_CHECK(nonce4,32); + CHECK(memcmp(nonce, nonce2, 32) != 0); + CHECK(memcmp(nonce, nonce3, 32) != 0); + CHECK(memcmp(nonce, nonce4, 32) != 0); + CHECK(memcmp(nonce2, nonce3, 32) != 0); + CHECK(memcmp(nonce2, nonce4, 32) != 0); + CHECK(memcmp(nonce3, nonce4, 32) != 0); + } + + /* Privkey export where pubkey is the point at infinity. */ { unsigned char privkey[300]; @@ -2157,9 +4313,9 @@ void test_ecdsa_edge_cases(void) { 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, }; size_t outlen = 300; - CHECK(!secp256k1_ec_privkey_export(ctx, privkey, &outlen, seckey, 0)); + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); outlen = 300; - CHECK(!secp256k1_ec_privkey_export(ctx, privkey, &outlen, seckey, SECP256K1_EC_COMPRESSED)); + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); } } @@ -2168,13 +4324,13 @@ void run_ecdsa_edge_cases(void) { } #ifdef ENABLE_OPENSSL_TESTS -EC_KEY *get_openssl_key(const secp256k1_scalar *key) { +EC_KEY *get_openssl_key(const unsigned char *key32) { unsigned char privkey[300]; size_t privkeylen; const unsigned char* pbegin = privkey; - int compr = secp256k1_rand32() & 1; + int compr = secp256k1_rand_bits(1); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr ? SECP256K1_EC_COMPRESSED : 0)); + CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); CHECK(EC_KEY_check_key(ec_key)); return ec_key; @@ -2192,12 +4348,14 @@ void test_ecdsa_openssl(void) { size_t secp_sigsize = 80; unsigned char message[32]; unsigned char signature[80]; + unsigned char key32[32]; secp256k1_rand256_test(message); secp256k1_scalar_set_b32(&msg, message, NULL); random_scalar_order_test(&key); + secp256k1_scalar_get_b32(key32, &key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); secp256k1_ge_set_gej(&q, &qj); - ec_key = get_openssl_key(&key); + ec_key = get_openssl_key(key32); CHECK(ec_key != NULL); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); @@ -2278,12 +4436,14 @@ int main(int argc, char **argv) { /* initialize */ run_context_tests(); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - if (secp256k1_rand32() & 1) { + if (secp256k1_rand_bits(1)) { secp256k1_rand256(run32); - CHECK(secp256k1_context_randomize(ctx, (secp256k1_rand32() & 1) ? run32 : NULL)); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); } + run_rand_bits(); + run_rand_int(); + run_sha256_tests(); run_hmac_sha256_tests(); run_rfc6979_hmac_sha256_tests(); @@ -2307,6 +4467,7 @@ int main(int argc, char **argv) { /* group tests */ run_ge(); + run_group_decompress(); /* ecmult tests */ run_wnaf(); @@ -2322,6 +4483,12 @@ int main(int argc, char **argv) { run_endomorphism_tests(); #endif + /* EC point parser test */ + run_ec_pubkey_parse_test(); + + /* EC key edge cases */ + run_eckey_edge_case_test(); + #ifdef ENABLE_MODULE_ECDH /* ecdh tests */ run_ecdh_tests(); @@ -2329,6 +4496,7 @@ int main(int argc, char **argv) { /* ecdsa tests */ run_random_pubkeys(); + run_ecdsa_der_parse(); run_ecdsa_sign_verify(); run_ecdsa_end_to_end(); run_ecdsa_edge_cases(); diff --git a/crypto/secp256k1/libsecp256k1/src/tests_exhaustive.c b/crypto/secp256k1/libsecp256k1/src/tests_exhaustive.c new file mode 100644 index 0000000000..b040bb0733 --- /dev/null +++ b/crypto/secp256k1/libsecp256k1/src/tests_exhaustive.c @@ -0,0 +1,470 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include + +#include + +#undef USE_ECMULT_STATIC_PRECOMPUTATION + +#ifndef EXHAUSTIVE_TEST_ORDER +/* see group_impl.h for allowable values */ +#define EXHAUSTIVE_TEST_ORDER 13 +#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */ +#endif + +#include "include/secp256k1.h" +#include "group.h" +#include "secp256k1.c" +#include "testrand_impl.h" + +#ifdef ENABLE_MODULE_RECOVERY +#include "src/modules/recovery/main_impl.h" +#include "include/secp256k1_recovery.h" +#endif + +/** stolen from tests.c */ +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); +} + +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); +} + +void random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} +/** END stolen from tests.c */ + +int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, + const unsigned char *key32, const unsigned char *algo16, + void *data, unsigned int attempt) { + secp256k1_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)algo16; + /* Some nonces cannot be used because they'd cause s and/or r to be zero. + * The signing function has retry logic here that just re-calls the nonce + * function with an increased `attempt`. So if attempt > 0 this means we + * need to change the nonce to avoid an infinite loop. */ + if (attempt > 0) { + *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; + } + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +#ifdef USE_ENDOMORPHISM +void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) { + int i; + for (i = 0; i < order; i++) { + secp256k1_ge res; + secp256k1_ge_mul_lambda(&res, &group[i]); + ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); + } +} +#endif + +void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { + int i, j; + + /* Sanity-check (and check infinity functions) */ + CHECK(secp256k1_ge_is_infinity(&group[0])); + CHECK(secp256k1_gej_is_infinity(&groupj[0])); + for (i = 1; i < order; i++) { + CHECK(!secp256k1_ge_is_infinity(&group[i])); + CHECK(!secp256k1_gej_is_infinity(&groupj[i])); + } + + /* Check all addition formulae */ + for (j = 0; j < order; j++) { + secp256k1_fe fe_inv; + secp256k1_fe_inv(&fe_inv, &groupj[j].z); + for (i = 0; i < order; i++) { + secp256k1_ge zless_gej; + secp256k1_gej tmp; + /* add_var */ + secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_ge */ + if (j > 0) { + secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + /* add_ge_var */ + secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_zinv_var */ + zless_gej.infinity = groupj[j].infinity; + zless_gej.x = groupj[j].x; + zless_gej.y = groupj[j].y; + secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + } + + /* Check doubling */ + for (i = 0; i < order; i++) { + secp256k1_gej tmp; + if (i > 0) { + secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + secp256k1_gej_double_var(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + + /* Check negation */ + for (i = 1; i < order; i++) { + secp256k1_ge tmp; + secp256k1_gej tmpj; + secp256k1_ge_neg(&tmp, &group[i]); + ge_equals_ge(&group[order - i], &tmp); + secp256k1_gej_neg(&tmpj, &groupj[i]); + ge_equals_gej(&group[order - i], &tmpj); + } +} + +void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { + int i, j, r_log; + for (r_log = 1; r_log < order; r_log++) { + for (j = 0; j < order; j++) { + for (i = 0; i < order; i++) { + secp256k1_gej tmp; + secp256k1_scalar na, ng; + secp256k1_scalar_set_int(&na, i); + secp256k1_scalar_set_int(&ng, j); + + secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng); + ge_equals_gej(&group[(i * r_log + j) % order], &tmp); + + if (i > 0) { + secp256k1_ecmult_const(&tmp, &group[i], &ng); + ge_equals_gej(&group[(i * j) % order], &tmp); + } + } + } + } +} + +void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { + secp256k1_fe x; + unsigned char x_bin[32]; + k %= EXHAUSTIVE_TEST_ORDER; + x = group[k].x; + secp256k1_fe_normalize(&x); + secp256k1_fe_get_b32(x_bin, &x); + secp256k1_scalar_set_b32(r, x_bin, NULL); +} + +void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* Verify by calling verify */ + secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + secp256k1_scalar_get_b32(msg32, &msg_s); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } + + /* We would like to verify zero-knowledge here by counting how often every + * possible (s, r) tuple appears, but because the group order is larger + * than the field order, when coercing the x-values to scalar values, some + * appear more often than others, so we are actually not zero-knowledge. + * (This effect also appears in the real code, but the difference is on the + * order of 1/2^128th the field order, so the deviation is not useful to a + * computationally bounded attacker.) + */ +} + +#ifdef ENABLE_MODULE_RECOVERY +void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_fe r_dot_y_normalized; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + int expected_recid; + int recid; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + /* Check directly */ + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + /* In computing the recid, there is an overflow condition that is disabled in + * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value + * will exceed the group order, and our signing code always holds out for r + * values that don't overflow, so with a proper overflow check the tests would + * loop indefinitely. */ + r_dot_y_normalized = group[k].y; + secp256k1_fe_normalize(&r_dot_y_normalized); + /* Also the recovery id is flipped depending if we hit the low-s branch */ + if ((k * s) % order == (i + r * j) % order) { + expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0; + } else { + expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1; + } + CHECK(recid == expected_recid); + + /* Convert to a standard sig then check */ + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } +} + +void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + /* This is essentially a copy of test_exhaustive_verify, with recovery added */ + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int recid = 0; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + secp256k1_scalar_get_b32(msg32, &msg_s); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* We would like to try recovering the pubkey and checking that it matches, + * but pubkey recovery is impossible in the exhaustive tests (the reason + * being that there are 12 nonzero r values, 12 nonzero points, and no + * overlap between the sets, so there are no valid signatures). */ + + /* Verify by converting to a standard signature and calling verify */ + secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} +#endif + +int main(void) { + int i; + secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; + secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; + + /* Build context */ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + /* TODO set z = 1, then do num_tests runs with random z values */ + + /* Generate the entire group */ + secp256k1_gej_set_infinity(&groupj[0]); + secp256k1_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + /* Set a different random z-value for each Jacobian point */ + secp256k1_fe z; + random_fe(&z); + + secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); + secp256k1_ge_set_gej(&group[i], &groupj[i]); + secp256k1_gej_rescale(&groupj[i], &z); + + /* Verify against ecmult_gen */ + { + secp256k1_scalar scalar_i; + secp256k1_gej generatedj; + secp256k1_ge generated; + + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + secp256k1_ge_set_gej(&generated, &generatedj); + + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); + CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); + } + } + + /* Run the tests */ +#ifdef USE_ENDOMORPHISM + test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER); +#endif + test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); + +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); +#endif + + secp256k1_context_destroy(ctx); + return 0; +} + diff --git a/crypto/secp256k1/libsecp256k1/src/util.h b/crypto/secp256k1/libsecp256k1/src/util.h index 4eef4ded47..4092a86c91 100644 --- a/crypto/secp256k1/libsecp256k1/src/util.h +++ b/crypto/secp256k1/libsecp256k1/src/util.h @@ -57,7 +57,10 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * #endif /* Like assert(), but when VERIFY is defined, and side-effect safe. */ -#ifdef VERIFY +#if defined(COVERAGE) +#define VERIFY_CHECK(check) +#define VERIFY_SETUP(stmt) +#elif defined(VERIFY) #define VERIFY_CHECK CHECK #define VERIFY_SETUP(stmt) do { stmt; } while(0) #else diff --git a/crypto/secp256k1/notes.go b/crypto/secp256k1/notes.go deleted file mode 100644 index 93e6d1902f..0000000000 --- a/crypto/secp256k1/notes.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package secp256k1 - -/* - sipa, int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed); - is that how i generate private/public keys? - HaltingState: you pass in a random 32-byte string as seckey - HaltingState: if it is valid, the corresponding pubkey is put in pubkey - and true is returned - otherwise, false is returned - around 1 in 2^128 32-byte strings are invalid, so the odds of even ever seeing one is extremely rare - - private keys are mathematically numbers - each has a corresponding point on the curve as public key - a private key is just a number - a public key is a point with x/y coordinates - almost every 256-bit number is a valid private key (one with a point on the curve corresponding to it) - HaltingState: ok? - - more than half of random points are not on the curve - and actually, it is less than the square root, not less than half, sorry :) -!!! - a private key is a NUMBER - a public key is a POINT - half the x,y values in the field are not on the curve, a private key is an integer. - - HaltingState: yes, n,q = private keys; N,Q = corresponding public keys (N=n*G, Q=q*G); then it follows that n*Q = n*q*G = q*n*G = q*N - that's the reason ECDH works - multiplication is associative and commutativ -*/ - -/* - sipa, ok; i am doing compact signatures and I want to know; can someone change the signature to get another valid signature for same message without the private key - because i know they can do that for the normal 72 byte signatures that openssl was putting out - HaltingState: if you don't enforce non-malleability, yes - HaltingState: if you force the highest bit of t - - it _creates_ signatures that already satisfy that condition - but it will accept ones that don't - maybe i should change that, and be strict - yes; i want some way to know signature is valid but fails malleability - well if the highest bit of S is 1, you can take its complement - and end up with a valid signature - that is canonical -*/ - -/* - - sipa, I am signing messages and highest bit of the compact signature is 1!!! - if (b & 0x80) == 0x80 { - log.Panic("b= %v b2= %v \n", b, b&0x80) - } - what bit? -* Pengoo has quit (Ping timeout: 272 seconds) - the highest bit of the first byte of signature - it's the highest bit of S - so the 32nd byte - wtf - -*/ - -/* - For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest - of the password. The nonces are different each time the 401 authentication challenge - response code is presented, thus making replay attacks virtually impossible. - -can verify client/server match without sending password over network -*/ - -/* - one thing I dont get about armory for instance, -is how the hot-wallet can generate new addresses without -knowing the master key -*/ - -/* - i am yelling at the telehash people for using secp256r1 -instead of secp256k1; they thing r1 is "more secure" despite fact that -there is no implementation that works and wrapping it is now taking -up massive time, lol - ... - - You know that the *r curves are selected via an undisclosed -secret process, right? - HaltingState: telehash is offtopic for this channel. -*/ -/* - For instance, nonces are used in HTTP digest access authentication to calculate an MD5 digest - of the password. The nonces are different each time the 401 authentication challenge - response code is presented, thus making replay attacks virtually impossible. - -can verify client/server match without sending password over network -*/ - -/* -void secp256k1_start(void); -void secp256k1_stop(void); - - * Verify an ECDSA signature. - * Returns: 1: correct signature - * 0: incorrect signature - * -1: invalid public key - * -2: invalid signature - * -int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, - const unsigned char *sig, int siglen, - const unsigned char *pubkey, int pubkeylen); - -http://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html - -Why did this work? ECDSA requires a random number for each signature. If this random -number is ever used twice with the same private key it can be recovered. -This transaction was generated by a hardware bitcoin wallet using a pseudo-random number -generator that was returning the same “random” number every time. - -Nonce is 32 bytes? - - * Create an ECDSA signature. - * Returns: 1: signature created - * 0: nonce invalid, try another one - * In: msg: the message being signed - * msglen: the length of the message being signed - * seckey: pointer to a 32-byte secret key (assumed to be valid) - * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG) - * Out: sig: pointer to a 72-byte array where the signature will be placed. - * siglen: pointer to an int, which will be updated to the signature length (<=72). - * -int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen, - unsigned char *sig, int *siglen, - const unsigned char *seckey, - const unsigned char *nonce); - - - * Create a compact ECDSA signature (64 byte + recovery id). - * Returns: 1: signature created - * 0: nonce invalid, try another one - * In: msg: the message being signed - * msglen: the length of the message being signed - * seckey: pointer to a 32-byte secret key (assumed to be valid) - * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG) - * Out: sig: pointer to a 64-byte array where the signature will be placed. - * recid: pointer to an int, which will be updated to contain the recovery id. - * -int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen, - unsigned char *sig64, - const unsigned char *seckey, - const unsigned char *nonce, - int *recid); - - * Recover an ECDSA public key from a compact signature. - * Returns: 1: public key succesfully recovered (which guarantees a correct signature). - * 0: otherwise. - * In: msg: the message assumed to be signed - * msglen: the length of the message - * compressed: whether to recover a compressed or uncompressed pubkey - * recid: the recovery id (as returned by ecdsa_sign_compact) - * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey. - * pubkeylen: pointer to an int that will contain the pubkey length. - * - -recovery id is between 0 and 3 - -int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, - const unsigned char *sig64, - unsigned char *pubkey, int *pubkeylen, - int compressed, int recid); - - - * Verify an ECDSA secret key. - * Returns: 1: secret key is valid - * 0: secret key is invalid - * In: seckey: pointer to a 32-byte secret key - * -int secp256k1_ecdsa_seckey_verify(const unsigned char *seckey); - -** Just validate a public key. - * Returns: 1: valid public key - * 0: invalid public key - * -int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen); - -** Compute the public key for a secret key. - * In: compressed: whether the computed public key should be compressed - * seckey: pointer to a 32-byte private key. - * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) - * area to store the public key. - * pubkeylen: pointer to int that will be updated to contains the pubkey's - * length. - * Returns: 1: secret was valid, public key stores - * 0: secret was invalid, try again. - * -int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed); -*/ diff --git a/crypto/secp256k1/pubkey_scalar_mul.h b/crypto/secp256k1/pubkey_scalar_mul.h deleted file mode 100644 index 0511545ec0..0000000000 --- a/crypto/secp256k1/pubkey_scalar_mul.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -/** Multiply point by scalar in constant time. - * Returns: 1: multiplication was successful - * 0: scalar was invalid (zero or overflow) - * Args: ctx: pointer to a context object (cannot be NULL) - * Out: point: the multiplied point (usually secret) - * In: point: pointer to a 64-byte bytepublic point, - encoded as two 256bit big-endian numbers. - * scalar: a 32-byte scalar with which to multiply the point - */ -int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) { - int ret = 0; - int overflow = 0; - secp256k1_fe feX, feY; - secp256k1_gej res; - secp256k1_ge ge; - secp256k1_scalar s; - ARG_CHECK(point != NULL); - ARG_CHECK(scalar != NULL); - (void)ctx; - - secp256k1_fe_set_b32(&feX, point); - secp256k1_fe_set_b32(&feY, point+32); - secp256k1_ge_set_xy(&ge, &feX, &feY); - secp256k1_scalar_set_b32(&s, scalar, &overflow); - if (overflow || secp256k1_scalar_is_zero(&s)) { - ret = 0; - } else { - secp256k1_ecmult_const(&res, &ge, &s); - secp256k1_ge_set_gej(&ge, &res); - /* Note: can't use secp256k1_pubkey_save here because it is not constant time. */ - secp256k1_fe_normalize(&ge.x); - secp256k1_fe_normalize(&ge.y); - secp256k1_fe_get_b32(point, &ge.x); - secp256k1_fe_get_b32(point+32, &ge.y); - ret = 1; - } - secp256k1_scalar_clear(&s); - return ret; -} - diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index ebf92c5072..1d24960cb7 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -14,10 +14,9 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +// Package secp256k1 wraps the bitcoin secp256k1 C library. package secp256k1 -// TODO: set USE_SCALAR_4X64 depending on platform? - /* #cgo CFLAGS: -I./libsecp256k1 #cgo CFLAGS: -I./libsecp256k1/src/ @@ -29,7 +28,7 @@ package secp256k1 #define NDEBUG #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" -#include "pubkey_scalar_mul.h" +#include "ext.h" typedef void (*callbackFunc) (const char* msg, void* data); extern void secp256k1GoPanicIllegal(const char* msg, void* data); @@ -45,16 +44,6 @@ import ( "github.com/ubiq/go-ubiq/crypto/randentropy" ) -//#define USE_FIELD_5X64 - -/* - TODO: - > store private keys in buffer and shuffle (deters persistance on swap disc) - > byte permutation (changing) - > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?) -*/ - -// holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h) var ( context *C.secp256k1_context N *big.Int @@ -67,127 +56,57 @@ func init() { HalfN, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", 16) // around 20 ms on a modern CPU. - context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY + context = C.secp256k1_context_create_sign_verify() C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) C.secp256k1_context_set_error_callback(context, C.callbackFunc(C.secp256k1GoPanicError), nil) } var ( - ErrInvalidMsgLen = errors.New("invalid message length for signature recovery") + ErrInvalidMsgLen = errors.New("invalid message length, need 32 bytes") ErrInvalidSignatureLen = errors.New("invalid signature length") ErrInvalidRecoveryID = errors.New("invalid signature recovery id") + ErrInvalidKey = errors.New("invalid private key") + ErrSignFailed = errors.New("signing failed") + ErrRecoverFailed = errors.New("recovery failed") ) -func GenerateKeyPair() ([]byte, []byte) { - var seckey []byte = randentropy.GetEntropyCSPRNG(32) - var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) - var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey - var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey - pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0])) - pubkey65_ptr := (*C.uchar)(unsafe.Pointer(&pubkey65[0])) - - ret := C.secp256k1_ec_pubkey_create( - context, - pubkey64_ptr, - seckey_ptr, - ) - - if ret != C.int(1) { - return GenerateKeyPair() // invalid secret, try again - } - - var output_len C.size_t - - C.secp256k1_ec_pubkey_serialize( // always returns 1 - context, - pubkey65_ptr, - &output_len, - pubkey64_ptr, - 0, // SECP256K1_EC_COMPRESSED - ) - - return pubkey65, seckey -} - -func GeneratePubKey(seckey []byte) ([]byte, error) { - if err := VerifySeckeyValidity(seckey); err != nil { - return nil, err - } - - var pubkey []byte = make([]byte, 64) - var pubkey_ptr *C.secp256k1_pubkey = (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0])) - - var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) - - ret := C.secp256k1_ec_pubkey_create( - context, - pubkey_ptr, - seckey_ptr, - ) - - if ret != C.int(1) { - return nil, errors.New("Unable to generate pubkey from seckey") - } - - return pubkey, nil -} - +// Sign creates a recoverable ECDSA signature. +// The produced signature is in the 65-byte [R || S || V] format where V is 0 or 1. +// +// The caller is responsible for ensuring that msg cannot be chosen +// directly by an attacker. It is usually preferable to use a cryptographic +// hash function on any input before handing it to this function. func Sign(msg []byte, seckey []byte) ([]byte, error) { - msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0])) - seckey_ptr := (*C.uchar)(unsafe.Pointer(&seckey[0])) - - sig := make([]byte, 65) - sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&sig[0])) - - nonce := randentropy.GetEntropyCSPRNG(32) - ndata_ptr := unsafe.Pointer(&nonce[0]) - - noncefp_ptr := &(*C.secp256k1_nonce_function_default) - - if C.secp256k1_ec_seckey_verify(context, seckey_ptr) != C.int(1) { - return nil, errors.New("Invalid secret key") + if len(msg) != 32 { + return nil, ErrInvalidMsgLen } - - ret := C.secp256k1_ecdsa_sign_recoverable( - context, - sig_ptr, - msg_ptr, - seckey_ptr, - noncefp_ptr, - ndata_ptr, - ) - - if ret == C.int(0) { - return Sign(msg, seckey) //invalid secret, try again - } - - sig_serialized := make([]byte, 65) - sig_serialized_ptr := (*C.uchar)(unsafe.Pointer(&sig_serialized[0])) - var recid C.int - - C.secp256k1_ecdsa_recoverable_signature_serialize_compact( - context, - sig_serialized_ptr, // 64 byte compact signature - &recid, - sig_ptr, // 65 byte "recoverable" signature - ) - - sig_serialized[64] = byte(int(recid)) // add back recid to get 65 bytes sig - - return sig_serialized, nil - -} - -func VerifySeckeyValidity(seckey []byte) error { if len(seckey) != 32 { - return errors.New("priv key is not 32 bytes") + return nil, ErrInvalidKey } - var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) - ret := C.secp256k1_ec_seckey_verify(context, seckey_ptr) - if int(ret) != 1 { - return errors.New("invalid seckey") + seckeydata := (*C.uchar)(unsafe.Pointer(&seckey[0])) + if C.secp256k1_ec_seckey_verify(context, seckeydata) != 1 { + return nil, ErrInvalidKey } - return nil + + var ( + msgdata = (*C.uchar)(unsafe.Pointer(&msg[0])) + nonce = randentropy.GetEntropyCSPRNG(32) + noncefunc = &(*C.secp256k1_nonce_function_default) + noncefuncData = unsafe.Pointer(&nonce[0]) + sigstruct C.secp256k1_ecdsa_recoverable_signature + ) + if C.secp256k1_ecdsa_sign_recoverable(context, &sigstruct, msgdata, seckeydata, noncefunc, noncefuncData) == 0 { + return nil, ErrSignFailed + } + + var ( + sig = make([]byte, 65) + sigdata = (*C.uchar)(unsafe.Pointer(&sig[0])) + recid C.int + ) + C.secp256k1_ecdsa_recoverable_signature_serialize_compact(context, sigdata, &recid, &sigstruct) + sig[64] = byte(recid) // add back recid to get 65 bytes sig + return sig, nil } // RecoverPubkey returns the the public key of the signer. @@ -202,49 +121,15 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { return nil, err } - msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0])) - sig_ptr := (*C.uchar)(unsafe.Pointer(&sig[0])) - pubkey := make([]byte, 64) - /* - this slice is used for both the recoverable signature and the - resulting serialized pubkey (both types in libsecp256k1 are 65 - bytes). this saves one allocation of 65 bytes, which is nice as - pubkey recovery is one bottleneck during load in Ethereum - */ - bytes65 := make([]byte, 65) - pubkey_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0])) - recoverable_sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&bytes65[0])) - recid := C.int(sig[64]) - - ret := C.secp256k1_ecdsa_recoverable_signature_parse_compact( - context, - recoverable_sig_ptr, - sig_ptr, - recid) - if ret == C.int(0) { - return nil, errors.New("Failed to parse signature") - } - - ret = C.secp256k1_ecdsa_recover( - context, - pubkey_ptr, - recoverable_sig_ptr, - msg_ptr, + var ( + pubkey = make([]byte, 65) + sigdata = (*C.uchar)(unsafe.Pointer(&sig[0])) + msgdata = (*C.uchar)(unsafe.Pointer(&msg[0])) ) - if ret == C.int(0) { - return nil, errors.New("Failed to recover public key") + if C.secp256k1_ecdsa_recover_pubkey(context, (*C.uchar)(unsafe.Pointer(&pubkey[0])), sigdata, msgdata) == 0 { + return nil, ErrRecoverFailed } - - serialized_pubkey_ptr := (*C.uchar)(unsafe.Pointer(&bytes65[0])) - var output_len C.size_t - C.secp256k1_ec_pubkey_serialize( // always returns 1 - context, - serialized_pubkey_ptr, - &output_len, - pubkey_ptr, - 0, // SECP256K1_EC_COMPRESSED - ) - return bytes65, nil + return pubkey, nil } func checkSignature(sig []byte) error { diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index cc87d867df..aad67f579a 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -18,6 +18,9 @@ package secp256k1 import ( "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" "encoding/hex" "testing" @@ -26,15 +29,41 @@ import ( const TestCount = 1000 -func TestPrivkeyGenerate(t *testing.T) { - _, seckey := GenerateKeyPair() - if err := VerifySeckeyValidity(seckey); err != nil { - t.Errorf("seckey not valid: %s", err) +func generateKeyPair() (pubkey, privkey []byte) { + key, err := ecdsa.GenerateKey(S256(), rand.Reader) + if err != nil { + panic(err) + } + pubkey = elliptic.Marshal(S256(), key.X, key.Y) + privkey = make([]byte, 32) + readBits(privkey, key.D) + return pubkey, privkey +} + +func randSig() []byte { + sig := randentropy.GetEntropyCSPRNG(65) + sig[32] &= 0x70 + sig[64] %= 4 + return sig +} + +// tests for malleability +// highest bit of signature ECDSA s value must be 0, in the 33th byte +func compactSigCheck(t *testing.T, sig []byte) { + var b int = int(sig[32]) + if b < 0 { + t.Errorf("highest bit is negative: %d", b) + } + if ((b >> 7) == 1) != ((b & 0x80) == 0x80) { + t.Errorf("highest bit: %d bit >> 7: %d", b, b>>7) + } + if (b & 0x80) == 0x80 { + t.Errorf("highest bit: %d bit & 0x80: %d", b, b&0x80) } } func TestSignatureValidity(t *testing.T) { - pubkey, seckey := GenerateKeyPair() + pubkey, seckey := generateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, err := Sign(msg, seckey) if err != nil { @@ -57,7 +86,7 @@ func TestSignatureValidity(t *testing.T) { } func TestInvalidRecoveryID(t *testing.T) { - _, seckey := GenerateKeyPair() + _, seckey := generateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) sig[64] = 99 @@ -68,7 +97,7 @@ func TestInvalidRecoveryID(t *testing.T) { } func TestSignAndRecover(t *testing.T) { - pubkey1, seckey := GenerateKeyPair() + pubkey1, seckey := generateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, err := Sign(msg, seckey) if err != nil { @@ -84,7 +113,7 @@ func TestSignAndRecover(t *testing.T) { } func TestRandomMessagesWithSameKey(t *testing.T) { - pubkey, seckey := GenerateKeyPair() + pubkey, seckey := generateKeyPair() keys := func() ([]byte, []byte) { return pubkey, seckey } @@ -93,7 +122,7 @@ func TestRandomMessagesWithSameKey(t *testing.T) { func TestRandomMessagesWithRandomKeys(t *testing.T) { keys := func() ([]byte, []byte) { - pubkey, seckey := GenerateKeyPair() + pubkey, seckey := generateKeyPair() return pubkey, seckey } signAndRecoverWithRandomMessages(t, keys) @@ -129,32 +158,20 @@ func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte) } func TestRecoveryOfRandomSignature(t *testing.T) { - pubkey1, seckey := GenerateKeyPair() + pubkey1, _ := generateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) - sig, err := Sign(msg, seckey) - if err != nil { - t.Errorf("signature error: %s", err) - } for i := 0; i < TestCount; i++ { - sig = randSig() - pubkey2, _ := RecoverPubkey(msg, sig) // recovery can sometimes work, but if so should always give wrong pubkey + pubkey2, _ := RecoverPubkey(msg, randSig()) if bytes.Equal(pubkey1, pubkey2) { t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2) } } } -func randSig() []byte { - sig := randentropy.GetEntropyCSPRNG(65) - sig[32] &= 0x70 - sig[64] %= 4 - return sig -} - func TestRandomMessagesAgainstValidSig(t *testing.T) { - pubkey1, seckey := GenerateKeyPair() + pubkey1, seckey := generateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) @@ -168,14 +185,6 @@ func TestRandomMessagesAgainstValidSig(t *testing.T) { } } -func TestZeroPrivkey(t *testing.T) { - zeroedBytes := make([]byte, 32) - err := VerifySeckeyValidity(zeroedBytes) - if err == nil { - t.Errorf("zeroed bytes should have returned error") - } -} - // Useful when the underlying libsecp256k1 API changes to quickly // check only recover function without use of signature function func TestRecoverSanity(t *testing.T) { @@ -191,47 +200,23 @@ func TestRecoverSanity(t *testing.T) { } } -// tests for malleability -// highest bit of signature ECDSA s value must be 0, in the 33th byte -func compactSigCheck(t *testing.T, sig []byte) { - var b int = int(sig[32]) - if b < 0 { - t.Errorf("highest bit is negative: %d", b) - } - if ((b >> 7) == 1) != ((b & 0x80) == 0x80) { - t.Errorf("highest bit: %d bit >> 7: %d", b, b>>7) - } - if (b & 0x80) == 0x80 { - t.Errorf("highest bit: %d bit & 0x80: %d", b, b&0x80) - } -} - -// godep go test -v -run=XXX -bench=BenchmarkSign -// add -benchtime=10s to benchmark longer for more accurate average - -// to avoid compiler optimizing the benchmarked function call -var err error - func BenchmarkSign(b *testing.B) { + _, seckey := generateKeyPair() + msg := randentropy.GetEntropyCSPRNG(32) + b.ResetTimer() + for i := 0; i < b.N; i++ { - _, seckey := GenerateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) - b.StartTimer() - _, e := Sign(msg, seckey) - err = e - b.StopTimer() + Sign(msg, seckey) } } -//godep go test -v -run=XXX -bench=BenchmarkECRec func BenchmarkRecover(b *testing.B) { + msg := randentropy.GetEntropyCSPRNG(32) + _, seckey := generateKeyPair() + sig, _ := Sign(msg, seckey) + b.ResetTimer() + for i := 0; i < b.N; i++ { - _, seckey := GenerateKeyPair() - msg := randentropy.GetEntropyCSPRNG(32) - sig, _ := Sign(msg, seckey) - b.StartTimer() - _, e := RecoverPubkey(msg, sig) - err = e - b.StopTimer() + RecoverPubkey(msg, sig) } } diff --git a/crypto/sha3/sha3_test.go b/crypto/sha3/sha3_test.go index caf72f279f..c433761a8a 100644 --- a/crypto/sha3/sha3_test.go +++ b/crypto/sha3/sha3_test.go @@ -201,7 +201,7 @@ func TestSqueezing(t *testing.T) { d1 := newShakeHash() d1.Write([]byte(testString)) var multiple []byte - for _ = range ref { + for range ref { one := make([]byte, 1) d1.Read(one) multiple = append(multiple, one...) diff --git a/errs/errors.go b/errs/errors.go index d9ee8faeef..ab0c892cd4 100644 --- a/errs/errors.go +++ b/errs/errors.go @@ -19,7 +19,6 @@ package errs import ( "fmt" - "github.com/ubiq/go-ubiq/logger" "github.com/ubiq/go-ubiq/logger/glog" ) @@ -32,15 +31,10 @@ Fields: Package: name of the package/component - - Level: - a function mapping error code to logger.LogLevel (severity) - if not given, errors default to logger.InfoLevel */ type Errors struct { Errors map[int]string Package string - Level func(code int) logger.LogLevel } /* @@ -58,7 +52,6 @@ type Error struct { Code int Name string Package string - level logger.LogLevel message string format string params []interface{} @@ -69,15 +62,10 @@ func (self *Errors) New(code int, format string, params ...interface{}) *Error { if !ok { panic("invalid error code") } - level := logger.InfoLevel - if self.Level != nil { - level = self.Level(code) - } return &Error{ Code: code, Name: name, Package: self.Package, - level: level, format: format, params: params, } @@ -98,13 +86,3 @@ func (self Error) Log(v glog.Verbose) { v.Infoln(self) } } - -/* -err.Fatal() is true if err's severity level is 0 or 1 (logger.ErrorLevel or logger.Silence) -*/ -func (self *Error) Fatal() (fatal bool) { - if self.level < logger.WarnLevel { - fatal = true - } - return -} diff --git a/errs/errors_test.go b/errs/errors_test.go index 2428590ed8..5a2ffbec32 100644 --- a/errs/errors_test.go +++ b/errs/errors_test.go @@ -19,8 +19,6 @@ package errs import ( "fmt" "testing" - - "github.com/ubiq/go-ubiq/logger" ) func testErrors() *Errors { @@ -30,14 +28,6 @@ func testErrors() *Errors { 0: "zero", 1: "one", }, - Level: func(i int) (l logger.LogLevel) { - if i == 0 { - l = logger.ErrorLevel - } else { - l = logger.WarnLevel - } - return - }, } } @@ -49,14 +39,3 @@ func TestErrorMessage(t *testing.T) { t.Errorf("error message incorrect. expected %v, got %v", exp, message) } } - -func TestErrorSeverity(t *testing.T) { - err0 := testErrors().New(0, "zero detail") - if !err0.Fatal() { - t.Errorf("error should be fatal") - } - err1 := testErrors().New(1, "one detail") - if err1.Fatal() { - t.Errorf("error should not be fatal") - } -} diff --git a/eth/api.go b/eth/api.go index b4e8fbb049..e2847405c5 100644 --- a/eth/api.go +++ b/eth/api.go @@ -18,6 +18,7 @@ package eth import ( "bytes" + "compress/gzip" "errors" "fmt" "io" @@ -25,10 +26,12 @@ import ( "math/big" "os" "runtime" + "strings" "time" "github.com/ethereum/ethash" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/core" "github.com/ubiq/go-ubiq/core/state" "github.com/ubiq/go-ubiq/core/types" @@ -67,8 +70,8 @@ func (s *PublicEthereumAPI) Coinbase() (common.Address, error) { } // Hashrate returns the POW hashrate -func (s *PublicEthereumAPI) Hashrate() *rpc.HexNumber { - return rpc.NewHexNumber(s.e.Miner().HashRate()) +func (s *PublicEthereumAPI) Hashrate() hexutil.Uint64 { + return hexutil.Uint64(s.e.Miner().HashRate()) } // PublicMinerAPI provides an API to control the miner. @@ -80,7 +83,7 @@ type PublicMinerAPI struct { // NewPublicMinerAPI create a new PublicMinerAPI instance. func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI { - agent := miner.NewRemoteAgent() + agent := miner.NewRemoteAgent(e.Pow()) e.Miner().Register(agent) return &PublicMinerAPI{e, agent} @@ -93,8 +96,8 @@ func (s *PublicMinerAPI) Mining() bool { // SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was // accepted. Note, this is not an indication if the provided work was valid! -func (s *PublicMinerAPI) SubmitWork(nonce rpc.HexNumber, solution, digest common.Hash) bool { - return s.agent.SubmitWork(nonce.Uint64(), digest, solution) +func (s *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest common.Hash) bool { + return s.agent.SubmitWork(nonce, digest, solution) } // GetWork returns a work package for external miner. The work package consists of 3 strings @@ -117,8 +120,8 @@ func (s *PublicMinerAPI) GetWork() (work [3]string, err error) { // SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined // hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which // must be unique between nodes. -func (s *PublicMinerAPI) SubmitHashrate(hashrate rpc.HexNumber, id common.Hash) bool { - s.agent.SubmitHashrate(id, hashrate.Uint64()) +func (s *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool { + s.agent.SubmitHashrate(id, uint64(hashrate)) return true } @@ -135,18 +138,15 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { // Start the miner with the given number of threads. If threads is nil the number of // workers started is equal to the number of logical CPU's that are usable by this process. -func (s *PrivateMinerAPI) Start(threads *rpc.HexNumber) (bool, error) { +func (s *PrivateMinerAPI) Start(threads *int) (bool, error) { s.e.StartAutoDAG() - + var err error if threads == nil { - threads = rpc.NewHexNumber(runtime.NumCPU()) + err = s.e.StartMining(runtime.NumCPU()) + } else { + err = s.e.StartMining(*threads) } - - err := s.e.StartMining(threads.Int()) - if err == nil { - return true, nil - } - return false, err + return err == nil, err } // Stop the miner @@ -164,8 +164,8 @@ func (s *PrivateMinerAPI) SetExtra(extra string) (bool, error) { } // SetGasPrice sets the minimum accepted gas price for the miner. -func (s *PrivateMinerAPI) SetGasPrice(gasPrice rpc.HexNumber) bool { - s.e.Miner().SetGasPrice(gasPrice.BigInt()) +func (s *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool { + s.e.Miner().SetGasPrice((*big.Int)(&gasPrice)) return true } @@ -217,8 +217,14 @@ func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) { } defer out.Close() + var writer io.Writer = out + if strings.HasSuffix(file, ".gz") { + writer = gzip.NewWriter(writer) + defer writer.(*gzip.Writer).Close() + } + // Export the blockchain - if err := api.eth.BlockChain().Export(out); err != nil { + if err := api.eth.BlockChain().Export(writer); err != nil { return false, err } return true, nil @@ -243,8 +249,15 @@ func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { } defer in.Close() + var reader io.Reader = in + if strings.HasSuffix(file, ".gz") { + if reader, err = gzip.NewReader(reader); err != nil { + return false, err + } + } + // Run actual the import in pre-configured batches - stream := rlp.NewStream(in, 0) + stream := rlp.NewStream(reader, 0) blocks, index := make([]*types.Block, 0, 2500), 0 for batch := 0; ; batch++ { @@ -422,7 +435,7 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, logConfig *vm.LogConf return true, structLogger.StructLogs(), nil } -// callmsg is the message type used for call transations. +// callmsg is the message type used for call transitions. type callmsg struct { addr common.Address to *common.Address @@ -515,9 +528,11 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common. if err != nil { return nil, fmt.Errorf("sender retrieval failed: %v", err) } + context := core.NewEVMContext(msg, block.Header(), api.eth.BlockChain()) + // Mutate the state if we haven't reached the tracing transaction yet if uint64(idx) < txIndex { - vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{}) + vmenv := vm.NewEVM(context, stateDb, api.config, vm.Config{}) _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { return nil, fmt.Errorf("mutation failed: %v", err) @@ -525,8 +540,8 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common. stateDb.DeleteSuicides() continue } - // Otherwise trace the transaction and return - vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{Debug: true, Tracer: tracer}) + + vmenv := vm.NewEVM(context, stateDb, api.config, vm.Config{Debug: true, Tracer: tracer}) ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { return nil, fmt.Errorf("tracing failed: %v", err) diff --git a/eth/api_backend.go b/eth/api_backend.go index 22d40cd13d..89e9ce3019 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -31,7 +31,7 @@ import ( "github.com/ubiq/go-ubiq/event" "github.com/ubiq/go-ubiq/internal/ethapi" "github.com/ubiq/go-ubiq/params" - rpc "github.com/ubiq/go-ubiq/rpc" + "github.com/ubiq/go-ubiq/rpc" "golang.org/x/net/context" ) @@ -106,12 +106,14 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { return b.eth.blockchain.GetTdByHash(blockHash) } -func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) { +func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) { statedb := state.(EthApiState).state from := statedb.GetOrNewStateObject(msg.From()) from.SetBalance(common.MaxBig) vmError := func() error { return nil } - return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}), vmError, nil + + context := core.NewEVMContext(msg, header, b.eth.BlockChain()) + return vm.NewEVM(context, statedb, b.eth.chainConfig, vm.Config{}), vmError, nil } func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { @@ -129,15 +131,20 @@ func (b *EthApiBackend) RemoveTx(txHash common.Hash) { b.eth.txPool.Remove(txHash) } -func (b *EthApiBackend) GetPoolTransactions() types.Transactions { +func (b *EthApiBackend) GetPoolTransactions() (types.Transactions, error) { b.eth.txMu.Lock() defer b.eth.txMu.Unlock() + pending, err := b.eth.txPool.Pending() + if err != nil { + return nil, err + } + var txs types.Transactions - for _, batch := range b.eth.txPool.Pending() { + for _, batch := range pending { txs = append(txs, batch...) } - return txs + return txs, nil } func (b *EthApiBackend) GetPoolTransaction(hash common.Hash) *types.Transaction { diff --git a/eth/backend.go b/eth/backend.go index ec545c4f08..2b0d42cb00 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -45,6 +45,7 @@ import ( "github.com/ubiq/go-ubiq/node" "github.com/ubiq/go-ubiq/p2p" "github.com/ubiq/go-ubiq/params" + "github.com/ubiq/go-ubiq/pow" "github.com/ubiq/go-ubiq/rpc" ) @@ -79,6 +80,7 @@ type Config struct { NatSpec bool DocRoot string AutoDAG bool + PowFake bool PowTest bool PowShared bool ExtraData []byte @@ -104,6 +106,7 @@ type Config struct { type LesServer interface { Start(srvr *p2p.Server) + Synced() Stop() Protocols() []p2p.Protocol } @@ -124,7 +127,7 @@ type Ethereum struct { chainDb ethdb.Database // Block chain database eventMux *event.TypeMux - pow *ethash.Ethash + pow pow.PoW accountManager *accounts.Manager ApiBackend *EthApiBackend @@ -138,13 +141,13 @@ type Ethereum struct { solcPath string NatSpec bool - PowTest bool netVersionId int netRPCService *ethapi.PublicNetAPI } func (s *Ethereum) AddLesServer(ls LesServer) { s.lesServer = ls + s.protocolManager.lesServer = ls } // New creates a new Ethereum object (including the @@ -172,7 +175,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { stopDbUpgrade: stopDbUpgrade, netVersionId: config.NetworkId, NatSpec: config.NatSpec, - PowTest: config.PowTest, etherbase: config.Etherbase, MinerThreads: config.MinerThreads, AutoDAG: config.AutoDAG, @@ -291,15 +293,17 @@ func SetupGenesisBlock(chainDb *ethdb.Database, config *Config) error { } // CreatePoW creates the required type of PoW instance for an Ethereum service -func CreatePoW(config *Config) (*ethash.Ethash, error) { +func CreatePoW(config *Config) (pow.PoW, error) { switch { + case config.PowFake: + glog.V(logger.Info).Infof("ethash used in fake mode") + return pow.PoW(core.FakePow{}), nil case config.PowTest: glog.V(logger.Info).Infof("ethash used in test mode") return ethash.NewForTesting() case config.PowShared: glog.V(logger.Info).Infof("ethash used in shared mode") return ethash.NewShared(), nil - default: return ethash.New(), nil } @@ -397,7 +401,7 @@ func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } -func (s *Ethereum) Pow() *ethash.Ethash { return s.pow } +func (s *Ethereum) Pow() pow.PoW { return s.pow } func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } func (s *Ethereum) IsListening() bool { return true } // Always listening func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } diff --git a/eth/backend_test.go b/eth/backend_test.go index 29d5efd68a..0eb82ef3fa 100644 --- a/eth/backend_test.go +++ b/eth/backend_test.go @@ -23,7 +23,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core" "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/params" ) @@ -38,12 +37,12 @@ func TestMipmapUpgrade(t *testing.T) { switch i { case 1: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{&vm.Log{Address: addr}} + receipt.Logs = []*types.Log{{Address: addr}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 2: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{&vm.Log{Address: addr}} + receipt.Logs = []*types.Log{{Address: addr}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} } diff --git a/eth/bind.go b/eth/bind.go index 010862fa33..52b4b9f86a 100644 --- a/eth/bind.go +++ b/eth/bind.go @@ -21,6 +21,7 @@ import ( "github.com/ubiq/go-ubiq" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/internal/ethapi" "github.com/ubiq/go-ubiq/rlp" @@ -83,16 +84,16 @@ func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs { args := ethapi.CallArgs{ To: msg.To, From: msg.From, - Data: common.ToHex(msg.Data), + Data: msg.Data, } if msg.Gas != nil { - args.Gas = *rpc.NewHexNumber(msg.Gas) + args.Gas = hexutil.Big(*msg.Gas) } if msg.GasPrice != nil { - args.GasPrice = *rpc.NewHexNumber(msg.GasPrice) + args.GasPrice = hexutil.Big(*msg.GasPrice) } if msg.Value != nil { - args.Value = *rpc.NewHexNumber(msg.Value) + args.Value = hexutil.Big(*msg.Value) } return args } @@ -106,9 +107,12 @@ func toBlockNumber(num *big.Int) rpc.BlockNumber { // PendingAccountNonce implements bind.ContractTransactor retrieving the current // pending nonce associated with an account. -func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { +func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (nonce uint64, err error) { out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber) - return out.Uint64(), err + if out != nil { + nonce = uint64(*out) + } + return nonce, err } // SuggestGasPrice implements bind.ContractTransactor retrieving the currently @@ -124,13 +128,13 @@ func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) // should provide a basis for setting a reasonable default. func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) { out, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg)) - return out.BigInt(), err + return out.ToInt(), err } // SendTransaction implements bind.ContractTransactor injects the transaction // into the pending pool for execution. func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { raw, _ := rlp.EncodeToBytes(tx) - _, err := b.txapi.SendRawTransaction(ctx, common.ToHex(raw)) + _, err := b.txapi.SendRawTransaction(ctx, raw) return err } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 3db459ab20..9334c70f93 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1005,7 +1005,7 @@ func (d *Downloader) fetchNodeData() error { // - fetchHook: tester callback to notify of new tasks being initiated (allows testing the scheduling logic) // - fetch: network callback to actually send a particular download request to a physical remote peer // - cancel: task callback to abort an in-flight download request and allow rescheduling it (in case of lost peer) -// - capacity: network callback to retreive the estimated type-specific bandwidth capacity of a peer (traffic shaping) +// - capacity: network callback to retrieve the estimated type-specific bandwidth capacity of a peer (traffic shaping) // - idle: network callback to retrieve the currently (type specific) idle peers that can be assigned tasks // - setIdle: network callback to set a peer back to idle and update its estimated capacity (traffic shaping) // - kind: textual label of the type being downloaded to display in log mesages diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 95f037a39f..d404580563 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -119,7 +119,7 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren // If the block number is multiple of 3, send a bonus transaction to the miner if parent == dl.genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) if err != nil { panic(err) } @@ -650,7 +650,7 @@ func assertOwnForkedChain(t *testing.T, tester *downloadTester, common int, leng } // Verify the state trie too for fast syncs if tester.downloader.mode == FastSync { - index := 0 + var index int if pivot := int(tester.downloader.queue.fastSyncPivot); pivot < common { index = pivot } else { diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go index b062aef8b7..0ef47dbdf1 100644 --- a/eth/downloader/peer.go +++ b/eth/downloader/peer.go @@ -205,7 +205,7 @@ func (p *peer) FetchNodeData(request *fetchRequest) error { // Convert the hash set to a retrievable slice hashes := make([]common.Hash, 0, len(request.Hashes)) - for hash, _ := range request.Hashes { + for hash := range request.Hashes { hashes = append(hashes, hash) } go p.getNodeData(hashes) @@ -314,7 +314,7 @@ func (p *peer) MarkLacking(hash common.Hash) { defer p.lock.Unlock() for len(p.lacking) >= maxLackingHashes { - for drop, _ := range p.lacking { + for drop := range p.lacking { delete(p.lacking, drop) break } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 930f6cee14..7b8731ac61 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -844,7 +844,7 @@ func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest, } } // Remove the expired requests from the pending pool - for id, _ := range expiries { + for id := range expiries { delete(pendPool, id) } return expiries @@ -1063,7 +1063,7 @@ func (q *queue) DeliverNodeData(id string, data [][]byte, callback func(int, boo // If no data was retrieved, mark their hashes as unavailable for the origin peer if len(data) == 0 { - for hash, _ := range request.Hashes { + for hash := range request.Hashes { request.Peer.MarkLacking(hash) } } @@ -1123,15 +1123,20 @@ func (q *queue) deliverNodeData(results []trie.SyncResult, callback func(int, bo callback(i, progressed, errNoFetchesPending) return } - if prog, _, err := q.stateScheduler.Process([]trie.SyncResult{result}); err != nil { - // Processing a state result failed, bail out + + batch := q.stateDatabase.NewBatch() + prog, _, err := q.stateScheduler.Process([]trie.SyncResult{result}, batch) + if err != nil { q.stateSchedLock.Unlock() callback(i, progressed, err) - return - } else if prog { - progressed = true } + if err = batch.Write(); err != nil { + q.stateSchedLock.Unlock() + callback(i, progressed, err) + } + // Item processing succeeded, release the lock (temporarily) + progressed = progressed || prog q.stateSchedLock.Unlock() } callback(len(results), progressed, nil) diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 9b81f57265..a101c170d0 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -51,7 +51,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) if err != nil { panic(err) } diff --git a/eth/filters/api.go b/eth/filters/api.go index b17357b461..7d9eee6113 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -45,7 +45,7 @@ type filter struct { deadline *time.Timer // filter is inactiv when deadline triggers hashes []common.Hash crit FilterCriteria - logs []Log + logs []*types.Log s *Subscription // associated subscription in event system } @@ -241,7 +241,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc var ( rpcSub = notifier.CreateSubscription() - matchedLogs = make(chan []Log) + matchedLogs = make(chan []*types.Log) ) logsSub, err := api.events.SubscribeLogs(crit, matchedLogs) @@ -290,16 +290,16 @@ type FilterCriteria struct { // // In case "fromBlock" > "toBlock" an error is returned. // -// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter +// https://github.com/ubiq/wiki/wiki/JSON-RPC#eth_newfilter func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { - logs := make(chan []Log) + logs := make(chan []*types.Log) logsSub, err := api.events.SubscribeLogs(crit, logs) if err != nil { return rpc.ID(""), err } api.filtersMu.Lock() - api.filters[logsSub.ID] = &filter{typ: LogsSubscription, crit: crit, deadline: time.NewTimer(deadline), logs: make([]Log, 0), s: logsSub} + api.filters[logsSub.ID] = &filter{typ: LogsSubscription, crit: crit, deadline: time.NewTimer(deadline), logs: make([]*types.Log, 0), s: logsSub} api.filtersMu.Unlock() go func() { @@ -326,7 +326,7 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) { // GetLogs returns logs matching the given argument that are stored within the state. // // https://github.com/ubiq/wiki/wiki/JSON-RPC#eth_getlogs -func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]Log, error) { +func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { if crit.FromBlock == nil { crit.FromBlock = big.NewInt(rpc.LatestBlockNumber.Int64()) } @@ -365,7 +365,7 @@ func (api *PublicFilterAPI) UninstallFilter(id rpc.ID) bool { // If the filter could not be found an empty array of logs is returned. // // https://github.com/ubiq/wiki/wiki/JSON-RPC#eth_getfilterlogs -func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]Log, error) { +func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Log, error) { api.filtersMu.Lock() f, found := api.filters[id] api.filtersMu.Unlock() @@ -388,7 +388,7 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]Log filter.SetAddresses(f.crit.Addresses) filter.SetTopics(f.crit.Topics) - logs, err:= filter.Find(ctx) + logs, err := filter.Find(ctx) if err != nil { return nil, err } @@ -440,9 +440,9 @@ func returnHashes(hashes []common.Hash) []common.Hash { // returnLogs is a helper that will return an empty log array in case the given logs array is nil, // otherwise the given logs array is returned. -func returnLogs(logs []Log) []Log { +func returnLogs(logs []*types.Log) []*types.Log { if logs == nil { - return []Log{} + return []*types.Log{} } return logs } @@ -505,7 +505,7 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error { switch topic := t.(type) { case nil: // ignore topic when matching logs - args.Topics[i] = []common.Hash{common.Hash{}} + args.Topics[i] = []common.Hash{{}} case string: // match specific topic diff --git a/eth/filters/filter.go b/eth/filters/filter.go index b72fba51c5..6d49b68490 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -37,7 +37,7 @@ type Backend interface { GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) } -// Filter can be used to retrieve and filter logs +// Filter can be used to retrieve and filter logs. type Filter struct { backend Backend useMipMap bool @@ -52,6 +52,8 @@ type Filter struct { // New creates a new filter which uses a bloom filter on blocks to figure out whether // a particular block is interesting or not. +// MipMaps allow past blocks to be searched much more efficiently, but are not available +// to light clients. func New(backend Backend, useMipMap bool) *Filter { return &Filter{ backend: backend, @@ -83,8 +85,11 @@ func (f *Filter) SetTopics(topics [][]common.Hash) { f.topics = topics } -// Run filters logs with the current parameters set -func (f *Filter) Find(ctx context.Context) ([]Log, error) { +// FindOnce searches the blockchain for matching log entries, returning +// all matching entries from the first block that contains matches, +// updating the start point of the filter accordingly. If no results are +// found, a nil slice is returned. +func (f *Filter) FindOnce(ctx context.Context) ([]*types.Log, error) { head, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) if head == nil { return nil, nil @@ -104,47 +109,69 @@ func (f *Filter) Find(ctx context.Context) ([]Log, error) { // uses the mipmap bloom filters to check for fast inclusion and uses // higher range probability in order to ensure at least a false positive if !f.useMipMap || len(f.addresses) == 0 { - return f.getLogs(ctx, beginBlockNo, endBlockNo) + logs, blockNumber, err := f.getLogs(ctx, beginBlockNo, endBlockNo) + f.begin = int64(blockNumber + 1) + return logs, err } - return f.mipFind(beginBlockNo, endBlockNo, 0), nil + + logs, blockNumber := f.mipFind(beginBlockNo, endBlockNo, 0) + f.begin = int64(blockNumber + 1) + return logs, nil } -func (f *Filter) mipFind(start, end uint64, depth int) (logs []Log) { +// Run filters logs with the current parameters set +func (f *Filter) Find(ctx context.Context) (logs []*types.Log, err error) { + for { + newLogs, err := f.FindOnce(ctx) + if len(newLogs) == 0 || err != nil { + return logs, err + } + logs = append(logs, newLogs...) + } +} + +func (f *Filter) mipFind(start, end uint64, depth int) (logs []*types.Log, blockNumber uint64) { level := core.MIPMapLevels[depth] // normalise numerator so we can work in level specific batches and // work with the proper range checks for num := start / level * level; num <= end; num += level { // find addresses in bloom filters bloom := core.GetMipmapBloom(f.db, num, level) + // Don't bother checking the first time through the loop - we're probably picking + // up where a previous run left off. + first := true for _, addr := range f.addresses { - if bloom.TestBytes(addr[:]) { + if first || bloom.TestBytes(addr[:]) { + first = false // range check normalised values and make sure that // we're resolving the correct range instead of the // normalised values. start := uint64(math.Max(float64(num), float64(start))) end := uint64(math.Min(float64(num+level-1), float64(end))) if depth+1 == len(core.MIPMapLevels) { - l, _ := f.getLogs(context.Background(), start, end) - logs = append(logs, l...) + l, blockNumber, _ := f.getLogs(context.Background(), start, end) + if len(l) > 0 { + return l, blockNumber + } } else { - logs = append(logs, f.mipFind(start, end, depth+1)...) + l, blockNumber := f.mipFind(start, end, depth+1) + if len(l) > 0 { + return l, blockNumber + } } - // break so we don't check the same range for each - // possible address. Checks on multiple addresses - // are handled further down the stack. - break } } } - return logs + return nil, end } -func (f *Filter) getLogs(ctx context.Context, start, end uint64) (logs []Log, err error) { +func (f *Filter) getLogs(ctx context.Context, start, end uint64) (logs []*types.Log, blockNumber uint64, err error) { for i := start; i <= end; i++ { - header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(i)) + blockNumber := rpc.BlockNumber(i) + header, err := f.backend.HeaderByNumber(ctx, blockNumber) if header == nil || err != nil { - return logs, err + return logs, end, err } // Use bloom filtering to see if this block is interesting given the @@ -153,21 +180,20 @@ func (f *Filter) getLogs(ctx context.Context, start, end uint64) (logs []Log, er // Get the logs of the block receipts, err := f.backend.GetReceipts(ctx, header.Hash()) if err != nil { - return nil, err + return nil, end, err } - var unfiltered []Log + var unfiltered []*types.Log for _, receipt := range receipts { - rl := make([]Log, len(receipt.Logs)) - for i, l := range receipt.Logs { - rl[i] = Log{l, false} - } - unfiltered = append(unfiltered, rl...) + unfiltered = append(unfiltered, ([]*types.Log)(receipt.Logs)...) + } + logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics) + if len(logs) > 0 { + return logs, uint64(blockNumber), nil } - logs = append(logs, filterLogs(unfiltered, nil, nil, f.addresses, f.topics)...) } } - return logs, nil + return logs, end, nil } func includes(addresses []common.Address, a common.Address) bool { @@ -180,15 +206,15 @@ func includes(addresses []common.Address, a common.Address) bool { return false } -func filterLogs(logs []Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []Log { - var ret []Log - // Filter the logs for interesting stuff +// filterLogs creates a slice of logs matching the given criteria. +func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*types.Log { + var ret []*types.Log Logs: for _, log := range logs { - if fromBlock != nil && fromBlock.Int64() >= 0 && uint64(fromBlock.Int64()) > log.BlockNumber { + if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber { continue } - if toBlock != nil && toBlock.Int64() >= 0 && uint64(toBlock.Int64()) < log.BlockNumber { + if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber { continue } diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go index 851495cfd0..a15c509253 100644 --- a/eth/filters/filter_system.go +++ b/eth/filters/filter_system.go @@ -19,7 +19,6 @@ package filters import ( - "encoding/json" "errors" "fmt" "sync" @@ -28,7 +27,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core" "github.com/ubiq/go-ubiq/core/types" - "github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/event" "github.com/ubiq/go-ubiq/rpc" "golang.org/x/net/context" @@ -39,7 +37,7 @@ import ( type Type byte const ( - // UnknownSubscription indicates an unkown subscription type + // UnknownSubscription indicates an unknown subscription type UnknownSubscription Type = iota // LogsSubscription queries for new or removed (chain reorg) logs LogsSubscription @@ -60,42 +58,12 @@ var ( ErrInvalidSubscriptionID = errors.New("invalid id") ) -// Log is a helper that can hold additional information about vm.Log -// necessary for the RPC interface. -type Log struct { - *vm.Log - Removed bool `json:"removed"` -} - -// MarshalJSON returns *l as the JSON encoding of l. -func (l *Log) MarshalJSON() ([]byte, error) { - fields := map[string]interface{}{ - "address": l.Address, - "data": fmt.Sprintf("0x%x", l.Data), - "blockNumber": nil, - "logIndex": fmt.Sprintf("%#x", l.Index), - "blockHash": nil, - "transactionHash": l.TxHash, - "transactionIndex": fmt.Sprintf("%#x", l.TxIndex), - "topics": l.Topics, - "removed": l.Removed, - } - - // mined logs - if l.BlockHash != (common.Hash{}) { - fields["blockNumber"] = fmt.Sprintf("%#x", l.BlockNumber) - fields["blockHash"] = l.BlockHash - } - - return json.Marshal(fields) -} - type subscription struct { id rpc.ID typ Type created time.Time logsCrit FilterCriteria - logs chan []Log + logs chan []*types.Log hashes chan common.Hash headers chan *types.Header installed chan struct{} // closed when the filter is installed @@ -182,7 +150,7 @@ func (es *EventSystem) subscribe(sub *subscription) *Subscription { // SubscribeLogs creates a subscription that will write all logs matching the // given criteria to the given logs channel. Default value for the from and to // block is "latest". If the fromBlock > toBlock an error is returned. -func (es *EventSystem) SubscribeLogs(crit FilterCriteria, logs chan []Log) (*Subscription, error) { +func (es *EventSystem) SubscribeLogs(crit FilterCriteria, logs chan []*types.Log) (*Subscription, error) { var from, to rpc.BlockNumber if crit.FromBlock == nil { from = rpc.LatestBlockNumber @@ -220,7 +188,7 @@ func (es *EventSystem) SubscribeLogs(crit FilterCriteria, logs chan []Log) (*Sub // subscribeMinedPendingLogs creates a subscription that returned mined and // pending logs that match the given criteria. -func (es *EventSystem) subscribeMinedPendingLogs(crit FilterCriteria, logs chan []Log) *Subscription { +func (es *EventSystem) subscribeMinedPendingLogs(crit FilterCriteria, logs chan []*types.Log) *Subscription { sub := &subscription{ id: rpc.NewID(), typ: MinedAndPendingLogsSubscription, @@ -238,7 +206,7 @@ func (es *EventSystem) subscribeMinedPendingLogs(crit FilterCriteria, logs chan // subscribeLogs creates a subscription that will write all logs matching the // given criteria to the given logs channel. -func (es *EventSystem) subscribeLogs(crit FilterCriteria, logs chan []Log) *Subscription { +func (es *EventSystem) subscribeLogs(crit FilterCriteria, logs chan []*types.Log) *Subscription { sub := &subscription{ id: rpc.NewID(), typ: LogsSubscription, @@ -256,7 +224,7 @@ func (es *EventSystem) subscribeLogs(crit FilterCriteria, logs chan []Log) *Subs // subscribePendingLogs creates a subscription that writes transaction hashes for // transactions that enter the transaction pool. -func (es *EventSystem) subscribePendingLogs(crit FilterCriteria, logs chan []Log) *Subscription { +func (es *EventSystem) subscribePendingLogs(crit FilterCriteria, logs chan []*types.Log) *Subscription { sub := &subscription{ id: rpc.NewID(), typ: PendingLogsSubscription, @@ -279,7 +247,7 @@ func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscripti id: rpc.NewID(), typ: BlocksSubscription, created: time.Now(), - logs: make(chan []Log), + logs: make(chan []*types.Log), hashes: make(chan common.Hash), headers: headers, installed: make(chan struct{}), @@ -296,7 +264,7 @@ func (es *EventSystem) SubscribePendingTxEvents(hashes chan common.Hash) *Subscr id: rpc.NewID(), typ: PendingTransactionsSubscription, created: time.Now(), - logs: make(chan []Log), + logs: make(chan []*types.Log), hashes: hashes, headers: make(chan *types.Header), installed: make(chan struct{}), @@ -315,11 +283,11 @@ func (es *EventSystem) broadcast(filters filterIndex, ev *event.Event) { } switch e := ev.Data.(type) { - case vm.Logs: + case []*types.Log: if len(e) > 0 { for _, f := range filters[LogsSubscription] { if ev.Time.After(f.created) { - if matchedLogs := filterLogs(convertLogs(e, false), f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 { + if matchedLogs := filterLogs(e, f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 { f.logs <- matchedLogs } } @@ -328,7 +296,7 @@ func (es *EventSystem) broadcast(filters filterIndex, ev *event.Event) { case core.RemovedLogsEvent: for _, f := range filters[LogsSubscription] { if ev.Time.After(f.created) { - if matchedLogs := filterLogs(convertLogs(e.Logs, true), f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 { + if matchedLogs := filterLogs(e.Logs, f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 { f.logs <- matchedLogs } } @@ -336,7 +304,7 @@ func (es *EventSystem) broadcast(filters filterIndex, ev *event.Event) { case core.PendingLogsEvent: for _, f := range filters[PendingLogsSubscription] { if ev.Time.After(f.created) { - if matchedLogs := filterLogs(convertLogs(e.Logs, false), nil, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 { + if matchedLogs := filterLogs(e.Logs, nil, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 { f.logs <- matchedLogs } } @@ -401,25 +369,22 @@ func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func } // filter logs of a single header in light client mode -func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []Log { - //fmt.Println("lightFilterLogs", header.Number.Uint64(), remove) +func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []*types.Log { if bloomFilter(header.Bloom, addresses, topics) { - //fmt.Println("bloom match") // Get the logs of the block ctx, _ := context.WithTimeout(context.Background(), time.Second*5) receipts, err := es.backend.GetReceipts(ctx, header.Hash()) if err != nil { return nil } - var unfiltered []Log + var unfiltered []*types.Log for _, receipt := range receipts { - rl := make([]Log, len(receipt.Logs)) - for i, l := range receipt.Logs { - rl[i] = Log{l, remove} + for _, log := range receipt.Logs { + logcopy := *log + logcopy.Removed = remove + unfiltered = append(unfiltered, &logcopy) } - unfiltered = append(unfiltered, rl...) } - logs := filterLogs(unfiltered, nil, nil, addresses, topics) return logs } @@ -430,7 +395,7 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common. func (es *EventSystem) eventLoop() { var ( index = make(filterIndex) - sub = es.mux.Subscribe(core.PendingLogsEvent{}, core.RemovedLogsEvent{}, vm.Logs{}, core.TxPreEvent{}, core.ChainEvent{}) + sub = es.mux.Subscribe(core.PendingLogsEvent{}, core.RemovedLogsEvent{}, []*types.Log{}, core.TxPreEvent{}, core.ChainEvent{}) ) for i := UnknownSubscription; i < LastIndexSubscription; i++ { @@ -465,13 +430,3 @@ func (es *EventSystem) eventLoop() { } } } - -// convertLogs is a helper utility that converts vm.Logs to []filter.Log. -func convertLogs(in vm.Logs, removed bool) []Log { - - logs := make([]Log, len(in)) - for i, l := range in { - logs[i] = Log{l, removed} - } - return logs -} diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index bd16a5237e..fd1460434b 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -27,7 +27,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core" "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/event" "github.com/ubiq/go-ubiq/params" @@ -74,10 +73,10 @@ func TestBlockSubscription(t *testing.T) { t.Parallel() var ( - mux = new(event.TypeMux) - db, _ = ethdb.NewMemDatabase() + mux = new(event.TypeMux) + db, _ = ethdb.NewMemDatabase() backend = &testBackend{mux, db} - api = NewPublicFilterAPI(backend, false) + api = NewPublicFilterAPI(backend, false) genesis = core.WriteGenesisBlockForTesting(db) chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {}) @@ -128,10 +127,10 @@ func TestPendingTxFilter(t *testing.T) { t.Parallel() var ( - mux = new(event.TypeMux) - db, _ = ethdb.NewMemDatabase() + mux = new(event.TypeMux) + db, _ = ethdb.NewMemDatabase() backend = &testBackend{mux, db} - api = NewPublicFilterAPI(backend, false) + api = NewPublicFilterAPI(backend, false) transactions = []*types.Transaction{ types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), @@ -178,10 +177,10 @@ func TestPendingTxFilter(t *testing.T) { // If not it must return an error. func TestLogFilterCreation(t *testing.T) { var ( - mux = new(event.TypeMux) - db, _ = ethdb.NewMemDatabase() + mux = new(event.TypeMux) + db, _ = ethdb.NewMemDatabase() backend = &testBackend{mux, db} - api = NewPublicFilterAPI(backend, false) + api = NewPublicFilterAPI(backend, false) testCases = []struct { crit FilterCriteria @@ -223,10 +222,10 @@ func TestInvalidLogFilterCreation(t *testing.T) { t.Parallel() var ( - mux = new(event.TypeMux) - db, _ = ethdb.NewMemDatabase() + mux = new(event.TypeMux) + db, _ = ethdb.NewMemDatabase() backend = &testBackend{mux, db} - api = NewPublicFilterAPI(backend, false) + api = NewPublicFilterAPI(backend, false) ) // different situations where log filter creation should fail. @@ -249,10 +248,10 @@ func TestLogFilter(t *testing.T) { t.Parallel() var ( - mux = new(event.TypeMux) - db, _ = ethdb.NewMemDatabase() + mux = new(event.TypeMux) + db, _ = ethdb.NewMemDatabase() backend = &testBackend{mux, db} - api = NewPublicFilterAPI(backend, false) + api = NewPublicFilterAPI(backend, false) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -263,34 +262,34 @@ func TestLogFilter(t *testing.T) { notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") // posted twice, once as vm.Logs and once as core.PendingLogsEvent - allLogs = vm.Logs{ - vm.NewLog(firstAddr, []common.Hash{}, []byte(""), 0), - vm.NewLog(firstAddr, []common.Hash{firstTopic}, []byte(""), 1), - vm.NewLog(secondAddr, []common.Hash{firstTopic}, []byte(""), 1), - vm.NewLog(thirdAddress, []common.Hash{secondTopic}, []byte(""), 2), - vm.NewLog(thirdAddress, []common.Hash{secondTopic}, []byte(""), 3), + allLogs = []*types.Log{ + {Address: firstAddr}, + {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, + {Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}, + {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 2}, + {Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}, } - expectedCase7 = vm.Logs{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} - expectedCase11 = vm.Logs{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} + expectedCase7 = []*types.Log{allLogs[3], allLogs[4], allLogs[0], allLogs[1], allLogs[2], allLogs[3], allLogs[4]} + expectedCase11 = []*types.Log{allLogs[1], allLogs[2], allLogs[1], allLogs[2]} testCases = []struct { crit FilterCriteria - expected vm.Logs + expected []*types.Log id rpc.ID }{ // match all 0: {FilterCriteria{}, allLogs, ""}, // match none due to no matching addresses - 1: {FilterCriteria{Addresses: []common.Address{common.Address{}, notUsedAddress}, Topics: [][]common.Hash{allLogs[0].Topics}}, vm.Logs{}, ""}, + 1: {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{allLogs[0].Topics}}, []*types.Log{}, ""}, // match logs based on addresses, ignore topics 2: {FilterCriteria{Addresses: []common.Address{firstAddr}}, allLogs[:2], ""}, // match none due to no matching topics (match with address) - 3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{[]common.Hash{notUsedTopic}}}, vm.Logs{}, ""}, + 3: {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, ""}, // match logs based on addresses and topics - 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, secondTopic}}}, allLogs[3:5], ""}, + 4: {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[3:5], ""}, // match logs based on multiple addresses and "or" topics - 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, secondTopic}}}, allLogs[2:5], ""}, + 5: {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, allLogs[2:5], ""}, // logs in the pending block 6: {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64())}, allLogs[:2], ""}, // mined logs with block num >= 2 or pending logs @@ -300,9 +299,9 @@ func TestLogFilter(t *testing.T) { // all "mined" logs 9: {FilterCriteria{ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, allLogs, ""}, // all "mined" logs with 1>= block num <=2 and topic secondTopic - 10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{[]common.Hash{secondTopic}}}, allLogs[3:4], ""}, + 10: {FilterCriteria{FromBlock: big.NewInt(1), ToBlock: big.NewInt(2), Topics: [][]common.Hash{{secondTopic}}}, allLogs[3:4], ""}, // all "mined" and pending logs with topic firstTopic - 11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{[]common.Hash{firstTopic}}}, expectedCase11, ""}, + 11: {FilterCriteria{FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), Topics: [][]common.Hash{{firstTopic}}}, expectedCase11, ""}, } ) @@ -321,14 +320,14 @@ func TestLogFilter(t *testing.T) { } for i, tt := range testCases { - var fetched []Log + var fetched []*types.Log for { // fetch all expected logs results, err := api.GetFilterChanges(tt.id) if err != nil { t.Fatalf("Unable to fetch logs: %v", err) } - fetched = append(fetched, results.([]Log)...) + fetched = append(fetched, results.([]*types.Log)...) if len(fetched) >= len(tt.expected) { break } @@ -345,7 +344,7 @@ func TestLogFilter(t *testing.T) { if fetched[l].Removed { t.Errorf("expected log not to be removed for log %d in case %d", l, i) } - if !reflect.DeepEqual(fetched[l].Log, tt.expected[l]) { + if !reflect.DeepEqual(fetched[l], tt.expected[l]) { t.Errorf("invalid log on index %d for case %d", l, i) } } @@ -357,10 +356,10 @@ func TestPendingLogsSubscription(t *testing.T) { t.Parallel() var ( - mux = new(event.TypeMux) - db, _ = ethdb.NewMemDatabase() + mux = new(event.TypeMux) + db, _ = ethdb.NewMemDatabase() backend = &testBackend{mux, db} - api = NewPublicFilterAPI(backend, false) + api = NewPublicFilterAPI(backend, false) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") secondAddr = common.HexToAddress("0x2222222222222222222222222222222222222222") @@ -373,21 +372,21 @@ func TestPendingLogsSubscription(t *testing.T) { notUsedTopic = common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999") allLogs = []core.PendingLogsEvent{ - core.PendingLogsEvent{Logs: vm.Logs{vm.NewLog(firstAddr, []common.Hash{}, []byte(""), 0)}}, - core.PendingLogsEvent{Logs: vm.Logs{vm.NewLog(firstAddr, []common.Hash{firstTopic}, []byte(""), 1)}}, - core.PendingLogsEvent{Logs: vm.Logs{vm.NewLog(secondAddr, []common.Hash{firstTopic}, []byte(""), 2)}}, - core.PendingLogsEvent{Logs: vm.Logs{vm.NewLog(thirdAddress, []common.Hash{secondTopic}, []byte(""), 3)}}, - core.PendingLogsEvent{Logs: vm.Logs{vm.NewLog(thirdAddress, []common.Hash{secondTopic}, []byte(""), 4)}}, - core.PendingLogsEvent{Logs: vm.Logs{ - vm.NewLog(thirdAddress, []common.Hash{firstTopic}, []byte(""), 5), - vm.NewLog(thirdAddress, []common.Hash{thirdTopic}, []byte(""), 5), - vm.NewLog(thirdAddress, []common.Hash{forthTopic}, []byte(""), 5), - vm.NewLog(firstAddr, []common.Hash{firstTopic}, []byte(""), 5), + {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{}, BlockNumber: 0}}}, + {Logs: []*types.Log{{Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 1}}}, + {Logs: []*types.Log{{Address: secondAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 2}}}, + {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 3}}}, + {Logs: []*types.Log{{Address: thirdAddress, Topics: []common.Hash{secondTopic}, BlockNumber: 4}}}, + {Logs: []*types.Log{ + {Address: thirdAddress, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, + {Address: thirdAddress, Topics: []common.Hash{thirdTopic}, BlockNumber: 5}, + {Address: thirdAddress, Topics: []common.Hash{forthTopic}, BlockNumber: 5}, + {Address: firstAddr, Topics: []common.Hash{firstTopic}, BlockNumber: 5}, }}, } - convertLogs = func(pl []core.PendingLogsEvent) vm.Logs { - var logs vm.Logs + convertLogs = func(pl []core.PendingLogsEvent) []*types.Log { + var logs []*types.Log for _, l := range pl { logs = append(logs, l.Logs...) } @@ -396,26 +395,26 @@ func TestPendingLogsSubscription(t *testing.T) { testCases = []struct { crit FilterCriteria - expected vm.Logs - c chan []Log + expected []*types.Log + c chan []*types.Log sub *Subscription }{ // match all {FilterCriteria{}, convertLogs(allLogs), nil, nil}, // match none due to no matching addresses - {FilterCriteria{Addresses: []common.Address{common.Address{}, notUsedAddress}, Topics: [][]common.Hash{[]common.Hash{}}}, vm.Logs{}, nil, nil}, + {FilterCriteria{Addresses: []common.Address{{}, notUsedAddress}, Topics: [][]common.Hash{{}}}, []*types.Log{}, nil, nil}, // match logs based on addresses, ignore topics {FilterCriteria{Addresses: []common.Address{firstAddr}}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, // match none due to no matching topics (match with address) - {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{[]common.Hash{notUsedTopic}}}, vm.Logs{}, nil, nil}, + {FilterCriteria{Addresses: []common.Address{secondAddr}, Topics: [][]common.Hash{{notUsedTopic}}}, []*types.Log{}, nil, nil}, // match logs based on addresses and topics - {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, secondTopic}}}, append(convertLogs(allLogs[3:5]), allLogs[5].Logs[0]), nil, nil}, + {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[3:5]), allLogs[5].Logs[0]), nil, nil}, // match logs based on multiple addresses and "or" topics - {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, secondTopic}}}, append(convertLogs(allLogs[2:5]), allLogs[5].Logs[0]), nil, nil}, - // block numbers are ignored for filters created with New***Filter, these return all logs that match the given criterias when the state changes + {FilterCriteria{Addresses: []common.Address{secondAddr, thirdAddress}, Topics: [][]common.Hash{{firstTopic, secondTopic}}}, append(convertLogs(allLogs[2:5]), allLogs[5].Logs[0]), nil, nil}, + // block numbers are ignored for filters created with New***Filter, these return all logs that match the given criteria when the state changes {FilterCriteria{Addresses: []common.Address{firstAddr}, FromBlock: big.NewInt(2), ToBlock: big.NewInt(3)}, append(convertLogs(allLogs[:2]), allLogs[5].Logs[3]), nil, nil}, // multiple pending logs, should match only 2 topics from the logs in block 5 - {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{[]common.Hash{firstTopic, forthTopic}}}, vm.Logs{allLogs[5].Logs[0], allLogs[5].Logs[2]}, nil, nil}, + {FilterCriteria{Addresses: []common.Address{thirdAddress}, Topics: [][]common.Hash{{firstTopic, forthTopic}}}, []*types.Log{allLogs[5].Logs[0], allLogs[5].Logs[2]}, nil, nil}, } ) @@ -423,7 +422,7 @@ func TestPendingLogsSubscription(t *testing.T) { // on slow machines this could otherwise lead to missing events when the subscription is created after // (some) events are posted. for i := range testCases { - testCases[i].c = make(chan []Log) + testCases[i].c = make(chan []*types.Log) testCases[i].sub, _ = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) } @@ -431,7 +430,7 @@ func TestPendingLogsSubscription(t *testing.T) { i := n tt := test go func() { - var fetched []Log + var fetched []*types.Log fetchLoop: for { logs := <-tt.c @@ -449,7 +448,7 @@ func TestPendingLogsSubscription(t *testing.T) { if fetched[l].Removed { t.Errorf("expected log not to be removed for log %d in case %d", l, i) } - if !reflect.DeepEqual(fetched[l].Log, tt.expected[l]) { + if !reflect.DeepEqual(fetched[l], tt.expected[l]) { t.Errorf("invalid log on index %d for case %d", l, i) } } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 5256711c2d..5904e41779 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -27,7 +27,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core" "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/ethdb" "github.com/ubiq/go-ubiq/event" @@ -36,8 +35,8 @@ import ( func makeReceipt(addr common.Address) *types.Receipt { receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{ - &vm.Log{Address: addr}, + receipt.Logs = []*types.Log{ + {Address: addr}, } receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) return receipt @@ -146,8 +145,8 @@ func TestFilters(t *testing.T) { switch i { case 1: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{ - &vm.Log{ + receipt.Logs = []*types.Log{ + { Address: addr, Topics: []common.Hash{hash1}, }, @@ -156,8 +155,8 @@ func TestFilters(t *testing.T) { receipts = types.Receipts{receipt} case 2: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{ - &vm.Log{ + receipt.Logs = []*types.Log{ + { Address: addr, Topics: []common.Hash{hash2}, }, @@ -166,8 +165,8 @@ func TestFilters(t *testing.T) { receipts = types.Receipts{receipt} case 998: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{ - &vm.Log{ + receipt.Logs = []*types.Log{ + { Address: addr, Topics: []common.Hash{hash3}, }, @@ -176,8 +175,8 @@ func TestFilters(t *testing.T) { receipts = types.Receipts{receipt} case 999: receipt := types.NewReceipt(nil, new(big.Int)) - receipt.Logs = vm.Logs{ - &vm.Log{ + receipt.Logs = []*types.Log{ + { Address: addr, Topics: []common.Hash{hash4}, }, @@ -211,7 +210,7 @@ func TestFilters(t *testing.T) { filter := New(backend, true) filter.SetAddresses([]common.Address{addr}) - filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2, hash3, hash4}}) + filter.SetTopics([][]common.Hash{{hash1, hash2, hash3, hash4}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) @@ -222,7 +221,7 @@ func TestFilters(t *testing.T) { filter = New(backend, true) filter.SetAddresses([]common.Address{addr}) - filter.SetTopics([][]common.Hash{[]common.Hash{hash3}}) + filter.SetTopics([][]common.Hash{{hash3}}) filter.SetBeginBlock(900) filter.SetEndBlock(999) logs, _ = filter.Find(context.Background()) @@ -235,7 +234,7 @@ func TestFilters(t *testing.T) { filter = New(backend, true) filter.SetAddresses([]common.Address{addr}) - filter.SetTopics([][]common.Hash{[]common.Hash{hash3}}) + filter.SetTopics([][]common.Hash{{hash3}}) filter.SetBeginBlock(990) filter.SetEndBlock(-1) logs, _ = filter.Find(context.Background()) @@ -247,7 +246,7 @@ func TestFilters(t *testing.T) { } filter = New(backend, true) - filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2}}) + filter.SetTopics([][]common.Hash{{hash1, hash2}}) filter.SetBeginBlock(1) filter.SetEndBlock(10) @@ -258,7 +257,7 @@ func TestFilters(t *testing.T) { failHash := common.BytesToHash([]byte("fail")) filter = New(backend, true) - filter.SetTopics([][]common.Hash{[]common.Hash{failHash}}) + filter.SetTopics([][]common.Hash{{failHash}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) @@ -279,7 +278,7 @@ func TestFilters(t *testing.T) { } filter = New(backend, true) - filter.SetTopics([][]common.Hash{[]common.Hash{failHash}, []common.Hash{hash1}}) + filter.SetTopics([][]common.Hash{{failHash}, {hash1}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) diff --git a/eth/handler.go b/eth/handler.go index 32d8b60698..90af93f685 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -83,6 +83,8 @@ type ProtocolManager struct { quitSync chan struct{} noMorePeers chan struct{} + lesServer LesServer + // wait group is used for graceful shutdowns during downloading // and processing wg sync.WaitGroup @@ -167,7 +169,7 @@ func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int return blockchain.CurrentBlock().NumberU64() } inserter := func(blocks types.Blocks) (int, error) { - atomic.StoreUint32(&manager.synced, 1) // Mark initial sync done on any fetcher import + manager.setSynced() // Mark initial sync done on any fetcher import return manager.insertChain(blocks) } manager.fetcher = fetcher.New(blockchain.GetBlockByHash, validator, manager.BroadcastBlock, heighter, inserter, manager.removePeer) @@ -544,38 +546,16 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } case msg.Code == NewBlockHashesMsg: - // Retrieve and deserialize the remote new block hashes notification - type announce struct { - Hash common.Hash - Number uint64 - } - var announces = []announce{} - - if p.version < eth62 { - // We're running the old protocol, make block number unknown (0) - var hashes []common.Hash - if err := msg.Decode(&hashes); err != nil { - return errResp(ErrDecode, "%v: %v", msg, err) - } - for _, hash := range hashes { - announces = append(announces, announce{hash, 0}) - } - } else { - // Otherwise extract both block hash and number - var request newBlockHashesData - if err := msg.Decode(&request); err != nil { - return errResp(ErrDecode, "%v: %v", msg, err) - } - for _, block := range request { - announces = append(announces, announce{block.Hash, block.Number}) - } + var announces newBlockHashesData + if err := msg.Decode(&announces); err != nil { + return errResp(ErrDecode, "%v: %v", msg, err) } // Mark the hashes as present at the remote node for _, block := range announces { p.MarkBlock(block.Hash) } // Schedule all the unknown hashes for retrieval - unknown := make([]announce, 0, len(announces)) + unknown := make(newBlockHashesData, 0, len(announces)) for _, block := range announces { if !pm.blockchain.HasBlock(block.Hash) { unknown = append(unknown, block) @@ -709,7 +689,7 @@ func (self *ProtocolManager) txBroadcastLoop() { // EthNodeInfo represents a short summary of the Ethereum sub-protocol metadata known // about the host peer. type EthNodeInfo struct { - Network int `json:"network"` // Ethereum network ID (0=Olympic, 1=Frontier, 2=Morden) + Network int `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3) Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block diff --git a/eth/handler_test.go b/eth/handler_test.go index bc3dfedb8c..7195b4dfa2 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -75,7 +75,7 @@ func testGetBlockHeaders(t *testing.T, protocol int) { // Create a "random" unknown hash for testing var unknown common.Hash - for i, _ := range unknown { + for i := range unknown { unknown[i] = byte(i) } // Create a batch of tests for various scenarios @@ -246,17 +246,17 @@ func testGetBlockBodies(t *testing.T, protocol int) { {limit + 1, nil, nil, limit}, // No more than the possible block count should be returned {0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable {0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable - {0, []common.Hash{common.Hash{}}, []bool{false}, 0}, // A non existent block should not be returned + {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned // Existing and non-existing blocks interleaved should not cause problems {0, []common.Hash{ - common.Hash{}, + {}, pm.blockchain.GetBlockByNumber(1).Hash(), - common.Hash{}, + {}, pm.blockchain.GetBlockByNumber(10).Hash(), - common.Hash{}, + {}, pm.blockchain.GetBlockByNumber(100).Hash(), - common.Hash{}, + {}, }, []bool{false, true, false, true, false, true, false}, 3}, } // Run each of the tests and verify the results against the chain @@ -311,13 +311,13 @@ func testGetNodeData(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) - tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: @@ -403,13 +403,13 @@ func testGetReceipt(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) - tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: @@ -445,4 +445,3 @@ func testGetReceipt(t *testing.T, protocol int) { t.Errorf("receipts mismatch: %v", err) } } - diff --git a/eth/helper_test.go b/eth/helper_test.go index 8165b698f7..d6cdf4489b 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -93,7 +93,7 @@ type testTxPool struct { // AddBatch appends a batch of transactions to the pool, and notifies any // listeners if the addition channel is non nil -func (p *testTxPool) AddBatch(txs []*types.Transaction) { +func (p *testTxPool) AddBatch(txs []*types.Transaction) error { p.lock.Lock() defer p.lock.Unlock() @@ -101,10 +101,12 @@ func (p *testTxPool) AddBatch(txs []*types.Transaction) { if p.added != nil { p.added <- txs } + + return nil } // Pending returns all the transactions known to the pool -func (p *testTxPool) Pending() map[common.Address]types.Transactions { +func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) { p.lock.RLock() defer p.lock.RUnlock() @@ -116,13 +118,13 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions { for _, batch := range batches { sort.Sort(types.TxByNonce(batch)) } - return batches + return batches, nil } // newTestTransaction create a new dummy transaction. func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) - tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from) + tx, _ = types.SignTx(tx, types.HomesteadSigner{}, from) return tx } diff --git a/eth/protocol.go b/eth/protocol.go index a657fa9546..4c267a52b2 100644 --- a/eth/protocol.go +++ b/eth/protocol.go @@ -98,11 +98,11 @@ var errorToString = map[int]string{ type txPool interface { // AddBatch should add the given transactions to the pool. - AddBatch([]*types.Transaction) + AddBatch([]*types.Transaction) error // Pending should return pending transactions. // The slice should be modifiable by the caller. - Pending() map[common.Address]types.Transactions + Pending() (map[common.Address]types.Transactions, error) } // statusData is the network packet for the status message. diff --git a/eth/protocol_test.go b/eth/protocol_test.go index 07b05bddd2..f808d95100 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -82,7 +82,7 @@ func testStatusMsgErrors(t *testing.T, protocol int) { t.Errorf("test %d: wrong error: got %q, want %q", i, err, test.wantError) } case <-time.After(2 * time.Second): - t.Errorf("protocol did not shut down withing 2 seconds") + t.Errorf("protocol did not shut down within 2 seconds") } p.close() } @@ -178,7 +178,7 @@ func testSendTransactions(t *testing.T, protocol int) { func TestGetBlockHeadersDataEncodeDecode(t *testing.T) { // Create a "random" hash for testing var hash common.Hash - for i, _ := range hash { + for i := range hash { hash[i] = byte(i) } // Assemble some table driven tests diff --git a/eth/sync.go b/eth/sync.go index 2dd963fe31..13342a4f9c 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -46,7 +46,8 @@ type txsync struct { // syncTransactions starts sending all currently pending transactions to the given peer. func (pm *ProtocolManager) syncTransactions(p *peer) { var txs types.Transactions - for _, batch := range pm.txpool.Pending() { + pending, _ := pm.txpool.Pending() + for _, batch := range pending { txs = append(txs, batch...) } if len(txs) == 0 { @@ -180,7 +181,7 @@ func (pm *ProtocolManager) synchronise(peer *peer) { if err := pm.downloader.Synchronise(peer.id, pHead, pTd, mode); err != nil { return } - atomic.StoreUint32(&pm.synced, 1) // Mark initial sync done + pm.setSynced() // Mark initial sync done // If fast sync was enabled, and we synced up, disable it if atomic.LoadUint32(&pm.fastSync) == 1 { @@ -191,3 +192,10 @@ func (pm *ProtocolManager) synchronise(peer *peer) { } } } + +// setSynced sets the synced flag and notifies the light server if present +func (pm *ProtocolManager) setSynced() { + if atomic.SwapUint32(&pm.synced, 1) == 0 && pm.lesServer != nil { + pm.lesServer.Synced() + } +} diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 4d8d6ca9f4..06db3f458f 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -26,7 +26,6 @@ import ( "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/core/types" - "github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/rpc" "golang.org/x/net/context" @@ -81,6 +80,8 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface err := ec.c.CallContext(ctx, &raw, method, args...) if err != nil { return nil, err + } else if len(raw) == 0 { + return nil, ethereum.NotFound } // Decode header and transactions. var head *types.Header @@ -112,7 +113,7 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface for i := range reqs { reqs[i] = rpc.BatchElem{ Method: "eth_getUncleByBlockHashAndIndex", - Args: []interface{}{body.Hash, fmt.Sprintf("%#x", i)}, + Args: []interface{}{body.Hash, hexutil.EncodeUint64(uint64(i))}, Result: &uncles[i], } } @@ -123,6 +124,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface if reqs[i].Error != nil { return nil, reqs[i].Error } + if uncles[i] == nil { + return nil, fmt.Errorf("got null header for uncle %d of block %x", i, body.Hash[:]) + } } } return types.NewBlockWithHeader(head).WithBody(body.Transactions, uncles), nil @@ -132,6 +136,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { var head *types.Header err := ec.c.CallContext(ctx, &head, "eth_getBlockByHash", hash, false) + if err == nil && head == nil { + err = ethereum.NotFound + } return head, err } @@ -140,19 +147,31 @@ func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.He func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { var head *types.Header err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false) + if err == nil && head == nil { + err = ethereum.NotFound + } return head, err } // TransactionByHash returns the transaction with the given hash. -func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*types.Transaction, error) { - var tx *types.Transaction - err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash) - if err == nil { - if _, r, _ := tx.RawSignatureValues(); r == nil { - return nil, fmt.Errorf("server returned transaction without signature") - } +func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { + var raw json.RawMessage + err = ec.c.CallContext(ctx, &raw, "eth_getTransactionByHash", hash) + if err != nil { + return nil, false, err + } else if len(raw) == 0 { + return nil, false, ethereum.NotFound } - return tx, err + if err := json.Unmarshal(raw, &tx); err != nil { + return nil, false, err + } else if _, r, _ := tx.RawSignatureValues(); r == nil { + return nil, false, fmt.Errorf("server returned transaction without signature") + } + var block struct{ BlockHash *common.Hash } + if err := json.Unmarshal(raw, &block); err != nil { + return nil, false, err + } + return tx, block.BlockHash == nil, nil } // TransactionCount returns the total number of transactions in the given block. @@ -165,13 +184,11 @@ func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) ( // TransactionInBlock returns a single transaction at index in the given block. func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { var tx *types.Transaction - err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index) + err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index)) if err == nil { - var signer types.Signer = types.HomesteadSigner{} - if tx.Protected() { - signer = types.NewEIP155Signer(tx.ChainId()) - } - if _, r, _ := types.SignatureValues(signer, tx); r == nil { + if tx == nil { + return nil, ethereum.NotFound + } else if _, r, _ := tx.RawSignatureValues(); r == nil { return nil, fmt.Errorf("server returned transaction without signature") } } @@ -183,8 +200,12 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { var r *types.Receipt err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash) - if err == nil && r != nil && len(r.PostState) == 0 { - return nil, fmt.Errorf("server returned receipt without post state") + if err == nil { + if r == nil { + return nil, ethereum.NotFound + } else if len(r.PostState) == 0 { + return nil, fmt.Errorf("server returned receipt without post state") + } } return r, err } @@ -193,7 +214,7 @@ func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } - return fmt.Sprintf("%#x", number) + return hexutil.EncodeBig(number) } type rpcProgress struct { @@ -272,14 +293,14 @@ func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumb // Filters // FilterLogs executes a filter query. -func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]vm.Log, error) { - var result []vm.Log +func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { + var result []types.Log err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q)) return result, err } // SubscribeFilterLogs subscribes to the results of a streaming filter query. -func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- vm.Log) (ethereum.Subscription, error) { +func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { return ec.c.EthSubscribe(ctx, ch, "logs", toFilterArg(q)) } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 349f7e217f..a3d21e6e3f 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -21,9 +21,9 @@ import "github.com/ubiq/go-ubiq" // Verify that Client implements the ethereum interfaces. var ( _ = ethereum.ChainReader(&Client{}) + _ = ethereum.TransactionReader(&Client{}) _ = ethereum.ChainStateReader(&Client{}) _ = ethereum.ChainSyncReader(&Client{}) - _ = ethereum.ChainHeadEventer(&Client{}) _ = ethereum.ContractCaller(&Client{}) _ = ethereum.GasEstimator(&Client{}) _ = ethereum.GasPricer(&Client{}) diff --git a/ethdb/database.go b/ethdb/database.go index 46378f168f..e31c769a69 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -305,3 +305,55 @@ func (b *ldbBatch) Put(key, value []byte) error { func (b *ldbBatch) Write() error { return b.db.Write(b.b, nil) } + +type table struct { + db Database + prefix string +} + +// NewTable returns a Database object that prefixes all keys with a given +// string. +func NewTable(db Database, prefix string) Database { + return &table{ + db: db, + prefix: prefix, + } +} + +func (dt *table) Put(key []byte, value []byte) error { + return dt.db.Put(append([]byte(dt.prefix), key...), value) +} + +func (dt *table) Get(key []byte) ([]byte, error) { + return dt.db.Get(append([]byte(dt.prefix), key...)) +} + +func (dt *table) Delete(key []byte) error { + return dt.db.Delete(append([]byte(dt.prefix), key...)) +} + +func (dt *table) Close() { + // Do nothing; don't close the underlying DB. +} + +type tableBatch struct { + batch Batch + prefix string +} + +// NewTableBatch returns a Batch object which prefixes all keys with a given string. +func NewTableBatch(db Database, prefix string) Batch { + return &tableBatch{db.NewBatch(), prefix} +} + +func (dt *table) NewBatch() Batch { + return &tableBatch{dt.db.NewBatch(), dt.prefix} +} + +func (tb *tableBatch) Put(key, value []byte) error { + return tb.batch.Put(append([]byte(tb.prefix), key...), value) +} + +func (tb *tableBatch) Write() error { + return tb.batch.Write() +} diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index 1b0e2cf70a..ada8c9fafa 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -67,7 +67,7 @@ func (db *MemDatabase) Keys() [][]byte { defer db.lock.RUnlock() keys := [][]byte{} - for key, _ := range db.db { + for key := range db.db { keys = append(keys, []byte(key)) } return keys diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index d175d34c75..19d23d28dc 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -25,6 +25,7 @@ import ( "regexp" "runtime" "strconv" + "strings" "time" "github.com/ubiq/go-ubiq/common" @@ -41,6 +42,10 @@ import ( "golang.org/x/net/websocket" ) +// historyUpdateRange is the number of blocks a node should report upon login or +// history request. +const historyUpdateRange = 50 + // Service implements an Ethereum netstats reporting daemon that pushes local // chain statistics up to a monitoring server. type Service struct { @@ -53,6 +58,9 @@ type Service struct { node string // Name of the node to display on the monitoring page pass string // Password to authorize access to the monitoring page host string // Remote address of the monitoring service + + pongCh chan struct{} // Pong notifications are fed into this channel + histCh chan []uint64 // History request block numbers are fed into this channel } // New returns a monitoring service ready for stats reporting. @@ -65,11 +73,13 @@ func New(url string, ethServ *eth.Ethereum, lesServ *les.LightEthereum) (*Servic } // Assemble and return the stats service return &Service{ - eth: ethServ, - les: lesServ, - node: parts[1], - pass: parts[3], - host: parts[4], + eth: ethServ, + les: lesServ, + node: parts[1], + pass: parts[3], + host: parts[4], + pongCh: make(chan struct{}), + histCh: make(chan []uint64, 1), }, nil } @@ -115,7 +125,11 @@ func (s *Service) loop() { // Loop reporting until termination for { // Establish a websocket connection to the server and authenticate the node - conn, err := websocket.Dial(fmt.Sprintf("wss://%s/api", s.host), "", "http://localhost/") + url := fmt.Sprintf("%s/api", s.host) + if !strings.Contains(url, "://") { + url = "wss://" + url + } + conn, err := websocket.Dial(url, "", "http://localhost/") if err != nil { glog.V(logger.Warn).Infof("Stats server unreachable: %v", err) time.Sleep(10 * time.Second) @@ -130,22 +144,34 @@ func (s *Service) loop() { time.Sleep(10 * time.Second) continue } - if err = s.report(in, out); err != nil { + go s.readLoop(conn, in) + + // Send the initial stats so our node looks decent from the get go + if err = s.report(out); err != nil { glog.V(logger.Warn).Infof("Initial stats report failed: %v", err) conn.Close() continue } + if err = s.reportHistory(out, nil); err != nil { + glog.V(logger.Warn).Infof("History report failed: %v", err) + conn.Close() + continue + } // Keep sending status updates until the connection breaks fullReport := time.NewTicker(15 * time.Second) for err == nil { select { case <-fullReport.C: - if err = s.report(in, out); err != nil { + if err = s.report(out); err != nil { glog.V(logger.Warn).Infof("Full stats report failed: %v", err) } - case head := <-headSub.Chan(): - if head == nil { // node stopped + case list := <-s.histCh: + if err = s.reportHistory(out, list); err != nil { + glog.V(logger.Warn).Infof("Block history report failed: %v", err) + } + case head, ok := <-headSub.Chan(): + if !ok { // node stopped conn.Close() return } @@ -155,8 +181,8 @@ func (s *Service) loop() { if err = s.reportPending(out); err != nil { glog.V(logger.Warn).Infof("Post-block transaction stats report failed: %v", err) } - case ev := <-txSub.Chan(): - if ev == nil { // node stopped + case _, ok := <-txSub.Chan(): + if !ok { // node stopped conn.Close() return } @@ -178,6 +204,76 @@ func (s *Service) loop() { } } +// readLoop loops as long as the connection is alive and retrieves data packets +// from the network socket. If any of them match an active request, it forwards +// it, if they themselves are requests it initiates a reply, and lastly it drops +// unknown packets. +func (s *Service) readLoop(conn *websocket.Conn, in *json.Decoder) { + // If the read loop exists, close the connection + defer conn.Close() + + for { + // Retrieve the next generic network packet and bail out on error + var msg map[string][]interface{} + if err := in.Decode(&msg); err != nil { + glog.V(logger.Warn).Infof("Failed to decode stats server message: %v", err) + return + } + if len(msg["emit"]) == 0 { + glog.V(logger.Warn).Infof("Stats server sent non-broadcast: %v", msg) + return + } + command, ok := msg["emit"][0].(string) + if !ok { + glog.V(logger.Warn).Infof("Invalid stats server message type: %v", msg["emit"][0]) + return + } + // If the message is a ping reply, deliver (someone must be listening!) + if len(msg["emit"]) == 2 && command == "node-pong" { + select { + case s.pongCh <- struct{}{}: + // Pong delivered, continue listening + continue + default: + // Ping routine dead, abort + glog.V(logger.Warn).Infof("Stats server pinger seems to have died") + return + } + } + // If the message is a history request, forward to the event processor + if len(msg["emit"]) == 2 && command == "history" { + // Make sure the request is valid and doesn't crash us + request, ok := msg["emit"][1].(map[string]interface{}) + if !ok { + glog.V(logger.Warn).Infof("Invalid history request: %v", msg["emit"][1]) + return + } + list, ok := request["list"].([]interface{}) + if !ok { + glog.V(logger.Warn).Infof("Invalid history block list: %v", request["list"]) + return + } + // Convert the block number list to an integer list + numbers := make([]uint64, len(list)) + for i, num := range list { + n, ok := num.(float64) + if !ok { + glog.V(logger.Warn).Infof("Invalid history block number: %v", num) + return + } + numbers[i] = uint64(n) + } + select { + case s.histCh <- numbers: + continue + default: + } + } + // Report anything else and continue + glog.V(logger.Info).Infof("Unknown stats message: %v", msg) + } +} + // nodeInfo is the collection of metainformation about a node that is displayed // on the monitoring page. type nodeInfo struct { @@ -190,6 +286,7 @@ type nodeInfo struct { Os string `json:"os"` OsVer string `json:"os_v"` Client string `json:"client"` + History bool `json:"canUpdateHistory"` } // authMsg is the authentication infos needed to login to a monitoring server. @@ -224,11 +321,12 @@ func (s *Service) login(in *json.Decoder, out *json.Encoder) error { Os: runtime.GOOS, OsVer: runtime.GOARCH, Client: "0.1.1", + History: true, }, Secret: s.pass, } login := map[string][]interface{}{ - "emit": []interface{}{"hello", auth}, + "emit": {"hello", auth}, } if err := out.Encode(login); err != nil { return err @@ -244,8 +342,8 @@ func (s *Service) login(in *json.Decoder, out *json.Encoder) error { // report collects all possible data to report and send it to the stats server. // This should only be used on reconnects or rarely to avoid overloading the // server. Use the individual methods for reporting subscribed events. -func (s *Service) report(in *json.Decoder, out *json.Encoder) error { - if err := s.reportLatency(in, out); err != nil { +func (s *Service) report(out *json.Encoder) error { + if err := s.reportLatency(out); err != nil { return err } if err := s.reportBlock(out, nil); err != nil { @@ -262,12 +360,12 @@ func (s *Service) report(in *json.Decoder, out *json.Encoder) error { // reportLatency sends a ping request to the server, measures the RTT time and // finally sends a latency update. -func (s *Service) reportLatency(in *json.Decoder, out *json.Encoder) error { +func (s *Service) reportLatency(out *json.Encoder) error { // Send the current time to the ethstats server start := time.Now() ping := map[string][]interface{}{ - "emit": []interface{}{"node-ping", map[string]string{ + "emit": {"node-ping", map[string]string{ "id": s.node, "clientTime": start.String(), }}, @@ -276,27 +374,28 @@ func (s *Service) reportLatency(in *json.Decoder, out *json.Encoder) error { return err } // Wait for the pong request to arrive back - var pong map[string][]interface{} - if err := in.Decode(&pong); err != nil || len(pong["emit"]) != 2 || pong["emit"][0].(string) != "node-pong" { - return errors.New("unexpected ping reply") + select { + case <-s.pongCh: + // Pong delivered, report the latency + case <-time.After(3 * time.Second): + // Ping timeout, abort + return errors.New("ping timed out") } // Send back the measured latency latency := map[string][]interface{}{ - "emit": []interface{}{"latency", map[string]string{ + "emit": {"latency", map[string]string{ "id": s.node, "latency": strconv.Itoa(int((time.Since(start) / time.Duration(2)).Nanoseconds() / 1000000)), }}, } - if err := out.Encode(latency); err != nil { - return err - } - return nil + return out.Encode(latency) } // blockStats is the information to report about individual blocks. type blockStats struct { Number *big.Int `json:"number"` Hash common.Hash `json:"hash"` + Timestamp *big.Int `json:"timestamp"` Miner common.Address `json:"miner"` GasUsed *big.Int `json:"gasUsed"` GasLimit *big.Int `json:"gasLimit"` @@ -330,9 +429,23 @@ func (s uncleStats) MarshalJSON() ([]byte, error) { // reportBlock retrieves the current chain head and repors it to the stats server. func (s *Service) reportBlock(out *json.Encoder, block *types.Block) error { - // Gather the head block infos from the local blockchain + // Assemble the block stats report and send it to the server + stats := map[string]interface{}{ + "id": s.node, + "block": s.assembleBlockStats(block), + } + report := map[string][]interface{}{ + "emit": {"block", stats}, + } + return out.Encode(report) +} + +// assembleBlockStats retrieves any required metadata to report a single block +// and assembles the block stats. If block is nil, the current head is processed. +func (s *Service) assembleBlockStats(block *types.Block) *blockStats { + // Gather the block infos from the local blockchain var ( - head *types.Header + header *types.Header td *big.Int txs []*types.Transaction uncles []*types.Header @@ -342,42 +455,77 @@ func (s *Service) reportBlock(out *json.Encoder, block *types.Block) error { if block == nil { block = s.eth.BlockChain().CurrentBlock() } - head = block.Header() - td = s.eth.BlockChain().GetTd(head.Hash(), head.Number.Uint64()) + header = block.Header() + td = s.eth.BlockChain().GetTd(header.Hash(), header.Number.Uint64()) txs = block.Transactions() uncles = block.Uncles() } else { // Light nodes would need on-demand lookups for transactions/uncles, skip if block != nil { - head = block.Header() + header = block.Header() + } else { + header = s.les.BlockChain().CurrentHeader() + } + td = s.les.BlockChain().GetTd(header.Hash(), header.Number.Uint64()) + } + // Assemble and return the block stats + return &blockStats{ + Number: header.Number, + Hash: header.Hash(), + Timestamp: header.Time, + Miner: header.Coinbase, + GasUsed: new(big.Int).Set(header.GasUsed), + GasLimit: new(big.Int).Set(header.GasLimit), + Diff: header.Difficulty.String(), + TotalDiff: td.String(), + Txs: txs, + Uncles: uncles, + } +} + +// reportHistory retrieves the most recent batch of blocks and reports it to the +// stats server. +func (s *Service) reportHistory(out *json.Encoder, list []uint64) error { + // Figure out the indexes that need reporting + indexes := make([]uint64, 0, historyUpdateRange) + if len(list) > 0 { + // Specific indexes requested, send them back in particular + indexes = append(indexes, list...) + } else { + // No indexes requested, send back the top ones + var head *types.Header + if s.eth != nil { + head = s.eth.BlockChain().CurrentHeader() } else { head = s.les.BlockChain().CurrentHeader() } - td = s.les.BlockChain().GetTd(head.Hash(), head.Number.Uint64()) + start := head.Number.Int64() - historyUpdateRange + if start < 0 { + start = 0 + } + for i := uint64(start); i <= head.Number.Uint64(); i++ { + indexes = append(indexes, i) + } } - // Assemble the block stats report and send it to the server + // Gather the batch of blocks to report + history := make([]*blockStats, len(indexes)) + for i, number := range indexes { + if s.eth != nil { + history[i] = s.assembleBlockStats(s.eth.BlockChain().GetBlockByNumber(number)) + } else { + history[i] = s.assembleBlockStats(types.NewBlockWithHeader(s.les.BlockChain().GetHeaderByNumber(number))) + } + } + // Assemble the history report and send it to the server stats := map[string]interface{}{ - "id": s.node, - "block": &blockStats{ - Number: head.Number, - Hash: head.Hash(), - Miner: head.Coinbase, - GasUsed: new(big.Int).Set(head.GasUsed), - GasLimit: new(big.Int).Set(head.GasLimit), - Diff: head.Difficulty.String(), - TotalDiff: td.String(), - Txs: txs, - Uncles: uncles, - }, + "id": s.node, + "history": history, } report := map[string][]interface{}{ - "emit": []interface{}{"block", stats}, + "emit": {"history", stats}, } - if err := out.Encode(report); err != nil { - return err - } - return nil + return out.Encode(report) } // pendStats is the information to report about pending transactions. @@ -403,12 +551,9 @@ func (s *Service) reportPending(out *json.Encoder) error { }, } report := map[string][]interface{}{ - "emit": []interface{}{"pending", stats}, + "emit": {"pending", stats}, } - if err := out.Encode(report); err != nil { - return err - } - return nil + return out.Encode(report) } // blockStats is the information to report about the local node. @@ -457,10 +602,7 @@ func (s *Service) reportStats(out *json.Encoder) error { }, } report := map[string][]interface{}{ - "emit": []interface{}{"stats", stats}, + "emit": {"stats", stats}, } - if err := out.Encode(report); err != nil { - return err - } - return nil + return out.Encode(report) } diff --git a/event/event_test.go b/event/event_test.go index 3940293013..2c56ecf29f 100644 --- a/event/event_test.go +++ b/event/event_test.go @@ -144,7 +144,7 @@ func TestMuxConcurrent(t *testing.T) { func emptySubscriber(mux *TypeMux, types ...interface{}) { s := mux.Subscribe(testEvent(0)) go func() { - for _ = range s.Chan() { + for range s.Chan() { } }() } @@ -187,7 +187,7 @@ func BenchmarkChanSend(b *testing.B) { c := make(chan interface{}) closed := make(chan struct{}) go func() { - for _ = range c { + for range c { } }() diff --git a/event/filter/generic_filter.go b/event/filter/generic_filter.go index 27f35920d4..d679b8bfa8 100644 --- a/event/filter/generic_filter.go +++ b/event/filter/generic_filter.go @@ -34,7 +34,7 @@ func (self Generic) Compare(f Filter) bool { strMatch = false } - for k, _ := range self.Data { + for k := range self.Data { if _, ok := filter.Data[k]; !ok { return false } diff --git a/generators/defaults.go b/generators/defaults.go deleted file mode 100644 index ab9d4a52d7..0000000000 --- a/generators/defaults.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -//go:generate go run defaults.go default.json defs.go - -package main //build !none - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strings" -) - -func fatalf(str string, v ...interface{}) { - fmt.Fprintf(os.Stderr, str, v...) - os.Exit(1) -} - -type setting struct { - Value int64 `json:"v"` - Comment string `json:"d"` -} - -func main() { - if len(os.Args) < 3 { - fatalf("usage %s \n", os.Args[0]) - } - - content, err := ioutil.ReadFile(os.Args[1]) - if err != nil { - fatalf("error reading file %v\n", err) - } - - m := make(map[string]setting) - json.Unmarshal(content, &m) - - filepath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ubiq", "go-ubiq", "params", os.Args[2]) - output, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE, 0666) - if err != nil { - fatalf("error opening file for writing %v\n", err) - } - - output.WriteString(`// DO NOT EDIT!!! -// AUTOGENERATED FROM generators/defaults.go - -package params - -import "math/big" - -var ( -`) - - for name, setting := range m { - output.WriteString(fmt.Sprintf("%s=big.NewInt(%d) // %s\n", strings.Title(name), setting.Value, setting.Comment)) - } - - output.WriteString(")\n") - output.Close() - - cmd := exec.Command("gofmt", "-w", filepath) - if err := cmd.Run(); err != nil { - fatalf("gofmt failed: %v\n", err) - } -} diff --git a/interfaces.go b/interfaces.go index 11897825ee..fef95f60af 100644 --- a/interfaces.go +++ b/interfaces.go @@ -18,14 +18,17 @@ package ethereum import ( + "errors" "math/big" "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core/types" - "github.com/ubiq/go-ubiq/core/vm" "golang.org/x/net/context" ) +// NotFound is returned by API methods if the requested item does not exist. +var NotFound = errors.New("not found") + // TODO: move subscription to package event // Subscription represents an event subscription where events are @@ -46,6 +49,8 @@ type Subscription interface { // blockchain fork that was previously downloaded and processed by the node. The block // number argument can be nil to select the latest canonical block. Reading block headers // should be preferred over full blocks whenever possible. +// +// The returned error is NotFound if the requested item does not exist. type ChainReader interface { BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) @@ -53,7 +58,30 @@ type ChainReader interface { HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) - TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) + + // This method subscribes to notifications about changes of the head block of + // the canonical chain. + SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (Subscription, error) +} + +// TransactionReader provides access to past transactions and their receipts. +// Implementations may impose arbitrary restrictions on the transactions and receipts that +// can be retrieved. Historic transactions may not be available. +// +// Avoid relying on this interface if possible. Contract logs (through the LogFilterer +// interface) are more reliable and usually safer in the presence of chain +// reorganisations. +// +// The returned error is NotFound if the requested item does not exist. +type TransactionReader interface { + // TransactionByHash checks the pool of pending transactions in addition to the + // blockchain. The isPending return value indicates whether the transaction has been + // mined yet. Note that the transaction may not be part of the canonical chain even if + // it's not pending. + TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) + // TransactionReceipt returns the receipt of a mined transaction. Note that the + // transaction may not be included in the current canonical chain even if a receipt + // exists. TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) } @@ -83,11 +111,6 @@ type ChainSyncReader interface { SyncProgress(ctx context.Context) (*SyncProgress, error) } -// A ChainHeadEventer returns notifications whenever the canonical head block is updated. -type ChainHeadEventer interface { - SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (Subscription, error) -} - // CallMsg contains parameters for contract calls. type CallMsg struct { From common.Address // the sender of the 'transaction' @@ -128,9 +151,12 @@ type FilterQuery struct { // LogFilterer provides access to contract log events using a one-off query or continuous // event subscription. +// +// Logs received through a streaming query subscription may have Removed set to true, +// indicating that the log was reverted due to a chain reorganisation. type LogFilterer interface { - FilterLogs(ctx context.Context, q FilterQuery) ([]vm.Log, error) - SubscribeFilterLogs(ctx context.Context, q FilterQuery, ch chan<- vm.Log) (Subscription, error) + FilterLogs(ctx context.Context, q FilterQuery) ([]types.Log, error) + SubscribeFilterLogs(ctx context.Context, q FilterQuery, ch chan<- types.Log) (Subscription, error) } // TransactionSender wraps transaction sending. The SendTransaction method injects a diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index bc94fd8114..a755e87193 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -19,15 +19,19 @@ package ethapi import ( "bytes" "encoding/hex" - "encoding/json" + "errors" "fmt" + "math" "math/big" "strings" "time" "github.com/ethereum/ethash" + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/util" "github.com/ubiq/go-ubiq/accounts" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/core" "github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/core/vm" @@ -38,12 +42,10 @@ import ( "github.com/ubiq/go-ubiq/p2p" "github.com/ubiq/go-ubiq/rlp" "github.com/ubiq/go-ubiq/rpc" - "github.com/syndtr/goleveldb/leveldb" - "github.com/syndtr/goleveldb/leveldb/util" "golang.org/x/net/context" ) -const defaultGas = uint64(90000) +const defaultGas = 90000 // PublicEthereumAPI provides an API to access Ethereum related information. // It offers only methods that operate on public data that is freely available to anyone. @@ -62,8 +64,8 @@ func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) { } // ProtocolVersion returns the current Ethereum protocol version this node supports -func (s *PublicEthereumAPI) ProtocolVersion() *rpc.HexNumber { - return rpc.NewHexNumber(s.b.ProtocolVersion()) +func (s *PublicEthereumAPI) ProtocolVersion() hexutil.Uint { + return hexutil.Uint(s.b.ProtocolVersion()) } // Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not @@ -82,11 +84,11 @@ func (s *PublicEthereumAPI) Syncing() (interface{}, error) { } // Otherwise gather the block sync stats return map[string]interface{}{ - "startingBlock": rpc.NewHexNumber(progress.StartingBlock), - "currentBlock": rpc.NewHexNumber(progress.CurrentBlock), - "highestBlock": rpc.NewHexNumber(progress.HighestBlock), - "pulledStates": rpc.NewHexNumber(progress.PulledStates), - "knownStates": rpc.NewHexNumber(progress.KnownStates), + "startingBlock": hexutil.Uint64(progress.StartingBlock), + "currentBlock": hexutil.Uint64(progress.CurrentBlock), + "highestBlock": hexutil.Uint64(progress.HighestBlock), + "pulledStates": hexutil.Uint64(progress.PulledStates), + "knownStates": hexutil.Uint64(progress.KnownStates), }, nil } @@ -128,11 +130,11 @@ func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransac } // Status returns the number of pending and queued transaction in the pool. -func (s *PublicTxPoolAPI) Status() map[string]*rpc.HexNumber { +func (s *PublicTxPoolAPI) Status() map[string]hexutil.Uint { pending, queue := s.b.Stats() - return map[string]*rpc.HexNumber{ - "pending": rpc.NewHexNumber(pending), - "queued": rpc.NewHexNumber(queue), + return map[string]hexutil.Uint{ + "pending": hexutil.Uint(pending), + "queued": hexutil.Uint(queue), } } @@ -237,16 +239,18 @@ func (s *PrivateAccountAPI) ImportRawKey(privkey string, password string) (commo // UnlockAccount will unlock the account associated with the given address with // the given password for duration seconds. If duration is nil it will use a // default of 300 seconds. It returns an indication if the account was unlocked. -func (s *PrivateAccountAPI) UnlockAccount(addr common.Address, password string, duration *rpc.HexNumber) (bool, error) { +func (s *PrivateAccountAPI) UnlockAccount(addr common.Address, password string, duration *uint64) (bool, error) { + const max = uint64(time.Duration(math.MaxInt64) / time.Second) + var d time.Duration if duration == nil { - duration = rpc.NewHexNumber(300) + d = 300 * time.Second + } else if *duration > max { + return false, errors.New("unlock duration too large") + } else { + d = time.Duration(*duration) * time.Second } - a := accounts.Account{Address: addr} - d := time.Duration(duration.Int64()) * time.Second - if err := s.am.TimedUnlock(a, password, d); err != nil { - return false, err - } - return true, nil + err := s.am.TimedUnlock(accounts.Account{Address: addr}, password, d) + return err == nil, err } // LockAccount will lock the account associated with the given address when it's unlocked. @@ -258,29 +262,12 @@ func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool { // tries to sign it with the key associated with args.To. If the given passwd isn't // able to decrypt the key it fails. func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) { - var err error - args, err = prepareSendTxArgs(ctx, args, s.b) - if err != nil { + if err := args.setDefaults(ctx, s.b); err != nil { return common.Hash{}, err } - - if args.Nonce == nil { - nonce, err := s.b.GetPoolNonce(ctx, args.From) - if err != nil { - return common.Hash{}, err - } - args.Nonce = rpc.NewHexNumber(nonce) - } - - var tx *types.Transaction - if args.To == nil { - tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } else { - tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } - + tx := args.toTransaction() signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) - signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes()) + signature, err := s.am.SignWithPassphrase(accounts.Account{Address: args.From}, passwd, signer.Hash(tx).Bytes()) if err != nil { return common.Hash{}, err } @@ -289,30 +276,33 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs } // signHash is a helper function that calculates a hash for the given message that can be -// safely used to calculate a signature from. The hash is calulcated with: -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). -func signHash(message string) []byte { - data := common.FromHex(message) - // Give context to the signed message. This prevents an adversery to sign a tx. - // It has no cryptographic purpose. +// safely used to calculate a signature from. +// +// The hash is calulcated as +// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). +// +// This gives context to the signed message and prevents signing of transactions. +func signHash(data []byte) []byte { msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) - // Always hash, this prevents choosen plaintext attacks that can extract key information return crypto.Keccak256([]byte(msg)) } // Sign calculates an Ethereum ECDSA signature for: // keccack256("\x19Ethereum Signed Message:\n" + len(message) + message)) // +// Note, the produced signature conforms to the secp256k1 curve R, S and V values, +// where the V value will be 27 or 28 for legacy reasons. +// // The key used to calculate the signature is decrypted with the given password. // // https://github.com/ubiq/go-ubiq/wiki/Management-APIs#personal_sign -func (s *PrivateAccountAPI) Sign(ctx context.Context, message string, addr common.Address, passwd string) (string, error) { - hash := signHash(message) - signature, err := s.b.AccountManager().SignWithPassphrase(addr, passwd, hash) +func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { + signature, err := s.b.AccountManager().SignWithPassphrase(accounts.Account{Address: addr}, passwd, signHash(data)) if err != nil { - return "0x", err + return nil, err } - return common.ToHex(signature), nil + signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper + return signature, nil } // EcRecover returns the address for the account that was used to create the signature. @@ -321,30 +311,25 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, message string, addr commo // hash = keccak256("\x19Ethereum Signed Message:\n"${message length}${message}) // addr = ecrecover(hash, signature) // +// Note, the signature must conform to the secp256k1 curve R, S and V values, where +// the V value must be be 27 or 28 for legacy reasons. +// // https://github.com/ubiq/go-ubiq/wiki/Management-APIs#personal_ecRecover -func (s *PrivateAccountAPI) EcRecover(ctx context.Context, message string, signature string) (common.Address, error) { - var ( - hash = signHash(message) - sig = common.FromHex(signature) - ) - +func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { if len(sig) != 65 { return common.Address{}, fmt.Errorf("signature must be 65 bytes long") } - - // see crypto.Ecrecover description - if sig[64] == 27 || sig[64] == 28 { - sig[64] -= 27 + if sig[64] != 27 && sig[64] != 28 { + return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)") } + sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 - rpk, err := crypto.Ecrecover(hash, sig) + rpk, err := crypto.Ecrecover(signHash(data), sig) if err != nil { return common.Address{}, err } - pubKey := crypto.ToECDSAPub(rpk) recoveredAddr := crypto.PubkeyToAddress(*pubKey) - return recoveredAddr, nil } @@ -412,15 +397,15 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash comm // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true // all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. -func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (map[string]interface{}, error) { +func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, blockNr) if block != nil { uncles := block.Uncles() - if index.Int() < 0 || index.Int() >= len(uncles) { - glog.V(logger.Debug).Infof("uncle block on index %d not found for block #%d", index.Int(), blockNr) + if index >= hexutil.Uint(len(uncles)) { + glog.V(logger.Debug).Infof("uncle block on index %d not found for block #%d", index, blockNr) return nil, nil } - block = types.NewBlockWithHeader(uncles[index.Int()]) + block = types.NewBlockWithHeader(uncles[index]) return s.rpcOutputBlock(block, false, false) } return nil, err @@ -428,32 +413,34 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, // GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true // all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. -func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (map[string]interface{}, error) { +func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { block, err := s.b.GetBlock(ctx, blockHash) if block != nil { uncles := block.Uncles() - if index.Int() < 0 || index.Int() >= len(uncles) { - glog.V(logger.Debug).Infof("uncle block on index %d not found for block %s", index.Int(), blockHash.Hex()) + if index >= hexutil.Uint(len(uncles)) { + glog.V(logger.Debug).Infof("uncle block on index %d not found for block %s", index, blockHash.Hex()) return nil, nil } - block = types.NewBlockWithHeader(uncles[index.Int()]) + block = types.NewBlockWithHeader(uncles[index]) return s.rpcOutputBlock(block, false, false) } return nil, err } // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number -func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *rpc.HexNumber { +func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return rpc.NewHexNumber(len(block.Uncles())) + n := hexutil.Uint(len(block.Uncles())) + return &n } return nil } // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash -func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *rpc.HexNumber { +func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return rpc.NewHexNumber(len(block.Uncles())) + n := hexutil.Uint(len(block.Uncles())) + return &n } return nil } @@ -486,7 +473,7 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A return res.Hex(), nil } -// callmsg is the message type used for call transations. +// callmsg is the message type used for call transitions. type callmsg struct { addr common.Address to *common.Address @@ -510,10 +497,10 @@ func (m callmsg) Data() []byte { return m.data } type CallArgs struct { From common.Address `json:"from"` To *common.Address `json:"to"` - Gas rpc.HexNumber `json:"gas"` - GasPrice rpc.HexNumber `json:"gasPrice"` - Value rpc.HexNumber `json:"value"` - Data string `json:"data"` + Gas hexutil.Big `json:"gas"` + GasPrice hexutil.Big `json:"gasPrice"` + Value hexutil.Big `json:"value"` + Data hexutil.Bytes `json:"data"` } func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { @@ -538,14 +525,14 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr } // Assemble the CALL invocation - gas, gasPrice := args.Gas.BigInt(), args.GasPrice.BigInt() + gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt() if gas.Cmp(common.Big0) == 0 { gas = big.NewInt(50000000) } if gasPrice.Cmp(common.Big0) == 0 { gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } - msg := types.NewMessage(addr, args.To, 0, args.Value.BigInt(), gas, gasPrice, common.FromHex(args.Data), false) + msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false) // Execute the call and return vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header) @@ -557,23 +544,23 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr if err := vmError(); err != nil { return "0x", common.Big0, err } - if len(res) == 0 { // backwards compatability + if len(res) == 0 { // backwards compatibility return "0x", gas, err } return common.ToHex(res), gas, err } // Call executes the given transaction on the state for the given block number. -// It doesn't make and changes in the state/blockchain and is usefull to execute and retrieve values. +// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values. func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (string, error) { result, _, err := s.doCall(ctx, args, blockNr) return result, err } // EstimateGas returns an estimate of the amount of gas needed to execute the given transaction. -func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*rpc.HexNumber, error) { +func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) { _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber) - return rpc.NewHexNumber(gas), err + return (*hexutil.Big)(gas), err } // ExecutionResult groups all structured logs emitted by the EVM @@ -635,7 +622,7 @@ func FormatLogs(structLogs []vm.StructLog) []StructLogRes { func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { head := b.Header() // copies the header once fields := map[string]interface{}{ - "number": rpc.NewHexNumber(head.Number), + "number": (*hexutil.Big)(head.Number), "hash": b.Hash(), "parentHash": head.ParentHash, "nonce": head.Nonce, @@ -644,13 +631,13 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx "logsBloom": head.Bloom, "stateRoot": head.Root, "miner": head.Coinbase, - "difficulty": rpc.NewHexNumber(head.Difficulty), - "totalDifficulty": rpc.NewHexNumber(s.b.GetTd(b.Hash())), - "extraData": rpc.HexBytes(head.Extra), - "size": rpc.NewHexNumber(b.Size().Int64()), - "gasLimit": rpc.NewHexNumber(head.GasLimit), - "gasUsed": rpc.NewHexNumber(head.GasUsed), - "timestamp": rpc.NewHexNumber(head.Time), + "difficulty": (*hexutil.Big)(head.Difficulty), + "totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())), + "extraData": hexutil.Bytes(head.Extra), + "size": hexutil.Uint64(uint64(b.Size().Int64())), + "gasLimit": (*hexutil.Big)(head.GasLimit), + "gasUsed": (*hexutil.Big)(head.GasUsed), + "timestamp": (*hexutil.Big)(head.Time), "transactionsRoot": head.TxHash, "receiptsRoot": head.ReceiptHash, } @@ -690,19 +677,19 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { BlockHash common.Hash `json:"blockHash"` - BlockNumber *rpc.HexNumber `json:"blockNumber"` + BlockNumber *hexutil.Big `json:"blockNumber"` From common.Address `json:"from"` - Gas *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` + Gas *hexutil.Big `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` Hash common.Hash `json:"hash"` - Input rpc.HexBytes `json:"input"` - Nonce *rpc.HexNumber `json:"nonce"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` To *common.Address `json:"to"` - TransactionIndex *rpc.HexNumber `json:"transactionIndex"` - Value *rpc.HexNumber `json:"value"` - V *rpc.HexNumber `json:"v"` - R *rpc.HexNumber `json:"r"` - S *rpc.HexNumber `json:"s"` + TransactionIndex hexutil.Uint `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` } // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation @@ -712,25 +699,25 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { signer = types.NewEIP155Signer(tx.ChainId()) } from, _ := types.Sender(signer, tx) - v, r, s := types.SignatureValues(signer, tx) + v, r, s := tx.RawSignatureValues() return &RPCTransaction{ From: from, - Gas: rpc.NewHexNumber(tx.Gas()), - GasPrice: rpc.NewHexNumber(tx.GasPrice()), + Gas: (*hexutil.Big)(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), Hash: tx.Hash(), - Input: rpc.HexBytes(tx.Data()), - Nonce: rpc.NewHexNumber(tx.Nonce()), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), To: tx.To(), - Value: rpc.NewHexNumber(tx.Value()), - V: rpc.NewHexNumber(v), - R: rpc.NewHexNumber(r), - S: rpc.NewHexNumber(s), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), } } // newRPCTransaction returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) { - if txIndex >= 0 && txIndex < len(b.Transactions()) { +func newRPCTransactionFromBlockIndex(b *types.Block, txIndex uint) (*RPCTransaction, error) { + if txIndex < uint(len(b.Transactions())) { tx := b.Transactions()[txIndex] var signer types.Signer = types.FrontierSigner{} if tx.Protected() { @@ -740,19 +727,19 @@ func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransacti v, r, s := tx.RawSignatureValues() return &RPCTransaction{ BlockHash: b.Hash(), - BlockNumber: rpc.NewHexNumber(b.Number()), + BlockNumber: (*hexutil.Big)(b.Number()), From: from, - Gas: rpc.NewHexNumber(tx.Gas()), - GasPrice: rpc.NewHexNumber(tx.GasPrice()), + Gas: (*hexutil.Big)(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), Hash: tx.Hash(), - Input: rpc.HexBytes(tx.Data()), - Nonce: rpc.NewHexNumber(tx.Nonce()), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), To: tx.To(), - TransactionIndex: rpc.NewHexNumber(txIndex), - Value: rpc.NewHexNumber(tx.Value()), - V: rpc.NewHexNumber(v), - R: rpc.NewHexNumber(r), - S: rpc.NewHexNumber(s), + TransactionIndex: hexutil.Uint(txIndex), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), }, nil } @@ -760,8 +747,8 @@ func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransacti } // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. -func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex int) (rpc.HexBytes, error) { - if txIndex >= 0 && txIndex < len(b.Transactions()) { +func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex uint) (hexutil.Bytes, error) { + if txIndex < uint(len(b.Transactions())) { tx := b.Transactions()[txIndex] return rlp.EncodeToBytes(tx) } @@ -773,7 +760,7 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, txIndex int) (rpc.HexByt func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, error) { for idx, tx := range b.Transactions() { if tx.Hash() == txHash { - return newRPCTransactionFromBlockIndex(b, idx) + return newRPCTransactionFromBlockIndex(b, uint(idx)) } } @@ -809,55 +796,57 @@ func getTransaction(chainDb ethdb.Database, b Backend, txHash common.Hash) (*typ } // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. -func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *rpc.HexNumber { +func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return rpc.NewHexNumber(len(block.Transactions())) + n := hexutil.Uint(len(block.Transactions())) + return &n } return nil } // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. -func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *rpc.HexNumber { +func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return rpc.NewHexNumber(len(block.Transactions())) + n := hexutil.Uint(len(block.Transactions())) + return &n } return nil } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (*RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (*RPCTransaction, error) { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, index.Int()) + return newRPCTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (*RPCTransaction, error) { +func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (*RPCTransaction, error) { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, index.Int()) + return newRPCTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. -func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index rpc.HexNumber) (rpc.HexBytes, error) { +func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (hexutil.Bytes, error) { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCRawTransactionFromBlockIndex(block, index.Int()) + return newRPCRawTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. -func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index rpc.HexNumber) (rpc.HexBytes, error) { +func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (hexutil.Bytes, error) { if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { - return newRPCRawTransactionFromBlockIndex(block, index.Int()) + return newRPCRawTransactionFromBlockIndex(block, uint(index)) } return nil, nil } // GetTransactionCount returns the number of transactions the given address has sent for the given block number -func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*rpc.HexNumber, error) { +func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { return nil, err @@ -866,7 +855,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr if err != nil { return nil, err } - return rpc.NewHexNumber(nonce), nil + return (*hexutil.Uint64)(&nonce), nil } // getTransactionBlockData fetches the meta data for the given transaction from the chain database. This is useful to @@ -922,7 +911,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, txH } // GetRawTransactionByHash returns the bytes of the transaction for the given hash. -func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, txHash common.Hash) (rpc.HexBytes, error) { +func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, txHash common.Hash) (hexutil.Bytes, error) { var tx *types.Transaction var err error @@ -963,21 +952,21 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma from, _ := types.Sender(signer, tx) fields := map[string]interface{}{ - "root": rpc.HexBytes(receipt.PostState), + "root": hexutil.Bytes(receipt.PostState), "blockHash": txBlock, - "blockNumber": rpc.NewHexNumber(blockIndex), + "blockNumber": hexutil.Uint64(blockIndex), "transactionHash": txHash, - "transactionIndex": rpc.NewHexNumber(index), + "transactionIndex": hexutil.Uint64(index), "from": from, "to": tx.To(), - "gasUsed": rpc.NewHexNumber(receipt.GasUsed), - "cumulativeGasUsed": rpc.NewHexNumber(receipt.CumulativeGasUsed), + "gasUsed": (*hexutil.Big)(receipt.GasUsed), + "cumulativeGasUsed": (*hexutil.Big)(receipt.CumulativeGasUsed), "contractAddress": nil, "logs": receipt.Logs, "logsBloom": receipt.Bloom, } if receipt.Logs == nil { - fields["logs"] = []vm.Logs{} + fields["logs"] = [][]*types.Log{} } // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation if receipt.ContractAddress != (common.Address{}) { @@ -990,7 +979,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) - signature, err := s.b.AccountManager().SignEthereum(addr, signer.Hash(tx).Bytes()) + signature, err := s.b.AccountManager().Sign(addr, signer.Hash(tx).Bytes()) if err != nil { return nil, err } @@ -1001,32 +990,46 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti type SendTxArgs struct { From common.Address `json:"from"` To *common.Address `json:"to"` - Gas *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - Nonce *rpc.HexNumber `json:"nonce"` + Gas *hexutil.Big `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + Value *hexutil.Big `json:"value"` + Data hexutil.Bytes `json:"data"` + Nonce *hexutil.Uint64 `json:"nonce"` } // prepareSendTxArgs is a helper function that fills in default values for unspecified tx fields. -func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxArgs, error) { +func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { if args.Gas == nil { - args.Gas = rpc.NewHexNumber(defaultGas) + args.Gas = (*hexutil.Big)(big.NewInt(defaultGas)) } if args.GasPrice == nil { price, err := b.SuggestPrice(ctx) if err != nil { - return args, err + return err } - args.GasPrice = rpc.NewHexNumber(price) + args.GasPrice = (*hexutil.Big)(price) } if args.Value == nil { - args.Value = rpc.NewHexNumber(0) + args.Value = new(hexutil.Big) } - return args, nil + if args.Nonce == nil { + nonce, err := b.GetPoolNonce(ctx, args.From) + if err != nil { + return err + } + args.Nonce = (*hexutil.Uint64)(&nonce) + } + return nil } -// submitTransaction is a helper function that submits tx to txPool and creates a log entry. +func (args *SendTxArgs) toTransaction() *types.Transaction { + if args.To == nil { + return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) + } + return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) +} + +// submitTransaction is a helper function that submits tx to txPool and logs a message. func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) { signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number()) @@ -1053,41 +1056,23 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, si // SendTransaction creates a transaction for the given argument, sign it and submit it to the // transaction pool. func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) { - var err error - args, err = prepareSendTxArgs(ctx, args, s.b) - if err != nil { + if err := args.setDefaults(ctx, s.b); err != nil { return common.Hash{}, err } - - if args.Nonce == nil { - nonce, err := s.b.GetPoolNonce(ctx, args.From) - if err != nil { - return common.Hash{}, err - } - args.Nonce = rpc.NewHexNumber(nonce) - } - - var tx *types.Transaction - if args.To == nil { - tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } else { - tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } - + tx := args.toTransaction() signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) - signature, err := s.b.AccountManager().SignEthereum(args.From, signer.Hash(tx).Bytes()) + signature, err := s.b.AccountManager().Sign(args.From, signer.Hash(tx).Bytes()) if err != nil { return common.Hash{}, err } - return submitTransaction(ctx, s.b, tx, signature) } // SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. -func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx string) (string, error) { +func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (string, error) { tx := new(types.Transaction) - if err := rlp.DecodeBytes(common.FromHex(encodedTx), tx); err != nil { + if err := rlp.DecodeBytes(encodedTx, tx); err != nil { return "", err } @@ -1113,168 +1098,52 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod // Sign calculates an ECDSA signature for: // keccack256("\x19Ethereum Signed Message:\n" + len(message) + message). // +// Note, the produced signature conforms to the secp256k1 curve R, S and V values, +// where the V value will be 27 or 28 for legacy reasons. +// // The account associated with addr must be unlocked. // // https://github.com/ubiq/wiki/wiki/JSON-RPC#eth_sign -func (s *PublicTransactionPoolAPI) Sign(addr common.Address, message string) (string, error) { - hash := signHash(message) - signature, err := s.b.AccountManager().SignEthereum(addr, hash) - return common.ToHex(signature), err -} - -// SignTransactionArgs represents the arguments to sign a transaction. -type SignTransactionArgs struct { - From common.Address - To *common.Address - Nonce *rpc.HexNumber - Value *rpc.HexNumber - Gas *rpc.HexNumber - GasPrice *rpc.HexNumber - Data string - - BlockNumber int64 -} - -// Tx is a helper object for argument and return values -type Tx struct { - tx *types.Transaction - - To *common.Address `json:"to"` - From common.Address `json:"from"` - Nonce *rpc.HexNumber `json:"nonce"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - GasLimit *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Hash common.Hash `json:"hash"` -} - -// UnmarshalJSON parses JSON data into tx. -func (tx *Tx) UnmarshalJSON(b []byte) (err error) { - req := struct { - To *common.Address `json:"to"` - From common.Address `json:"from"` - Nonce *rpc.HexNumber `json:"nonce"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - GasLimit *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Hash common.Hash `json:"hash"` - }{} - - if err := json.Unmarshal(b, &req); err != nil { - return err +func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { + signature, err := s.b.AccountManager().Sign(addr, signHash(data)) + if err == nil { + signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper } - - tx.To = req.To - tx.From = req.From - tx.Nonce = req.Nonce - tx.Value = req.Value - tx.Data = req.Data - tx.GasLimit = req.GasLimit - tx.GasPrice = req.GasPrice - tx.Hash = req.Hash - - data := common.Hex2Bytes(tx.Data) - - if tx.Nonce == nil { - return fmt.Errorf("need nonce") - } - if tx.Value == nil { - tx.Value = rpc.NewHexNumber(0) - } - if tx.GasLimit == nil { - tx.GasLimit = rpc.NewHexNumber(0) - } - if tx.GasPrice == nil { - tx.GasPrice = rpc.NewHexNumber(int64(50000000000)) - } - - if req.To == nil { - tx.tx = types.NewContractCreation(tx.Nonce.Uint64(), tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) - } else { - tx.tx = types.NewTransaction(tx.Nonce.Uint64(), *tx.To, tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) - } - - return nil + return signature, err } // SignTransactionResult represents a RLP encoded signed transaction. type SignTransactionResult struct { - Raw string `json:"raw"` - Tx *Tx `json:"tx"` -} - -func newTx(t *types.Transaction) *Tx { - var signer types.Signer = types.HomesteadSigner{} - if t.Protected() { - signer = types.NewEIP155Signer(t.ChainId()) - } - - from, _ := types.Sender(signer, t) - return &Tx{ - tx: t, - To: t.To(), - From: from, - Value: rpc.NewHexNumber(t.Value()), - Nonce: rpc.NewHexNumber(t.Nonce()), - Data: "0x" + common.Bytes2Hex(t.Data()), - GasLimit: rpc.NewHexNumber(t.Gas()), - GasPrice: rpc.NewHexNumber(t.GasPrice()), - Hash: t.Hash(), - } + Raw hexutil.Bytes `json:"raw"` + Tx *types.Transaction `json:"tx"` } // SignTransaction will sign the given transaction with the from account. // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. -func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args SignTransactionArgs) (*SignTransactionResult, error) { - if args.Gas == nil { - args.Gas = rpc.NewHexNumber(defaultGas) +func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) { + if err := args.setDefaults(ctx, s.b); err != nil { + return nil, err } - if args.GasPrice == nil { - price, err := s.b.SuggestPrice(ctx) - if err != nil { - return nil, err - } - args.GasPrice = rpc.NewHexNumber(price) - } - if args.Value == nil { - args.Value = rpc.NewHexNumber(0) - } - - if args.Nonce == nil { - nonce, err := s.b.GetPoolNonce(ctx, args.From) - if err != nil { - return nil, err - } - args.Nonce = rpc.NewHexNumber(nonce) - } - - var tx *types.Transaction - if args.To == nil { - tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } else { - tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) - } - - signedTx, err := s.sign(args.From, tx) + tx, err := s.sign(args.From, args.toTransaction()) if err != nil { return nil, err } - - data, err := rlp.EncodeToBytes(signedTx) + data, err := rlp.EncodeToBytes(tx) if err != nil { return nil, err } - - return &SignTransactionResult{"0x" + common.Bytes2Hex(data), newTx(signedTx)}, nil + return &SignTransactionResult{data, tx}, nil } // PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of // the accounts this node manages. -func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction { - pending := s.b.GetPoolTransactions() +func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { + pending, err := s.b.GetPoolTransactions() + if err != nil { + return nil, err + } + transactions := make([]*RPCTransaction, 0, len(pending)) for _, tx := range pending { var signer types.Signer = types.HomesteadSigner{} @@ -1286,49 +1155,52 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction { transactions = append(transactions, newRPCPendingTransaction(tx)) } } - return transactions + return transactions, nil } -// Resend accepts an existing transaction and a new gas price and limit. It will remove the given transaction from the -// pool and reinsert it with the new gas price and limit. -func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) { - pending := s.b.GetPoolTransactions() +// Resend accepts an existing transaction and a new gas price and limit. It will remove +// the given transaction from the pool and reinsert it with the new gas price and limit. +func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxArgs, gasPrice, gasLimit *hexutil.Big) (common.Hash, error) { + if sendArgs.Nonce == nil { + return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec") + } + if err := sendArgs.setDefaults(ctx, s.b); err != nil { + return common.Hash{}, err + } + matchTx := sendArgs.toTransaction() + pending, err := s.b.GetPoolTransactions() + if err != nil { + return common.Hash{}, err + } + for _, p := range pending { var signer types.Signer = types.HomesteadSigner{} if p.Protected() { signer = types.NewEIP155Signer(p.ChainId()) } + wantSigHash := signer.Hash(matchTx) - if pFrom, err := types.Sender(signer, p); err == nil && pFrom == tx.From && signer.Hash(p) == signer.Hash(tx.tx) { - if gasPrice == nil { - gasPrice = rpc.NewHexNumber(tx.tx.GasPrice()) + if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash { + // Match. Re-sign and send the transaction. + if gasPrice != nil { + sendArgs.GasPrice = gasPrice } - if gasLimit == nil { - gasLimit = rpc.NewHexNumber(tx.tx.Gas()) + if gasLimit != nil { + sendArgs.Gas = gasLimit } - - var newTx *types.Transaction - if tx.tx.To() == nil { - newTx = types.NewContractCreation(tx.tx.Nonce(), tx.tx.Value(), gasLimit.BigInt(), gasPrice.BigInt(), tx.tx.Data()) - } else { - newTx = types.NewTransaction(tx.tx.Nonce(), *tx.tx.To(), tx.tx.Value(), gasLimit.BigInt(), gasPrice.BigInt(), tx.tx.Data()) - } - - signedTx, err := s.sign(tx.From, newTx) + signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction()) if err != nil { return common.Hash{}, err } - - s.b.RemoveTx(tx.Hash) + s.b.RemoveTx(p.Hash()) if err = s.b.SendTx(ctx, signedTx); err != nil { return common.Hash{}, err } - return signedTx.Hash(), nil } } - return common.Hash{}, fmt.Errorf("Transaction %#x not found", tx.Hash) + return common.Hash{}, fmt.Errorf("Transaction %#x not found", matchTx.Hash()) } // PublicDebugAPI is the collection of Etheruem APIs exposed over the public @@ -1425,8 +1297,8 @@ func (api *PrivateDebugAPI) ChaindbCompact() error { } // SetHead rewinds the head of the blockchain to a previous block. -func (api *PrivateDebugAPI) SetHead(number rpc.HexNumber) { - api.b.SetHead(uint64(number.Int64())) +func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) { + api.b.SetHead(uint64(number)) } // PublicNetAPI offers network related RPC methods @@ -1446,8 +1318,8 @@ func (s *PublicNetAPI) Listening() bool { } // PeerCount returns the number of connected peers -func (s *PublicNetAPI) PeerCount() *rpc.HexNumber { - return rpc.NewHexNumber(s.net.PeerCount()) +func (s *PublicNetAPI) PeerCount() hexutil.Uint { + return hexutil.Uint(s.net.PeerCount()) } // Version returns the current ubiq protocol version. diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 6376a51635..759e235ef2 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -51,11 +51,11 @@ type Backend interface { GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetTd(blockHash common.Hash) *big.Int - GetVMEnv(ctx context.Context, msg core.Message, state State, header *types.Header) (vm.Environment, func() error, error) + GetVMEnv(ctx context.Context, msg core.Message, state State, header *types.Header) (*vm.EVM, func() error, error) // TxPool API SendTx(ctx context.Context, signedTx *types.Transaction) error RemoveTx(txHash common.Hash) - GetPoolTransactions() types.Transactions + GetPoolTransactions() (types.Transactions, error) GetPoolTransaction(txHash common.Hash) *types.Transaction GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) Stats() (pending int, queued int) diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go index cbf6b69d2b..d0a53c418d 100644 --- a/internal/ethapi/tracer.go +++ b/internal/ethapi/tracer.go @@ -124,7 +124,7 @@ func (sw *stackWrapper) toValue(vm *otto.Otto) otto.Value { // dbWrapper provides a JS wrapper around vm.Database type dbWrapper struct { - db vm.Database + db vm.StateDB } // getBalance retrieves an account's balance @@ -278,11 +278,11 @@ func wrapError(context string, err error) error { } // CaptureState implements the Tracer interface to trace a single step of VM execution -func (jst *JavascriptTracer) CaptureState(env vm.Environment, pc uint64, op vm.OpCode, gas, cost *big.Int, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { +func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost *big.Int, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { if jst.err == nil { jst.memory.memory = memory jst.stack.stack = stack - jst.db.db = env.Db() + jst.db.db = env.StateDB ocw := &opCodeWrapper{op} diff --git a/internal/ethapi/tracer_test.go b/internal/ethapi/tracer_test.go index fbce039ef5..cc8d69b1ef 100644 --- a/internal/ethapi/tracer_test.go +++ b/internal/ethapi/tracer_test.go @@ -25,62 +25,9 @@ import ( "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" ) -type Env struct { - gasLimit *big.Int - depth int - evm *vm.EVM -} - -func NewEnv(config *vm.Config) *Env { - env := &Env{gasLimit: big.NewInt(10000), depth: 0} - env.evm = vm.New(env, *config) - return env -} - -func (self *Env) ChainConfig() *params.ChainConfig { - return params.TestChainConfig -} -func (self *Env) Vm() vm.Vm { return self.evm } -func (self *Env) Origin() common.Address { return common.Address{} } -func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) } - -//func (self *Env) PrevHash() []byte { return self.parent } -func (self *Env) Coinbase() common.Address { return common.Address{} } -func (self *Env) SnapshotDatabase() int { return 0 } -func (self *Env) RevertToSnapshot(int) {} -func (self *Env) Time() *big.Int { return big.NewInt(time.Now().Unix()) } -func (self *Env) Difficulty() *big.Int { return big.NewInt(0) } -func (self *Env) Db() vm.Database { return nil } -func (self *Env) GasLimit() *big.Int { return self.gasLimit } -func (self *Env) VmType() vm.Type { return vm.StdVmTy } -func (self *Env) GetHash(n uint64) common.Hash { - return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) -} -func (self *Env) AddLog(log *vm.Log) { -} -func (self *Env) Depth() int { return self.depth } -func (self *Env) SetDepth(i int) { self.depth = i } -func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool { - return true -} -func (self *Env) Transfer(from, to vm.Account, amount *big.Int) {} -func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return nil, nil -} -func (self *Env) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return nil, nil -} -func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - return nil, common.Address{}, nil -} -func (self *Env) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - return nil, nil -} - type account struct{} func (account) SubBalance(amount *big.Int) {} @@ -91,17 +38,17 @@ func (account) SetBalance(*big.Int) {} func (account) SetNonce(uint64) {} func (account) Balance() *big.Int { return nil } func (account) Address() common.Address { return common.Address{} } -func (account) ReturnGas(*big.Int, *big.Int) {} +func (account) ReturnGas(*big.Int) {} func (account) SetCode(common.Hash, []byte) {} func (account) ForEachStorage(cb func(key, value common.Hash) bool) {} func runTrace(tracer *JavascriptTracer) (interface{}, error) { - env := NewEnv(&vm.Config{Debug: true, Tracer: tracer}) + env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) - contract := vm.NewContract(account{}, account{}, big.NewInt(0), env.GasLimit(), big.NewInt(1)) + contract := vm.NewContract(account{}, account{}, big.NewInt(0), big.NewInt(10000)) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} - _, err := env.Vm().Run(contract, []byte{}) + _, err := env.Interpreter().Run(contract, []byte{}) if err != nil { return nil, err } @@ -186,8 +133,8 @@ func TestHaltBetweenSteps(t *testing.T) { t.Fatal(err) } - env := NewEnv(&vm.Config{Debug: true, Tracer: tracer}) - contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), big.NewInt(0), big.NewInt(0)) + env := vm.NewEVM(vm.Context{}, nil, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), big.NewInt(0)) tracer.CaptureState(env, 0, 0, big.NewInt(0), big.NewInt(0), nil, nil, contract, 0, nil) timeout := errors.New("stahp") diff --git a/internal/jsre/bignumber_js.go b/internal/jsre/deps/bignumber.js similarity index 94% rename from internal/jsre/bignumber_js.go rename to internal/jsre/deps/bignumber.js index 2e9c74c9f2..17c8851e24 100644 --- a/internal/jsre/bignumber_js.go +++ b/internal/jsre/deps/bignumber.js @@ -1,22 +1,4 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package jsre - -const BigNumber_JS = `/* bignumber.js v2.0.3 https://github.com/MikeMcl/bignumber.js/LICENCE */ +/* bignumber.js v2.0.3 https://github.com/MikeMcl/bignumber.js/LICENCE */ /* modified by zelig to fix https://github.com/robertkrimen/otto#regular-expression-incompatibility */ !function(e){"use strict";function n(e){function a(e,n){var t,r,i,o,u,s,f=this;if(!(f instanceof a))return j&&L(26,"constructor call without new",e),new a(e,n);if(null!=n&&H(n,2,64,M,"base")){if(n=0|n,s=e+"",10==n)return f=new a(e instanceof a?e:s),U(f,P+f.e+1,k);if((o="number"==typeof e)&&0*e!=0||!new RegExp("^-?"+(t="["+O.slice(0,n)+"]+")+"(?:\\."+t+")?$",37>n?"i":"").test(s))return g(f,s,o,n);o?(f.s=0>1/e?(s=s.slice(1),-1):1,j&&s.replace(/^0\.0*|\./,"").length>15&&L(M,b,e),o=!1):f.s=45===s.charCodeAt(0)?(s=s.slice(1),-1):1,s=D(s,10,n,f.s)}else{if(e instanceof a)return f.s=e.s,f.e=e.e,f.c=(e=e.c)?e.slice():e,void(M=0);if((o="number"==typeof e)&&0*e==0){if(f.s=0>1/e?(e=-e,-1):1,e===~~e){for(r=0,i=e;i>=10;i/=10,r++);return f.e=r,f.c=[e],void(M=0)}s=e+""}else{if(!p.test(s=e+""))return g(f,s,o);f.s=45===s.charCodeAt(0)?(s=s.slice(1),-1):1}}for((r=s.indexOf("."))>-1&&(s=s.replace(".","")),(i=s.search(/e/i))>0?(0>r&&(r=i),r+=+s.slice(i+1),s=s.substring(0,i)):0>r&&(r=s.length),i=0;48===s.charCodeAt(i);i++);for(u=s.length;48===s.charCodeAt(--u););if(s=s.slice(i,u+1))if(u=s.length,o&&j&&u>15&&L(M,b,f.s*e),r=r-i-1,r>z)f.c=f.e=null;else if(G>r)f.c=[f.e=0];else{if(f.e=r,f.c=[],i=(r+1)%y,0>r&&(i+=y),u>i){for(i&&f.c.push(+s.slice(0,i)),u-=y;u>i;)f.c.push(+s.slice(i,i+=y));s=s.slice(i),i=y-s.length}else i-=u;for(;i--;s+="0");f.c.push(+s)}else f.c=[f.e=0];M=0}function D(e,n,t,i){var o,u,f,c,h,g,p,d=e.indexOf("."),m=P,w=k;for(37>t&&(e=e.toLowerCase()),d>=0&&(f=J,J=0,e=e.replace(".",""),p=new a(t),h=p.pow(e.length-d),J=f,p.c=s(l(r(h.c),h.e),10,n),p.e=p.c.length),g=s(e,t,n),u=f=g.length;0==g[--f];g.pop());if(!g[0])return"0";if(0>d?--u:(h.c=g,h.e=u,h.s=i,h=C(h,p,m,w,n),g=h.c,c=h.r,u=h.e),o=u+m+1,d=g[o],f=n/2,c=c||0>o||null!=g[o+1],c=4>w?(null!=d||c)&&(0==w||w==(h.s<0?3:2)):d>f||d==f&&(4==w||c||6==w&&1&g[o-1]||w==(h.s<0?8:7)),1>o||!g[0])e=c?l("1",-m):"0";else{if(g.length=o,c)for(--n;++g[--o]>n;)g[o]=0,o||(++u,g.unshift(1));for(f=g.length;!g[--f];);for(d=0,e="";f>=d;e+=O.charAt(g[d++]));e=l(e,u)}return e}function _(e,n,t,i){var o,u,s,c,h;if(t=null!=t&&H(t,0,8,i,v)?0|t:k,!e.c)return e.toString();if(o=e.c[0],s=e.e,null==n)h=r(e.c),h=19==i||24==i&&B>=s?f(h,s):l(h,s);else if(e=U(new a(e),n,t),u=e.e,h=r(e.c),c=h.length,19==i||24==i&&(u>=n||B>=u)){for(;n>c;h+="0",c++);h=f(h,u)}else if(n-=s,h=l(h,u),u+1>c){if(--n>0)for(h+=".";n--;h+="0");}else if(n+=u-c,n>0)for(u+1==c&&(h+=".");n--;h+="0");return e.s<0&&o?"-"+h:h}function x(e,n){var t,r,i=0;for(u(e[0])&&(e=e[0]),t=new a(e[0]);++ie||e>t||e!=c(e))&&L(r,(i||"decimal places")+(n>e||e>t?" out of range":" not an integer"),e),!0}function I(e,n,t){for(var r=1,i=n.length;!n[--i];n.pop());for(i=n[0];i>=10;i/=10,r++);return(t=r+t*y-1)>z?e.c=e.e=null:G>t?e.c=[e.e=0]:(e.e=t,e.c=n),e}function L(e,n,t){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][e]+"() "+n+": "+t);throw r.name="BigNumber Error",M=0,r}function U(e,n,t,r){var i,o,u,s,f,l,c,a=e.c,h=R;if(a){e:{for(i=1,s=a[0];s>=10;s/=10,i++);if(o=n-i,0>o)o+=y,u=n,f=a[l=0],c=f/h[i-u-1]%10|0;else if(l=d((o+1)/y),l>=a.length){if(!r)break e;for(;a.length<=l;a.push(0));f=c=0,i=1,o%=y,u=o-y+1}else{for(f=s=a[l],i=1;s>=10;s/=10,i++);o%=y,u=o-y+i,c=0>u?0:f/h[i-u-1]%10|0}if(r=r||0>n||null!=a[l+1]||(0>u?f:f%h[i-u-1]),r=4>t?(c||r)&&(0==t||t==(e.s<0?3:2)):c>5||5==c&&(4==t||r||6==t&&(o>0?u>0?f/h[i-u]:0:a[l-1])%10&1||t==(e.s<0?8:7)),1>n||!a[0])return a.length=0,r?(n-=e.e+1,a[0]=h[n%y],e.e=-n||0):a[0]=e.e=0,e;if(0==o?(a.length=l,s=1,l--):(a.length=l+1,s=h[y-o],a[l]=u>0?m(f/h[i-u]%h[u])*s:0),r)for(;;){if(0==l){for(o=1,u=a[0];u>=10;u/=10,o++);for(u=a[0]+=s,s=1;u>=10;u/=10,s++);o!=s&&(e.e++,a[0]==N&&(a[0]=1));break}if(a[l]+=s,a[l]!=N)break;a[l--]=0,s=1}for(o=a.length;0===a[--o];a.pop());}e.e>z?e.c=e.e=null:e.et?null!=(e=i[t++]):void 0};return f(n="DECIMAL_PLACES")&&H(e,0,E,2,n)&&(P=0|e),r[n]=P,f(n="ROUNDING_MODE")&&H(e,0,8,2,n)&&(k=0|e),r[n]=k,f(n="EXPONENTIAL_AT")&&(u(e)?H(e[0],-E,0,2,n)&&H(e[1],0,E,2,n)&&(B=0|e[0],$=0|e[1]):H(e,-E,E,2,n)&&(B=-($=0|(0>e?-e:e)))),r[n]=[B,$],f(n="RANGE")&&(u(e)?H(e[0],-E,-1,2,n)&&H(e[1],1,E,2,n)&&(G=0|e[0],z=0|e[1]):H(e,-E,E,2,n)&&(0|e?G=-(z=0|(0>e?-e:e)):j&&L(2,n+" cannot be zero",e))),r[n]=[G,z],f(n="ERRORS")&&(e===!!e||1===e||0===e?(M=0,H=(j=!!e)?F:o):j&&L(2,n+w,e)),r[n]=j,f(n="CRYPTO")&&(e===!!e||1===e||0===e?(V=!(!e||!h||"object"!=typeof h),e&&!V&&j&&L(2,"crypto unavailable",h)):j&&L(2,n+w,e)),r[n]=V,f(n="MODULO_MODE")&&H(e,0,9,2,n)&&(W=0|e),r[n]=W,f(n="POW_PRECISION")&&H(e,0,E,2,n)&&(J=0|e),r[n]=J,f(n="FORMAT")&&("object"==typeof e?X=e:j&&L(2,n+" not an object",e)),r[n]=X,r},a.max=function(){return x(arguments,T.lt)},a.min=function(){return x(arguments,T.gt)},a.random=function(){var e=9007199254740992,n=Math.random()*e&2097151?function(){return m(Math.random()*e)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(e){var t,r,i,o,u,s=0,f=[],l=new a(q);if(e=null!=e&&H(e,0,E,14)?0|e:P,o=d(e/y),V)if(h&&h.getRandomValues){for(t=h.getRandomValues(new Uint32Array(o*=2));o>s;)u=131072*t[s]+(t[s+1]>>>11),u>=9e15?(r=h.getRandomValues(new Uint32Array(2)),t[s]=r[0],t[s+1]=r[1]):(f.push(u%1e14),s+=2);s=o/2}else if(h&&h.randomBytes){for(t=h.randomBytes(o*=7);o>s;)u=281474976710656*(31&t[s])+1099511627776*t[s+1]+4294967296*t[s+2]+16777216*t[s+3]+(t[s+4]<<16)+(t[s+5]<<8)+t[s+6],u>=9e15?h.randomBytes(7).copy(t,s):(f.push(u%1e14),s+=7);s=o/7}else j&&L(14,"crypto unavailable",h);if(!s)for(;o>s;)u=n(),9e15>u&&(f[s++]=u%1e14);for(o=f[--s],e%=y,o&&e&&(u=R[y-e],f[s]=m(o/u)*u);0===f[s];f.pop(),s--);if(0>s)f=[i=0];else{for(i=-1;0===f[0];f.shift(),i-=y);for(s=1,u=f[0];u>=10;u/=10,s++);y>s&&(i-=y-s)}return l.e=i,l.c=f,l}}(),C=function(){function e(e,n,t){var r,i,o,u,s=0,f=e.length,l=n%A,c=n/A|0;for(e=e.slice();f--;)o=e[f]%A,u=e[f]/A|0,r=c*o+u*l,i=l*o+r%A*A+s,s=(i/t|0)+(r/A|0)+c*u,e[f]=i%t;return s&&e.unshift(s),e}function n(e,n,t,r){var i,o;if(t!=r)o=t>r?1:-1;else for(i=o=0;t>i;i++)if(e[i]!=n[i]){o=e[i]>n[i]?1:-1;break}return o}function r(e,n,t,r){for(var i=0;t--;)e[t]-=i,i=e[t]1;e.shift());}return function(i,o,u,s,f){var l,c,h,g,p,d,w,v,b,O,S,R,A,E,D,_,x,F=i.s==o.s?1:-1,I=i.c,L=o.c;if(!(I&&I[0]&&L&&L[0]))return new a(i.s&&o.s&&(I?!L||I[0]!=L[0]:L)?I&&0==I[0]||!L?0*F:F/0:0/0);for(v=new a(F),b=v.c=[],c=i.e-o.e,F=u+c+1,f||(f=N,c=t(i.e/y)-t(o.e/y),F=F/y|0),h=0;L[h]==(I[h]||0);h++);if(L[h]>(I[h]||0)&&c--,0>F)b.push(1),g=!0;else{for(E=I.length,_=L.length,h=0,F+=2,p=m(f/(L[0]+1)),p>1&&(L=e(L,p,f),I=e(I,p,f),_=L.length,E=I.length),A=_,O=I.slice(0,_),S=O.length;_>S;O[S++]=0);x=L.slice(),x.unshift(0),D=L[0],L[1]>=f/2&&D++;do p=0,l=n(L,O,_,S),0>l?(R=O[0],_!=S&&(R=R*f+(O[1]||0)),p=m(R/D),p>1?(p>=f&&(p=f-1),d=e(L,p,f),w=d.length,S=O.length,l=n(d,O,w,S),1==l&&(p--,r(d,w>_?x:L,w,f))):(0==p&&(l=p=1),d=L.slice()),w=d.length,S>w&&d.unshift(0),r(O,d,S,f),-1==l&&(S=O.length,l=n(L,O,_,S),1>l&&(p++,r(O,S>_?x:L,S,f))),S=O.length):0===l&&(p++,O=[0]),b[h++]=p,l&&O[0]?O[S++]=I[A]||0:(O=[I[A]],S=1);while((A++=10;F/=10,h++);U(v,u+(v.e=h+c*y-1)+1,s,g)}else v.e=c,v.r=+g;return v}}(),g=function(){var e=/^(-?)0([xbo])(\w[\w.]*$)/i,n=/^([^.]+)\.$/,t=/^\.([^.]+)$/,r=/^-?(Infinity|NaN)$/,i=/^\s*\+([\w.])|^\s+|\s+$/g;return function(o,u,s,f){var l,c=s?u:u.replace(i,"$1");if(r.test(c))o.s=isNaN(c)?null:0>c?-1:1;else{if(!s&&(c=c.replace(e,function(e,n,t){return l="x"==(t=t.toLowerCase())?16:"b"==t?2:8,f&&f!=l?e:n}),f&&(l=f,c=c.replace(n,"$1").replace(t,"0.$1")),u!=c))return new a(c,l);j&&L(M,"not a"+(f?" base "+f:"")+" number",u),o.s=null}o.c=o.e=null,M=0}}(),T.absoluteValue=T.abs=function(){var e=new a(this);return e.s<0&&(e.s=1),e},T.ceil=function(){return U(new a(this),this.e+1,2)},T.comparedTo=T.cmp=function(e,n){return M=1,i(this,new a(e,n))},T.decimalPlaces=T.dp=function(){var e,n,r=this.c;if(!r)return null;if(e=((n=r.length-1)-t(this.e/y))*y,n=r[n])for(;n%10==0;n/=10,e--);return 0>e&&(e=0),e},T.dividedBy=T.div=function(e,n){return M=3,C(this,new a(e,n),P,k)},T.dividedToIntegerBy=T.divToInt=function(e,n){return M=4,C(this,new a(e,n),0,1)},T.equals=T.eq=function(e,n){return M=5,0===i(this,new a(e,n))},T.floor=function(){return U(new a(this),this.e+1,3)},T.greaterThan=T.gt=function(e,n){return M=6,i(this,new a(e,n))>0},T.greaterThanOrEqualTo=T.gte=function(e,n){return M=7,1===(n=i(this,new a(e,n)))||0===n},T.isFinite=function(){return!!this.c},T.isInteger=T.isInt=function(){return!!this.c&&t(this.e/y)>this.c.length-2},T.isNaN=function(){return!this.s},T.isNegative=T.isNeg=function(){return this.s<0},T.isZero=function(){return!!this.c&&0==this.c[0]},T.lessThan=T.lt=function(e,n){return M=8,i(this,new a(e,n))<0},T.lessThanOrEqualTo=T.lte=function(e,n){return M=9,-1===(n=i(this,new a(e,n)))||0===n},T.minus=T.sub=function(e,n){var r,i,o,u,s=this,f=s.s;if(M=10,e=new a(e,n),n=e.s,!f||!n)return new a(0/0);if(f!=n)return e.s=-n,s.plus(e);var l=s.e/y,c=e.e/y,h=s.c,g=e.c;if(!l||!c){if(!h||!g)return h?(e.s=-n,e):new a(g?s:0/0);if(!h[0]||!g[0])return g[0]?(e.s=-n,e):new a(h[0]?s:3==k?-0:0)}if(l=t(l),c=t(c),h=h.slice(),f=l-c){for((u=0>f)?(f=-f,o=h):(c=l,o=g),o.reverse(),n=f;n--;o.push(0));o.reverse()}else for(i=(u=(f=h.length)<(n=g.length))?f:n,f=n=0;i>n;n++)if(h[n]!=g[n]){u=h[n]0)for(;n--;h[r++]=0);for(n=N-1;i>f;){if(h[--i]0?(s=u,r=l):(o=-o,r=f),r.reverse();o--;r.push(0));r.reverse()}for(o=f.length,n=l.length,0>o-n&&(r=l,l=f,f=r,n=o),o=0;n;)o=(f[--n]=f[n]+l[n]+o)/N|0,f[n]%=N;return o&&(f.unshift(o),++s),I(e,f,s)},T.precision=T.sd=function(e){var n,t,r=this,i=r.c;if(null!=e&&e!==!!e&&1!==e&&0!==e&&(j&&L(13,"argument"+w,e),e!=!!e&&(e=null)),!i)return null;if(t=i.length-1,n=t*y+1,t=i[t]){for(;t%10==0;t/=10,n--);for(t=i[0];t>=10;t/=10,n++);}return e&&r.e+1>n&&(n=r.e+1),n},T.round=function(e,n){var t=new a(this);return(null==e||H(e,0,E,15))&&U(t,~~e+this.e+1,null!=n&&H(n,0,8,15,v)?0|n:k),t},T.shift=function(e){var n=this;return H(e,-S,S,16,"argument")?n.times("1e"+c(e)):new a(n.c&&n.c[0]&&(-S>e||e>S)?n.s*(0>e?0:1/0):n)},T.squareRoot=T.sqrt=function(){var e,n,i,o,u,s=this,f=s.c,l=s.s,c=s.e,h=P+4,g=new a("0.5");if(1!==l||!f||!f[0])return new a(!l||0>l&&(!f||f[0])?0/0:f?s:1/0);if(l=Math.sqrt(+s),0==l||l==1/0?(n=r(f),(n.length+c)%2==0&&(n+="0"),l=Math.sqrt(n),c=t((c+1)/2)-(0>c||c%2),l==1/0?n="1e"+c:(n=l.toExponential(),n=n.slice(0,n.indexOf("e")+1)+c),i=new a(n)):i=new a(l+""),i.c[0])for(c=i.e,l=c+h,3>l&&(l=0);;)if(u=i,i=g.times(u.plus(C(s,u,h,1))),r(u.c).slice(0,l)===(n=r(i.c)).slice(0,l)){if(i.el&&(m=O,O=S,S=m,o=l,l=g,g=o),o=l+g,m=[];o--;m.push(0));for(w=N,v=A,o=g;--o>=0;){for(r=0,p=S[o]%v,d=S[o]/v|0,s=l,u=o+s;u>o;)c=O[--s]%v,h=O[s]/v|0,f=d*c+h*p,c=p*c+f%v*v+m[u]+r,r=(c/w|0)+(f/v|0)+d*h,m[u--]=c%w;m[u]=r}return r?++i:m.shift(),I(e,m,i)},T.toDigits=function(e,n){var t=new a(this);return e=null!=e&&H(e,1,E,18,"precision")?0|e:null,n=null!=n&&H(n,0,8,18,v)?0|n:k,e?U(t,e,n):t},T.toExponential=function(e,n){return _(this,null!=e&&H(e,0,E,19)?~~e+1:null,n,19)},T.toFixed=function(e,n){return _(this,null!=e&&H(e,0,E,20)?~~e+this.e+1:null,n,20)},T.toFormat=function(e,n){var t=_(this,null!=e&&H(e,0,E,21)?~~e+this.e+1:null,n,21);if(this.c){var r,i=t.split("."),o=+X.groupSize,u=+X.secondaryGroupSize,s=X.groupSeparator,f=i[0],l=i[1],c=this.s<0,a=c?f.slice(1):f,h=a.length;if(u&&(r=o,o=u,u=r,h-=r),o>0&&h>0){for(r=h%o||o,f=a.substr(0,r);h>r;r+=o)f+=s+a.substr(r,o);u>0&&(f+=s+a.slice(r)),c&&(f="-"+f)}t=l?f+X.decimalSeparator+((u=+X.fractionGroupSize)?l.replace(new RegExp("\\d{"+u+"}\\B","g"),"$&"+X.fractionGroupSeparator):l):f}return t},T.toFraction=function(e){var n,t,i,o,u,s,f,l,c,h=j,g=this,p=g.c,d=new a(q),m=t=new a(q),w=f=new a(q);if(null!=e&&(j=!1,s=new a(e),j=h,(!(h=s.isInt())||s.lt(q))&&(j&&L(22,"max denominator "+(h?"out of range":"not an integer"),e),e=!h&&s.c&&U(s,s.e+1,1).gte(q)?s:null)),!p)return g.toString();for(c=r(p),o=d.e=c.length-g.e-1,d.c[0]=R[(u=o%y)<0?y+u:u],e=!e||s.cmp(d)>0?o>0?d:m:s,u=z,z=1/0,s=new a(c),f.c[0]=0;l=C(s,d,0,1),i=t.plus(l.times(w)),1!=i.cmp(e);)t=w,w=i,m=f.plus(l.times(i=m)),f=i,d=s.minus(l.times(i=d)),s=i;return i=C(e.minus(t),w,0,1),f=f.plus(i.times(m)),t=t.plus(i.times(w)),f.s=m.s=g.s,o*=2,n=C(m,w,o,k).minus(g).abs().cmp(C(f,t,o,k).minus(g).abs())<1?[m.toString(),w.toString()]:[f.toString(),t.toString()],z=u,n},T.toNumber=function(){var e=this;return+e||(e.s?0*e.s:0/0)},T.toPower=T.pow=function(e){var n,t,r=m(0>e?-e:+e),i=this;if(!H(e,-S,S,23,"exponent")&&(!isFinite(e)||r>S&&(e/=0)||parseFloat(e)!=e&&!(e=0/0)))return new a(Math.pow(+i,e));for(n=J?d(J/y+2):0,t=new a(q);;){if(r%2){if(t=t.times(i),!t.c)break;n&&t.c.length>n&&(t.c.length=n)}if(r=m(r/2),!r)break;i=i.times(i),n&&i.c&&i.c.length>n&&(i.c.length=n)}return 0>e&&(t=q.div(t)),n?U(t,J,k):t},T.toPrecision=function(e,n){return _(this,null!=e&&H(e,1,E,24,"precision")?0|e:null,n,24)},T.toString=function(e){var n,t=this,i=t.s,o=t.e;return null===o?i?(n="Infinity",0>i&&(n="-"+n)):n="NaN":(n=r(t.c),n=null!=e&&H(e,2,64,25,"base")?D(l(n,o),0|e,10,i):B>=o||o>=$?f(n,o):l(n,o),0>i&&t.c[0]&&(n="-"+n)),n},T.truncated=T.trunc=function(){return U(new a(this),this.e+1,1)},T.valueOf=T.toJSON=function(){return this.toString()},null!=e&&a.config(e),a}function t(e){var n=0|e;return e>0||e===n?n:n-1}function r(e){for(var n,t,r=1,i=e.length,o=e[0]+"";i>r;){for(n=e[r++]+"",t=y-n.length;t--;n="0"+n);o+=n}for(i=o.length;48===o.charCodeAt(--i););return o.slice(0,i+1||1)}function i(e,n){var t,r,i=e.c,o=n.c,u=e.s,s=n.s,f=e.e,l=n.e;if(!u||!s)return null;if(t=i&&!i[0],r=o&&!o[0],t||r)return t?r?0:-s:u;if(u!=s)return u;if(t=0>u,r=f==l,!i||!o)return r?0:!i^t?1:-1;if(!r)return f>l^t?1:-1;for(s=(f=i.length)<(l=o.length)?f:l,u=0;s>u;u++)if(i[u]!=o[u])return i[u]>o[u]^t?1:-1;return f==l?0:f>l^t?1:-1}function o(e,n,t){return(e=c(e))>=n&&t>=e}function u(e){return"[object Array]"==Object.prototype.toString.call(e)}function s(e,n,t){for(var r,i,o=[0],u=0,s=e.length;s>u;){for(i=o.length;i--;o[i]*=n);for(o[r=0]+=O.indexOf(e.charAt(u++));rt-1&&(null==o[r+1]&&(o[r+1]=0),o[r+1]+=o[r]/t|0,o[r]%=t)}return o.reverse()}function f(e,n){return(e.length>1?e.charAt(0)+"."+e.slice(1):e)+(0>n?"e":"e+")+n}function l(e,n){var t,r;if(0>n){for(r="0.";++n;r+="0");e=r+e}else if(t=e.length,++n>t){for(r="0",n-=t;--n;r+="0");e+=r}else t>n&&(e=e.slice(0,n)+"."+e.slice(n));return e}function c(e){return e=parseFloat(e),0>e?d(e):m(e)}var a,h,g,p=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,d=Math.ceil,m=Math.floor,w=" not a boolean or binary digit",v="rounding mode",b="number type has more than 15 significant digits",O="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",N=1e14,y=14,S=9007199254740991,R=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],A=1e7,E=1e9;if(a=n(),"function"==typeof define&&define.amd)define(function(){return a});else if("undefined"!=typeof module&&module.exports){if(module.exports=a,!h)try{h=require("crypto")}catch(D){}}else e.BigNumber=a}(this); -//# sourceMappingURL=doc/bignumber.js.map` +//# sourceMappingURL=doc/bignumber.js.map diff --git a/internal/jsre/deps/bindata.go b/internal/jsre/deps/bindata.go new file mode 100644 index 0000000000..73732a4ebc --- /dev/null +++ b/internal/jsre/deps/bindata.go @@ -0,0 +1,258 @@ +// Code generated by go-bindata. +// sources: +// bignumber.js +// web3.js +// DO NOT EDIT! + +package deps + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _bignumberJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\xbc\x6b\x77\x9b\xc8\x93\x38\xfc\x7e\x3f\x85\xc4\xc6\x9c\x6e\x53\x20\x90\x9d\x38\x86\x14\x9c\x4c\x62\xe7\xe7\x79\x1c\x3b\x4f\x9c\xcc\xcc\xae\xa2\xc9\x91\x51\x23\x75\x82\x40\xe1\x62\xc7\x09\xfe\x7d\xf6\xff\xa9\x6e\x40\xf2\x25\xbb\xb3\x6f\x2c\xe8\x4b\x75\x75\x75\xdd\xbb\xf0\x68\x77\x70\x29\x17\x59\xbd\xba\x14\x85\xf3\xa5\x1c\x5c\x8d\x1d\xd7\xd9\x1b\x2c\xab\x6a\x5d\xfa\xa3\xd1\x42\x56\xcb\xfa\xd2\x89\xf3\xd5\xe8\xad\xfc\x2a\xde\xc6\xe9\x68\x7b\xf8\xe8\xf4\xe4\xd5\xd1\xd9\xab\xa3\xc1\xee\xe8\x3f\x46\xbb\x83\x55\x3e\x97\x89\x14\xf3\xc1\xe5\xcd\xe0\x87\x48\xe5\x62\x50\xe5\x83\x44\x7e\x7f\x0c\x5c\x91\x5f\x8a\xa2\xfa\x5a\xc8\x95\xc8\x46\x79\x55\xe5\xff\x59\x88\x45\x9d\xce\x0a\x5b\x7c\x5f\x17\xa2\x2c\x65\x9e\xd9\x32\x8b\xf3\xd5\x7a\x56\xc9\x4b\x99\xca\xea\x86\x96\x19\x26\x75\x16\x57\x32\xcf\x98\xe0\x3f\x8d\xba\x14\x83\xb2\x2a\x64\x5c\x19\x41\xd7\x31\x50\x5d\xfd\xdb\x8c\x09\xc8\xf8\xcf\xab\x59\x31\xa8\xa0\x00\x09\x39\xd4\x50\x42\x82\xd5\x52\x96\x81\x4c\xd8\x90\x25\x03\x99\x95\xd5\x2c\x8b\x45\x9e\x0c\x66\x9c\x17\xa2\xaa\x8b\x6c\xf0\xc5\x34\x4f\xd9\xf8\x19\x18\x71\x9e\x95\x55\x51\xc7\x55\x5e\x0c\xe2\x59\x9a\x0e\xae\x65\xb5\xcc\xeb\x6a\x90\x89\x6b\x03\x04\x87\x4c\x5c\xb7\xeb\x10\xc0\xac\x4e\xd3\x21\x66\xa6\xf9\x2f\x96\xc1\x18\x9e\xed\xc3\x5b\x30\x2e\x67\xa5\x30\x38\xff\x49\xfd\xe8\x36\x19\x94\x28\x2c\xc3\x00\xcf\x45\xcc\xba\x15\x13\x6c\x21\xdd\x41\x28\x12\x7e\xc9\xe1\x23\x4b\xe0\x9d\x95\x38\xc2\xf2\xe0\xab\x5a\x87\xe5\x68\xe8\xa3\x30\x10\xab\x9b\x35\x0d\x16\xdc\x34\xdd\x5d\x31\x44\xb7\x69\x86\x04\xec\xbd\x58\x1c\x7d\x5f\x33\xe3\x6f\x3b\x32\x2c\x56\xa1\x31\x31\xac\x73\xa7\x4c\x65\x2c\x98\x0b\x19\xb7\x8c\xa9\x65\x70\xcb\x60\x91\xff\xe9\x93\x63\x58\x95\x65\xf0\xe8\x89\x01\x7b\x07\x61\x16\x19\xd2\xf0\x0d\x83\x3b\x95\x28\x2b\x56\xf6\x84\x59\xb0\x04\x4a\xc8\x69\xbb\x79\xc4\x12\xa7\x44\x37\xf4\x46\x22\x62\x25\x96\x2d\x68\x8f\x83\xed\x71\xdf\x83\x2f\xa6\x59\x3a\x85\x58\xa7\xb3\x58\xb0\xd1\xdf\xee\x27\xc7\xdd\x6d\x3e\x39\x23\x20\xb8\xa9\xc8\x16\xd5\x32\xf4\x9e\x12\xa5\xdf\xc2\x25\xd1\x32\xc7\xa1\xc7\x7d\x02\xba\xff\x14\x11\x4b\x27\x5e\xce\x8a\x57\xf9\x5c\xbc\xac\x98\xcb\x1f\x5d\xa3\xc4\xd7\xac\x04\xcf\x85\x0c\x12\xa7\xe4\xb7\x22\x2d\x05\x11\xfa\x2e\x19\x7b\x22\x3b\x25\x0a\xa7\x84\xc4\x11\x28\x1c\x01\x89\x13\x23\xa3\xc7\x98\x47\xa2\x05\xcd\x7d\x01\x57\xb9\x9c\xb3\xb7\xe8\xfe\x6f\xb4\x46\x74\xd5\xb1\x6e\xd1\x41\xa0\x2d\x5a\xdc\x04\x22\xfe\xfb\xdf\xc4\x90\x79\xc1\x0a\x74\x41\xa2\x08\x64\x88\x9e\x1b\xc8\x11\x7a\x2e\x14\x96\xc5\x83\x1e\x35\x81\x85\x42\x68\x22\xa6\x1b\x04\x6e\x35\xaf\xf4\xfb\x1a\xae\xdb\x13\x51\xcd\xf7\x8f\x85\x07\xff\x17\xe2\xdd\xde\x12\x62\xac\xc0\xd2\x91\xd9\x5c\x7c\x3f\x4f\x98\xe1\x18\x9c\x87\xb6\x67\x9a\x6a\x7c\x77\x78\x86\x63\xd0\xa1\x71\x60\x92\xa0\x88\x59\x11\x2f\xd9\x48\x8c\x24\xe7\xa1\x1b\x31\x37\x2c\x4c\x93\x15\x28\x39\x14\x16\x5a\xdd\x3a\xd2\xf2\x38\xa8\x65\xeb\x4b\x92\xd4\x6c\xc1\x5c\x90\x9c\xfb\xdd\xf8\xb2\xe5\x02\x0e\x12\xdd\x60\xff\xf9\x7d\xb4\x25\x0f\x24\x91\x88\xd0\xac\xfb\xd1\x8f\x0c\xb4\xed\x9a\x07\xea\xb0\x36\xbb\x94\x50\x5b\x1e\xe7\x32\xd9\x9a\x0a\xb9\x69\x7e\x31\xcd\x7a\x8b\xed\x12\xa7\xdc\x15\x1c\x0a\x2c\x6c\x69\x7b\x50\x84\x3f\x38\x1d\x02\x1d\x07\x09\x73\x40\x84\x1f\xc8\x84\xbd\x09\x0b\xd5\x31\xa1\x1e\x77\x1a\x74\x07\xb2\x75\x6e\x53\x90\xc8\x0a\xcb\xe3\x3b\x37\xa0\xb7\x28\x2d\xbc\xe1\x50\x87\x52\xf3\x80\x34\xcd\xc4\x89\x9d\x75\x5d\x2e\x59\x4f\x25\x45\x12\xa8\x6d\xbc\x09\xea\x50\x06\xfc\xe1\x08\x09\x0a\x0e\x0f\xb6\x36\x47\x24\xbb\xb1\xbb\x7d\xdd\x6a\x2c\x6d\xac\x15\xad\x02\x69\xdb\x41\x69\xa1\xe1\x1a\xc4\x11\x3d\x3c\x2d\x1e\x83\xed\x6d\xbc\x45\xf7\xb6\xd7\x97\xaf\x49\x8f\x41\x05\x52\xeb\x4c\xd2\x96\x09\xc4\xb0\x84\x05\xac\x61\x8e\xe2\x0e\x9b\xc0\x0a\xdf\xc1\x35\x7e\x55\x2b\xee\x1d\x84\x95\x69\x2a\x51\xaa\xf2\xd3\xfc\x5a\x14\xaf\x66\xa5\x60\x9c\xc3\x3c\x44\xd7\x34\x59\x82\xbf\xc3\xef\xe8\x02\x8d\xb8\xc7\x55\xb0\x6e\x55\x5f\xc5\x61\x89\x6b\x67\x9d\x5f\x33\xd1\x6e\xcc\x9e\x73\xf8\x1d\x13\x58\x3b\x31\x96\x2c\x65\x05\x5b\x3a\x31\x87\xa5\x23\xb8\x12\x7a\x0e\x6b\x47\xe0\xda\x89\x7b\x4e\x5a\x60\xc9\x04\x54\xd4\x55\x63\x82\x8b\x8e\x69\x5c\xc4\xc5\xc4\xb6\x93\x69\xb0\x70\xd6\xf9\x9a\x71\xc5\x2e\xc3\xc5\xc4\x9d\xb6\x42\x64\xb8\x06\x35\xb9\xe1\x3c\xb2\xed\xda\xa7\x95\x70\x41\x4b\x61\x0d\x4b\xa7\x44\x09\x4b\x7c\xc5\x96\xb0\x86\x15\x5c\x13\xfc\x05\x2e\x9d\x18\x62\x5c\x3a\x05\xd4\xa8\x70\xca\xb1\xb6\x56\x96\x07\x73\x5c\x4c\xf2\x29\x24\x98\x8d\xc6\x10\x63\xdc\x34\x6e\x98\x37\x8d\x36\x0f\x8b\x49\x6e\x79\x53\x88\x71\x3f\xbc\x8e\x5a\x93\x31\x6f\x9a\x98\x9b\x26\x73\x11\xaf\x9b\xe6\x1a\x91\x2d\x9d\xf2\x85\x1b\xed\xf9\x63\xce\xfd\x79\x98\x34\xcd\x1c\x31\x31\x4d\xb6\xaf\x46\xc4\x4d\xf3\x0c\xf1\xda\x34\x3d\x73\x31\xc9\x6d\x6f\xba\x3d\xe9\xb9\x7f\xc0\x39\x78\xb4\xa2\xde\xa0\xc0\x38\x4a\x99\xe1\x19\x60\xaf\xb8\x4f\x1b\xed\xd8\xb7\xa3\x0f\xe6\x10\x73\x3a\x49\xdb\xce\x02\xcb\x22\x52\xe5\xd3\x30\x0b\x38\xed\x03\x5d\xc8\x9b\x86\x59\x56\x0d\x0b\xa7\xce\xca\xa5\x4c\x2a\xe6\x71\x2d\x98\x5b\x34\x1e\xb6\x14\xd6\x1d\x73\x75\xdc\x86\x11\x24\x21\xce\x03\x61\xe1\xb9\x12\xd9\x97\x15\x5b\x4c\xe6\x96\x35\xe5\x3c\x10\x98\x32\x01\x35\xbf\x6d\xd5\x98\xd8\xf0\xe2\xe7\x87\xbc\x58\x12\x2f\xd2\x11\x55\xa8\x89\x56\x91\x9d\xad\xc0\x85\xe7\x20\xe1\x8a\x47\x6e\x53\xf9\x5f\x61\x48\xea\xbc\x03\xe8\x54\xf9\x85\x56\x3d\xea\xbc\x73\xd2\xf5\x13\x77\x4a\x26\xd8\x11\x40\x60\xc8\x06\x2f\xb1\x60\x42\x31\x16\x7a\x87\x88\xb2\x69\xc6\xfb\x88\xd2\x34\x7f\x0b\xb1\x8c\x12\xb6\x84\x92\xfb\xa9\xfa\xe9\x15\x82\xc0\x8f\xac\x35\xd9\x9c\x30\x25\x7e\x23\x98\x3d\x2c\x62\x8c\x56\xed\xdc\x05\xca\xea\x10\xb3\xa6\xf9\x2d\xc4\x9a\x6b\xc5\x10\x64\x61\x1c\x2c\x95\xc0\x42\x4c\x1a\x6f\x89\xb4\x68\xdd\x0a\x2c\x39\x0e\x36\x96\xb0\xc4\x54\xb5\x92\x66\x0b\x63\x65\x79\x6c\x3b\x0b\x5d\x75\x70\x34\xdd\x31\x82\xcc\xb6\x5b\x48\x3c\xd8\xcc\xb6\xb0\xb6\x63\xe8\x86\xd6\x96\x87\x18\x9b\x66\x3b\x87\xdf\x99\xd4\x53\xae\x7c\xe1\x9a\x66\x1e\x19\xb6\x61\x2d\xfd\xe5\xe6\x64\xbe\xdf\xf3\xaa\xd0\xd5\x0a\x9a\x09\x62\x35\xad\x05\xe8\x09\xaa\xce\xa5\xa1\xb7\xc0\xb2\xe4\x8b\x4e\xac\x03\x85\x7b\xd1\xf7\xcb\x29\x87\x61\xe1\x94\xfc\x67\x85\x45\x70\x59\x88\xd9\xd7\xdb\xcc\x21\x7f\x8b\x55\x50\x10\xcc\x0a\x8b\x9e\x4b\xaa\x0d\x2e\xc7\x2d\x97\x14\xc4\x27\xba\x9b\x65\xa1\x68\x1a\x11\x56\x4d\x23\x86\x18\x33\xc1\x39\xe9\xfa\x02\x98\x6c\x1a\x63\x2e\x62\xb9\x9a\xa5\x03\xa5\x81\x4a\x83\x5b\xfd\xf0\xc8\x18\x90\x5f\x97\x27\x83\x62\x96\x2d\x84\xe1\x1b\x83\x2c\xaf\x06\xb3\x6c\x20\xb3\x4a\x2c\x44\x61\x70\xf2\x51\x86\x5b\xfa\xf2\x44\xaf\xae\xcf\x90\xe8\x51\xa0\x07\x12\xb3\x5e\x1e\xb2\x89\x6d\xcb\x69\x90\x75\x1a\x47\x19\x01\xcc\x26\xee\xf4\x57\x7e\x00\x6d\xd4\xaa\x76\x6f\x6c\x8f\x87\x3f\x22\xe1\xc4\xc4\x53\x8a\xdd\xfd\x37\x61\xa5\x1a\x26\x42\xa9\x6e\x9f\xd1\x6f\x05\xd4\x94\x71\xd8\x12\x9d\xd3\x0e\x2d\x8d\x12\x11\xf9\xa8\x28\xf2\x82\x4d\x0c\x7a\xfe\x4d\x2e\xce\xb4\x3b\x03\x46\xbc\x5a\x1b\xca\xc9\x4d\xe4\xc2\x00\x63\x2e\xaf\xf4\xdf\x0f\xf9\x49\x56\x19\x60\x88\x6f\x06\x18\x8b\x4a\xfd\x11\x06\x18\x69\xa5\xfe\xd0\xe3\x4a\x66\x75\x49\xbf\xf9\xdc\x00\x63\x9d\xaa\x97\x75\x21\x62\x49\xfe\xbb\x01\x46\x31\xcb\xe6\xf9\x8a\x1e\xf2\x3a\xa3\x31\x4a\x6f\x18\x60\x54\x72\x25\x68\x70\x95\xbf\x96\x0b\x59\xe9\xc7\xa3\xef\xeb\x3c\x13\x59\x25\x67\xa9\x7a\x3f\x96\xdf\xc5\x5c\x3f\xe5\xc5\x6a\x56\xe9\xc7\x62\xa6\xb6\x48\x2b\xe5\xd7\xaa\xe9\xdd\xd6\x8a\x9d\xac\x1b\x60\x6c\x36\x39\x9d\x88\xa9\x65\x30\x3e\x30\xac\xcc\x32\xfc\x81\x61\x55\x3c\xa8\x96\x45\x7e\x3d\x28\x9c\x6c\xb6\x12\xb8\x19\xac\xe9\x64\xc0\x5b\x74\xa1\xd8\x10\xf4\x63\xc7\x65\x9a\xa4\x7d\x1c\x01\x29\xc4\x30\x23\x95\x02\x4b\x7c\x4f\xfa\x65\xc6\x7f\x0a\x5f\xdb\x7a\x24\xe7\x74\x46\x47\x5d\xaa\xa3\x2e\xd5\x51\x2b\x7f\x46\x29\xa2\xcc\x96\xe0\x86\x39\xcf\x2d\xbc\x81\x1a\x33\x48\x70\x36\x49\xd1\x25\xc3\x90\x8c\x96\x13\x69\xd7\xb6\x37\xdd\xf1\xdc\xc6\xed\x75\x4e\x8a\x73\xc6\x72\xcb\xe3\xa3\x1b\x0e\x69\x88\xb3\xce\xec\x29\xd7\xb0\xe0\x4a\x72\x06\x42\x3b\x01\x5d\xe7\x0b\x4c\x83\x99\x76\x01\x5c\xe2\x41\x8c\x95\x2b\xea\x41\xbe\xa3\x56\xce\xed\x1b\xcb\xd3\x0e\xa6\xd6\xe7\x84\x76\x4a\xce\x8c\xf7\x10\xf5\xad\x39\x12\x62\x74\xc3\x3a\x72\xfd\x7b\xe8\xde\x2a\xd9\x2e\xc8\xe6\x65\x9d\xcd\x9b\x4d\x52\x8b\x8c\x14\xa3\x19\x89\x9f\xec\x74\x33\xc8\xf5\xda\x0f\xab\x88\xc5\x4d\x53\xb4\x16\xb0\x6a\x9a\x0a\x91\x89\x2d\x0b\x18\x87\x4f\x9b\xe6\xa9\xd6\x5a\xfb\x6a\x44\xa1\x2c\x20\x79\x1d\x79\xe8\x46\x75\xe8\x46\x2d\x1a\x53\xdf\xf5\x67\x93\x94\x60\xef\x78\xae\xe9\x6d\x03\xeb\x2c\x63\xd6\x34\xc3\xd9\xc6\xf4\x0f\x3a\x5a\xd1\xb9\x47\xa4\x6c\x85\x0a\xb6\x68\x08\x2e\x27\xd9\xce\xcd\x14\x48\xda\xec\xac\x69\x5c\xee\xab\x66\x25\x85\x20\x94\xcb\x80\x98\x47\xac\x87\x91\x42\x89\x1e\xa4\xb6\xcd\xfd\xad\x46\x8b\xf8\x61\x39\xb9\xb1\xf3\x29\x10\x7d\x91\x50\x5e\xb1\x0e\xe9\x9d\xe5\xa4\x9e\xf2\xdd\xd2\x77\x39\x14\x4a\x4b\x07\x5a\x4b\xba\x88\xa9\xd6\x30\x39\x7a\x50\x6b\x96\xaa\xd5\xb9\xd4\xea\x5c\xf2\x8d\x8b\x4c\x7d\x16\x96\xb4\xfe\x9d\x21\xa5\x3a\xba\x21\x96\xa4\x9d\x1d\x61\x59\x7a\x67\x78\x66\x9a\x4c\x3d\x91\x31\xd7\x6a\x97\x98\x78\x92\x2a\x28\xf4\x3b\xc4\x33\xcd\x55\x01\x91\xd4\x26\x57\xa0\x44\xef\x56\xa3\x33\xdb\x72\xae\x70\xa6\x5c\x06\xe2\x34\xad\xeb\x6e\x85\x23\xee\xab\x30\xe1\x88\x17\x6f\x14\x0e\xbd\x1a\xdb\xb2\xfd\x24\x5b\xaf\x94\xec\x7d\xc0\x99\xb3\x2e\xf2\x2a\xa7\x70\x0b\xbe\xb5\x76\xc2\xe3\xf0\x0e\xc7\x2e\x7c\xc5\x7d\xf8\x0d\xed\x03\x78\x82\x63\x0f\xde\xa0\xed\x89\x03\xf8\x81\xf4\xf7\x0b\x0e\x5d\xf8\x17\x1e\xc3\x1f\x38\xf4\xe0\x4f\xf4\xe0\x77\xf4\x5c\x17\xfe\xc2\x9f\xad\xe6\xbf\x10\xeb\x59\x31\xab\xf2\xc2\x27\xf7\x73\x51\xe4\xf5\x7a\xab\x09\xba\x26\xf9\x43\xf8\x7b\x50\x8a\x38\xcf\xe6\xb3\xe2\xe6\x4d\xdf\xe8\x42\xd2\x2a\xa1\x37\xf7\xe6\x0e\x8c\x7b\x5d\x6a\xf8\x6d\xd0\xb3\xd8\x2c\xcb\xab\xa5\x28\x30\x83\x99\xf3\xfe\xfc\xe3\xd9\xeb\xcf\x1f\xdf\xa1\xdb\xbf\xbc\x3e\xff\xf3\x0c\xbd\xfe\xf5\xd5\xd1\xc9\x29\x8e\xfb\xd7\xe3\xd3\xf3\xf3\xf7\xb8\xd7\xbf\xff\xeb\xe5\xe9\x31\xcd\xdf\xbf\xdb\xa2\x80\x3c\xbd\xdb\x76\xf4\xc7\xd1\x19\x3e\xbb\xdb\xa6\xa0\x1f\xdc\x6d\xd3\x4b\x3c\x87\x99\x73\xf4\xf1\xd5\xe9\xc9\x6b\x3c\x84\x99\xa3\x6d\x03\xf6\xa9\x17\xad\x02\x95\x3e\x24\x61\xc1\x9f\xb7\x20\x71\x56\x2c\xea\x95\xc8\x2a\xe2\x3c\x49\xee\x55\x42\xac\x66\xe4\x97\x5f\x44\x5c\x6d\xa2\xe6\x32\xda\x02\xd3\x92\xa5\x74\x96\xb3\xf2\xfc\x3a\x7b\x57\xe4\x6b\x51\x54\x37\x2c\xe3\x91\x56\x19\x4c\x60\x39\xc9\xa6\xdc\xa7\x60\x78\xe0\xde\xfa\x0f\x27\xcb\x2e\x8d\x50\x6d\xe6\xc8\x49\x45\xce\x65\x37\xab\x8f\xaf\x59\x86\xc6\xeb\xa3\x57\x27\x6f\x5f\x9e\x7e\x7e\x77\xfa\xf2\xd5\xd1\x85\xc1\xc9\x7f\x14\xe0\xc2\x11\x8c\x21\x23\xe5\xf3\x0e\xdd\x86\xa2\xc1\x49\x36\xc5\x77\xa0\xe6\x28\x02\x9d\x9c\xbd\xf9\xfc\xf6\xfc\xf5\xd1\x66\xca\xf3\x6e\xca\xd7\xad\x29\x5f\xf5\x94\xa3\xbf\xde\x9d\x9f\x1d\x9d\x7d\x38\x79\x79\xfa\xf9\xe5\x07\x9a\x43\xde\x11\x8f\xfe\xa5\x5c\x21\xb0\x8f\xc0\x6d\x67\x53\x8b\x37\xdd\xc6\xe0\x37\x02\x47\xa3\x9e\xa8\x07\x6f\xca\x7d\x5a\xd0\x3e\xda\x1e\x62\x33\xea\x65\x6e\x28\x22\x5b\xf8\x82\x73\xde\x22\x30\xf9\x0d\x9e\x4c\x5b\xbc\x5f\x9e\xbd\x39\x7a\x6c\x6d\xdb\xbb\xbb\xb8\xb7\x81\xfc\xa6\x5b\xfc\xc7\x2f\x17\x77\x1b\x11\xbd\x41\x9b\xfd\xb8\x8b\x80\xaf\x33\x66\x90\x59\xc6\x20\x9e\x65\xe4\x39\x5d\x8a\xc1\x0f\x51\xe4\x06\x88\x0d\x7a\x6f\xe0\x47\x8b\xde\xd1\xfb\xf7\xe7\xef\xd5\x11\x30\x81\x88\xc3\xa1\x68\x1a\x0f\x11\x45\xd3\x90\x36\x11\x11\x23\x45\xf0\x2f\x64\x5f\xa8\x8f\x47\xc7\x7e\xbe\xb5\xc8\x35\x01\xd5\x30\xbf\x68\x78\xaf\xde\xff\xd7\xbb\x0f\xe7\xff\x13\xbc\x3f\x70\xc8\xa8\x75\xb8\x6c\x9a\x8e\x35\x87\x1d\x6b\x2e\x39\x08\xd3\x1c\xfe\xa1\xf2\x03\xb4\x86\x11\x17\x37\xeb\x2a\x1f\xd4\xd9\xec\x6a\x26\xd3\xd9\x65\x2a\x0c\x58\xf2\xc7\x71\xf8\x43\xe3\xf0\xf6\xfc\xf5\xc7\xd3\xf3\x7b\x8c\x72\xd8\x51\xee\xcf\x2d\x46\xf9\x53\x4f\x78\x77\xfe\xe7\xe7\x77\xef\x8f\x5e\x9d\x5c\x9c\x9c\x9f\x3d\xc2\x8e\xbf\x6f\x4d\xf9\x5d\x4f\x39\x3e\x7f\xff\xb6\xe5\xa9\x07\xf2\x25\xa2\xbf\x50\x6c\x9f\x44\xeb\xc0\xb6\xe3\x36\xf8\xfe\x05\xc5\x2d\xcc\x9c\xd5\xec\x3b\x3e\x14\xaa\xef\x6c\x23\xce\x1f\x9c\xb4\xe2\x6a\xa8\xcc\xfe\xd7\xa1\x0b\x3d\x54\xfb\x7d\x0f\x34\x06\x1e\xba\xee\x81\x77\x78\x38\x7e\xba\x7f\xb0\xef\x1e\x1e\x8e\x21\xc3\xb7\xb3\x6a\xd9\x8e\x67\x7c\x57\x98\x63\xf7\xf0\xc0\x7b\xea\x3d\xa2\x26\x56\xec\xde\x58\xfe\x98\x3e\x78\xbe\xf7\xfc\xf9\x33\xf7\xf9\x2e\xf3\xdc\x83\xbd\x83\x7d\xef\xf9\x78\x7f\xf7\xce\xbc\xc6\xe5\x16\xeb\x46\xdd\xef\xd9\xe8\x8a\xad\x3c\xf3\xbd\xe4\x31\xba\x90\xe0\x64\x0a\x69\x6b\x93\xbe\x29\x6f\x4e\xb4\x01\xa9\xd8\x9c\xa0\xb7\x4f\xf1\xa8\xf0\xdf\x41\x8e\x73\x26\xc8\x61\xfb\x83\xcb\x84\x2d\x4d\x73\xe9\x2c\x44\xf5\x5e\xad\xfb\xc7\x2c\xad\x45\xa9\xcd\x7b\x85\x0f\x3a\x54\x80\xf9\x51\x66\xd5\xde\xf8\x65\x51\xcc\x6e\x58\xbe\x8b\x63\xce\x83\x3c\x2c\x03\x5e\xa3\xb7\xe7\xb9\x07\xe3\xdd\x6a\x52\x4e\x2d\x56\x4d\x4a\xcb\x9b\x86\x61\xe8\x79\x1c\xea\x10\x0f\x85\xf7\x34\x62\xc5\x3f\x00\x3a\xe6\x1c\x08\x06\x16\x24\xfa\x1a\x0e\x16\x4a\xfa\x59\xa2\x1d\xc7\x7a\xc7\x13\xde\x3e\x87\xd2\xc2\x31\x0f\x4a\xcc\x47\xe3\x3e\xb8\x54\x3b\xd2\x64\xfc\xed\xa6\xda\xde\xcd\x56\x23\x61\x7e\xd0\x23\x3e\x7e\xee\xed\x1f\xec\x1f\x1e\x3c\x3b\xf0\xdc\x67\x4f\x9f\xed\xb2\x3d\xcf\x24\x0c\xb8\xe5\xb9\x87\x87\x4f\x3d\xef\xd9\xf8\xe0\xe0\xe0\xd9\xae\xc6\xc5\xda\x1f\x1f\xee\x1f\x3e\x3b\x18\x1f\xea\x96\xf1\xd4\xf2\x9e\x1d\x1c\x1c\x8c\x3d\xfd\xbe\xd7\xee\x7e\x7f\xfa\xe2\x85\xf7\x8c\xeb\x97\xa7\xd3\x17\x2f\x9e\x73\x8b\x1e\x9f\x4d\x7b\x7a\xdc\xc5\xe9\x80\x3b\x71\xbe\xbe\x61\x15\x85\xf7\x8f\x6c\xf5\x40\x6f\xf5\x40\x6f\x55\xc9\x95\xb7\xff\x2b\xcd\xa0\xd2\x49\xa5\xf6\xdc\xda\x6d\x66\x8c\x03\x2d\x1b\xd6\xa6\xc9\x92\x49\x69\x59\x53\x6c\xc1\x07\xda\x83\x4a\x26\xb6\x5d\x4e\x41\x90\x57\x9d\x9b\xa6\x20\x6d\x8d\xef\x27\x37\xb6\x98\x42\x42\x47\xb2\x62\xf9\xa8\xe6\xbb\x35\x57\x3e\x16\x35\x05\x89\xf6\xb0\xa0\xb4\x6d\xae\x13\x56\x25\x4f\x70\x22\xfb\xac\xa4\x0e\x3f\x6c\xaf\x9d\xe2\xd2\x14\x9d\xb3\xe1\x20\x6d\xbc\xd1\x8b\x97\xca\x9b\x4c\xee\x7b\x93\xca\x55\xbc\x09\xc9\x53\xa4\xb1\x76\xd9\x3b\x68\xa9\x23\x50\x42\xea\xc4\x98\x40\x7a\x7b\xcb\x38\xbc\xda\x16\xf2\x3e\x5a\x12\x77\xc2\xcf\x3b\x82\xd3\xc5\xff\x24\x3e\x3b\x2f\x21\xc6\x6c\xf4\xb2\xd1\xe9\x03\x81\x7d\x02\x3e\x48\x6c\x3b\xe0\x39\x8a\x49\x32\xdd\x79\x09\xb5\x7a\xa0\x81\x50\x60\xbc\x9b\x5b\xf5\x6e\x0a\x12\xd3\xdd\xdc\x2a\x76\x5e\xee\xbe\xb4\xc8\xeb\x60\x72\x54\x29\xe1\x2e\x68\x20\xb7\xe2\xdd\x1a\x68\x1a\xca\x9d\xaa\x13\xeb\xd2\x34\x45\x9f\xbe\x2a\xef\x84\xcc\xd9\x83\x08\x4f\xe5\x99\x86\x58\xf0\x1c\xab\xb0\x88\x3c\xdf\xf6\x74\x18\xa6\xa9\x9b\xa3\x1b\x54\xa1\x54\xf9\x69\x52\x00\x13\x39\x1d\x62\x36\x91\x53\xfe\x93\x10\x97\xd3\x90\x5e\xf4\x34\xed\x58\xb7\x48\xe4\x9b\x45\x8b\xcd\xa2\x5d\x02\x41\x12\x58\xda\xbd\x98\x54\x53\x1b\x25\x48\xa4\xa7\x17\xd9\xa4\x22\x60\x2e\xd0\x1b\xca\xdd\xc2\x52\x03\xa8\x59\x07\x7b\x43\x32\xdb\xb4\xbf\xee\x5e\x25\x10\xdd\x99\xf3\xe0\xf6\xbe\x5e\xeb\x23\x58\xbd\xdd\x74\x93\xe4\x85\x6b\xb8\x82\x4b\x38\x87\x0b\x78\x0f\x2f\xe1\x08\x5e\xc3\x67\xf8\x0e\xc7\x28\x9d\x12\x31\x77\x4a\xb5\x25\x38\x41\xe9\xc4\x70\x8a\xb9\x13\xeb\x7b\xb4\x13\xd3\x3c\x51\x18\x9c\x9a\xe6\x29\x05\x56\x5d\x64\xa5\xd5\xa4\x74\x4a\xd3\xcc\xe9\x0f\x3b\x89\x86\xa7\x4d\x43\x83\x87\x48\x23\xfd\x53\x1e\x9d\x98\xa6\x8b\x48\x6d\x4d\x33\x3c\x8d\xdc\xdd\x63\xff\x78\xe4\xfa\xee\xc8\xd5\xbc\x7a\xd5\x6a\xdb\x63\x0e\x97\x78\xa5\x73\xed\x31\x4a\x47\xd8\xb9\x23\xe0\x18\x6b\x2b\xb6\x3c\x48\x9a\x86\x25\x78\x06\x31\x56\x4c\x3a\xa4\x72\xed\x8a\xe5\xea\x01\x8e\xf1\x78\x74\xd3\xb8\x1c\x96\xe8\x06\xa7\x93\xe5\x14\x91\x9d\x4c\x96\x53\x8a\xe7\x82\x65\x1b\x94\x53\x7b\xd8\x37\x9b\x66\x6c\xdb\xe0\x86\xc7\xfc\x52\x6b\x06\x8f\xc3\x02\x87\xee\x46\xc8\x8e\xf0\xa4\x63\xe8\xcf\x78\xda\x3d\x52\x10\x79\x6c\xe1\x18\xd6\x48\xe1\x1d\xa3\x4d\x5a\x1e\xe7\xb0\x0e\x3d\xd3\x64\xa7\x28\xd8\x29\xac\x21\xe1\x70\x82\x82\x9d\xe8\xc7\xad\xf9\x1b\xa8\x1c\x5e\xe2\x67\x38\xc7\x93\xfe\xaa\xe0\x33\x87\x0b\x3c\xef\xc2\xae\xcf\xe1\x45\x70\x3e\xb9\x20\xb5\xe2\xf2\xe0\x3b\x9e\x76\x12\x04\xdf\x7b\x3e\x77\x39\xbc\x56\x74\x86\xd3\x89\x37\x0d\x31\x19\x8d\x4d\xf3\xb5\x65\x05\xf3\x7c\xb0\x46\x97\x24\x91\x9d\xc2\x39\x7c\x86\x0b\x0e\x6e\x98\x46\xec\x3d\x9e\xd3\xf0\xcf\x43\xbc\x30\x4d\xf6\x1e\xdf\xef\x26\x16\x3b\x9f\x78\x8a\x28\x5c\xed\xea\xfd\xe8\xb5\xda\x4e\xc4\xd6\xa1\x4a\x4a\xaf\x31\xb1\x3d\x0e\xf3\xcd\xde\xae\x71\xde\x6d\x68\x83\xb1\x5a\x6d\x0e\xe7\x70\x4d\xab\x79\x88\x29\xcd\xb5\x6d\x28\xd8\x1c\xae\xc3\xcf\xd1\x77\xff\x14\xae\x21\xe1\x9c\xfb\x14\xf8\xae\x4d\x93\xa5\xb8\x46\x05\xba\xdf\xdd\x5d\xe0\xe1\xb5\x69\xce\xb7\xb7\x5b\xb0\x73\x98\xc3\x05\x21\x61\xb7\x4b\xdc\xc3\xa0\xdf\xaf\x17\x2a\x04\x2c\x4b\x4d\xba\x68\x11\xb8\x50\x08\x6c\xa1\xcd\x7d\xd2\xa4\xdd\xd0\x73\x54\xd9\xcd\xcb\xc9\x92\x08\xbf\x86\xd4\x34\x89\x60\x51\x7b\x12\x27\x93\x97\x44\x29\x9f\x9d\xe3\x84\x9e\xa7\x70\x81\x1e\x0f\xae\x97\x32\x15\x8c\xbd\xb4\xac\x17\x47\x5d\x52\xe4\x5c\x27\x4c\x8f\x49\x91\x2f\x70\xd3\x06\x97\x4a\x12\x2e\x3b\x09\xa6\xa0\x3c\x41\x3c\xd3\x7a\x62\x89\x1e\x1c\x23\x0d\x09\x8e\x95\xe2\x3e\x56\x8a\x5b\x31\xf1\x47\x76\x05\xb5\xc5\xae\x1c\x81\x4b\x2b\x56\x69\x44\xcb\x83\x12\x16\x6d\x26\x99\x3a\x62\xb8\x72\x0a\xb4\x16\x9d\x5a\xbc\x52\xba\xfc\x61\x88\x87\xa3\xbf\x99\x1d\x71\x97\x4d\xbe\x5f\xe6\x53\xce\x3e\x5d\x4f\x3e\x5d\x3b\xd3\xdd\x27\x7c\x24\x21\xa3\xde\xc9\xdf\xce\xd4\xe2\x9f\x9c\x27\x23\xa8\x70\xf4\xf7\x27\xa7\x6d\x79\x32\x82\x02\x47\x7f\xdb\x11\x3b\xc9\x12\x99\xc9\xea\xa6\x39\x9b\x9d\x51\xb3\xa4\x61\xe5\xee\x27\x8b\x29\x58\xbc\xf9\xfb\x53\x69\x35\x9f\x4a\xeb\xc9\x68\xf1\xc0\xfb\xba\xaf\xa3\xb0\x8c\x6a\xbf\xee\xaf\x8f\x24\x18\x4f\x3c\x43\x09\x6e\xa1\x2f\x45\x63\xce\x73\xa7\x44\x59\x9e\xcd\xce\x58\xac\xe3\x48\xdf\x0d\xe3\xc8\xf6\x7c\xaf\xbf\xf2\x18\x92\x16\x8a\x31\xee\x01\x09\xd8\x38\x7c\xda\x72\x75\x16\x0f\x8d\xef\x06\x22\xab\xb0\xba\x77\xad\x15\x79\xcf\x7c\xe3\x92\x3c\xef\x68\xec\x3f\x87\xc4\x34\x93\x21\xa6\x91\xf0\xb3\x5b\x4e\x6f\x2c\xc5\x04\xb6\xd7\xc8\x34\xb2\xfd\x7b\x05\x86\xeb\x50\x0b\x87\x7a\x88\xf1\x3d\x75\x19\x43\xca\x83\x2f\xfa\x8a\xd2\x50\x4e\xbc\x61\xb1\x24\x32\x06\x97\xb3\x52\x0c\x0c\x2b\xf1\x0d\x83\x93\x7f\xdf\xe6\x71\x6b\x0e\xb4\x71\xda\xef\x6d\xee\xc4\x98\xb7\x09\x17\x78\x8b\xae\x3a\xdd\x0f\xce\xec\xb2\xcc\xd3\xba\x12\xca\x07\x44\xf5\xfe\xf0\xc4\xdb\x7b\xb8\xa5\x2c\xef\xdf\x03\x30\xe1\x94\x24\x86\xe2\x16\x3e\x38\xb1\x90\xe9\x23\xd1\x40\x77\x1f\xa2\xe6\x03\xfd\x55\x49\xb4\x31\x57\x73\xf2\xd5\x7a\x56\x88\xf9\x87\x1c\x3f\x38\xf1\x6a\x8d\xdb\x34\xef\x41\xbc\x45\x0f\xa4\x02\xb0\x55\x58\xa1\xe6\xb7\xe9\x9b\x77\x2a\x6f\x8f\x1f\x9c\xf9\xfa\xb1\x9c\x44\xa1\x4a\x3b\x5a\xa3\x54\xf4\x44\xad\xd3\x54\xbb\xe9\x8c\x65\x58\x74\x77\x8b\x1e\xd9\x07\x8d\xe6\xe8\x86\xf3\xdd\x1b\xc8\x90\xc2\x23\xed\xc3\x65\x3b\x9e\x8b\xe8\x06\x99\x92\x2e\x41\x32\xda\x82\x73\x43\xa1\xa2\x4c\xb7\x25\xc7\x5c\x5e\xc9\xb9\x98\xff\x76\x83\xea\xf9\x57\x3b\xdb\x83\x57\xf7\x77\x06\xef\xe0\x2b\xdf\x02\xa1\xd2\xee\x62\x21\x8a\x0e\x96\x6a\xf8\x15\xc0\xfd\x47\x00\xba\xe0\x29\x80\xe2\x5b\x3d\x4b\x89\x4e\xe2\xdb\xaf\xa6\x3f\x05\xd2\x6a\x8f\x53\x3b\x49\xf3\xbc\xf8\xe7\x47\xbc\xa7\x26\x2d\x0a\x31\xab\x44\xf1\x61\x39\xcb\x90\xa2\xc1\x5f\x2d\xfc\xec\x91\x23\x0e\xdd\x7b\x10\xce\x8b\x23\xda\x82\x62\x97\x45\x25\x7e\x05\xeb\x80\xac\x08\xb2\xec\x91\x7d\x70\x1d\xf9\x67\x04\x58\x96\xc7\xa4\x87\xc4\xc3\x2d\x0d\x87\x9a\x63\xf4\xa8\x96\xfc\xd8\x3e\xff\x7a\xb8\x69\x6e\xb1\x4e\xa8\xdb\x3a\xbe\x1a\x6b\x58\x67\xb3\xb3\x47\xe6\xab\xa1\x65\x3b\x42\x2c\x66\x95\xbc\x12\xd8\xbe\x3c\x42\x70\x3d\xfc\x85\xab\x27\xfc\xb7\x28\xf2\xff\x09\x27\x17\x5b\xfe\x9f\xb8\x53\x9a\x91\x8a\xb2\x6c\x8f\x23\xfd\xe5\x71\x3c\x7f\xe4\x38\xf4\x82\xdd\xf4\xed\xb3\x48\x7f\x7d\x16\x87\xca\xde\xfe\xef\x87\xa1\x6e\x8e\xf0\x83\x53\xd6\x97\xf7\x40\xdd\x8d\x18\x14\x8c\x04\x4b\x47\xd5\x6a\xbd\x55\x62\x88\x5b\xbc\x9e\xa9\x5a\x9e\x61\xd2\x34\xc3\xec\xae\xfe\x54\x8e\x23\x19\xcd\xe1\xa6\xc0\x8a\x14\x98\x9d\x41\xe9\xac\xd3\xba\x64\x82\x07\xca\xaa\xa0\x3a\x41\x50\x39\xea\xd1\x0d\x2c\xb1\x74\x62\x58\xa0\x68\x55\x48\xda\x34\x43\x7d\xd1\x3a\x5c\x36\xcd\x70\xd1\x01\x5b\x46\xac\x85\x27\xb8\xaf\xd7\x5c\x44\xa5\xdf\xad\x3b\x5c\x6a\x57\x76\xab\xba\x60\x40\xcf\x0f\x67\xd1\xc0\xa8\xf4\xf7\x10\xbf\x46\xb6\xeb\xbb\xca\xd6\xa7\x58\xb1\x94\x2b\x3f\x56\xdd\x49\x2f\x7b\xbf\x2e\xc1\xd4\x8e\xb5\x1b\xc0\x6a\x74\xc3\x84\x47\x2c\x41\x3b\x81\x1c\x97\xdc\x67\x31\xa6\x90\xe3\x82\xac\x41\x21\xae\x44\x41\xb6\x0a\x32\x4c\xd4\x05\x6f\xbe\xb9\x03\xda\xea\xbe\xdd\x0a\x6a\x58\x8d\x2c\xe9\x6f\xad\xf9\x0b\x96\xf5\x77\xfb\x9c\x47\x89\x9f\x41\x82\x19\xba\x81\x0c\xb3\x20\xd3\x81\xcf\x72\x92\x4d\x87\xb8\x20\xad\xf9\xb3\x46\x7a\x7b\x41\x2f\x9b\xcb\x04\x0a\x7d\x73\x24\xaf\x78\x01\x0b\xcc\x41\x11\x40\x38\x25\xe1\xc5\xe4\x06\xbe\xad\x52\x15\x9d\xdf\xdb\xdd\x54\xeb\x9b\xe9\x49\xd1\xba\xb8\xd4\x94\xe1\x99\xed\x05\x32\x4c\xf4\xf5\xc8\x52\x5d\xb1\xbe\x58\xa8\xd0\x4b\x17\x5a\xc9\xa0\x30\xcd\x21\x75\x14\x53\x9a\x3c\xc5\x8c\x07\xb6\x4d\x4f\xb0\x9c\xc8\xa9\x85\x67\xb7\xf4\x6b\x23\xcd\x52\x77\x19\x14\x2a\xd3\x51\x04\xcb\x3e\x52\xb6\xed\xb8\xd7\xf8\xea\x94\x4e\x98\x80\x25\xc4\xdc\x57\x87\xa8\x4f\xcc\xf3\x3d\xd8\xba\xcc\x00\xa1\x14\xe1\x2a\x9f\xd7\x29\x09\xcb\x2a\x9f\x3f\xc2\xe1\xfa\xd6\x5c\xd5\x20\x6e\xcc\x9e\x77\x97\xb7\x87\xd2\x89\x9b\x66\x28\x9c\xb2\x69\x04\x89\xf6\x50\x17\x2e\x44\x1b\x06\xf7\xa9\xa9\x69\xa4\xea\x95\xdb\xbd\x92\xfb\xec\x10\xf1\xcf\x88\x15\x4a\x44\x94\xed\x86\x0a\x5f\x31\x09\x02\x5c\xd8\xe3\xaa\xa9\x80\xca\x29\x77\xb1\xe0\xfe\xa6\xeb\x4f\x0e\x52\x0b\x28\xab\x1c\x75\x51\xcb\x04\xd7\x36\x21\x23\x6d\x25\xe6\xa8\x9e\xfe\xa9\xef\xa0\xce\x5a\xfb\xbb\xda\x58\x92\xf4\x91\xfb\x31\x7f\x8c\x32\x1d\x5d\x20\xa7\x78\xb3\x95\xfa\xf1\xa3\x52\x9f\xff\x5a\xea\xf3\x87\x52\xdf\xed\xa9\x15\xfb\x1a\x55\x7c\xa8\xab\x40\x46\x37\x90\xa8\x70\x36\xed\xc5\xbe\x6e\x9a\x61\xa9\xc5\x9e\xb4\x4b\x7a\x77\x9d\xbc\x93\xf2\x44\x4b\x79\xba\x25\xe5\xf4\x4c\x6e\xa0\x1a\x48\xfd\x91\xf4\xdd\xdd\x5c\x89\x75\x8d\x15\xab\x39\x29\x36\x56\x92\x28\x27\xbd\x58\xe7\x58\xdb\x6d\xde\x2c\x0f\xdd\x88\x95\x58\x43\x81\x29\xf7\x59\x8e\x76\x0e\x05\x26\x1c\x8a\x8d\xcc\x06\xb9\x6d\x07\xc5\x46\x9c\xb7\xba\xda\x9b\xb9\xa4\x0b\x77\x32\x4c\xbb\x47\x37\xcc\xed\x4c\xd5\xdd\xa5\x40\xee\x69\x82\x05\x64\x98\xd3\xea\x6e\x90\x05\x3c\x47\x96\x4c\x6c\x3b\x9b\x62\x32\xc9\xa6\x56\x4a\x7f\x72\x3e\x3a\x6b\x5c\xa0\x86\x1d\x3c\xeb\xce\x35\x37\x4d\x96\xf4\x21\x57\xce\xc1\xb2\x4a\x0e\x24\x1f\x09\x94\x8a\x57\xfa\x3a\x00\x52\xf3\xdb\x27\xad\xcf\x59\x65\x3d\xf4\x49\x4b\x2c\x34\xd1\xfb\x0c\xaa\x18\xaa\xf4\xbd\x69\x7a\x43\xa4\x77\x57\xff\x30\x9d\x7f\xdb\x03\xa3\xcb\x39\x1b\x2a\x05\x0f\x62\xa8\x87\xb7\x59\x58\x4e\xc2\x73\xdf\xf3\xab\x50\xf6\x5e\x1f\x64\x58\xed\xde\x58\x24\x10\x72\x52\xb5\x5a\x23\xa8\x5a\x77\xaf\x52\xee\x5e\x46\xee\x9e\x4e\x63\x4a\x52\x0b\x95\x0a\xb4\xda\x3e\x0a\xb4\xfa\x5b\x4b\xd3\x2c\xc8\x05\x0a\x89\xb2\xe4\x5b\x0a\xcb\xe3\xa0\xcc\x9c\x2a\x7b\x78\x4c\xfc\x1f\x11\x15\xa6\x2b\x91\x44\xd3\xf4\xf9\xe3\xa7\x9c\x9b\xe6\x47\x56\xc1\xbf\xff\x2d\xac\xde\xd3\xba\x53\x60\xec\xc2\x73\xf0\x9e\xea\xca\xa7\xcc\xff\xca\xa1\xa2\x75\xd5\xa9\x3c\x24\xf9\x1d\x85\xa3\x6e\x75\x2e\xe0\x02\xbc\x67\x5b\xf4\xe4\x51\xd6\xca\xbc\xe1\x09\xc3\x52\xb5\x33\x2d\x2b\x67\xa4\x65\x32\xa5\x64\x4c\x93\xd9\x17\xba\x68\xe6\x82\x66\x94\xbb\xea\x1e\xc8\xf5\x3d\x52\x4a\x99\x3a\xff\xf2\x5b\x3d\x2b\xc4\xfb\x3c\xaf\x88\x01\xbe\x15\xd5\x63\xce\xfa\x03\x3b\x4f\x22\x58\x3a\x25\x45\x7a\xaa\x90\xea\x9d\xb5\x0f\x8b\x96\x5a\x86\xeb\x3c\xd5\xc1\x1e\xb1\x05\xd9\x65\x92\xcc\x64\x4b\xf4\xf4\x38\x32\xd9\xae\x0a\xeb\x69\x80\xea\x8f\xdc\x91\xeb\x27\x51\xa9\x10\x0c\x94\x7d\x55\xa9\x7f\xc2\x8b\x11\xe7\xba\x0a\x60\x8a\xe8\x8d\xdc\x88\x4e\x91\x25\x1c\x58\x57\xc6\x63\xc5\x7c\x67\x8c\xaa\x8a\x31\xd3\x35\x52\xb0\x0d\x20\xd3\x86\x9a\xc5\x96\xc7\x47\x63\x6e\x33\x37\x8c\x9b\x26\xde\x19\xd3\x30\x05\x31\x43\x4d\x4e\x9f\x91\x34\xde\x29\x75\x51\xe6\x39\xdb\xd4\x64\x6f\x2a\x2c\x85\xc1\x2d\x8f\x5b\x31\x07\xd9\x52\x20\xe3\xdc\xef\x9e\x53\xcb\x30\x48\x53\xd3\x79\x28\x43\xa9\xb2\x61\x90\x62\x6c\x2d\x61\x4f\x6d\x3f\x25\x83\x19\xe8\xfa\x57\x09\x64\x69\xf5\xd1\xd6\xda\x01\x7a\xc5\x4a\xa8\x61\x09\x9e\xba\x9c\x63\xb5\x13\xf3\x1e\x8d\x94\x6b\x37\xae\x60\xd2\x89\xf9\x76\xbb\xd2\x89\xd2\x11\x2f\x62\xd3\xb4\xed\x74\x0b\xf9\xd4\xde\x83\x94\x78\xdf\x38\x3c\x3c\x3c\x34\x14\x8f\xb2\xbc\x69\x8c\xfd\xf6\x95\xf3\x9f\x6c\x68\x65\x4d\x33\xb4\xb2\xbe\x10\xd9\x34\x8d\xa7\x06\x62\xd6\x55\x06\xba\xc4\xf4\xec\x23\x93\x20\x1d\x61\xbd\xb3\xc6\x40\x31\x27\x0e\x65\x8b\xbc\xe4\x8e\xf8\xc6\xca\xed\x6a\x85\x61\xae\x66\xd4\x50\xb7\x33\x5c\x0e\x75\xb7\xd7\x6e\x38\xff\x29\xb1\x6e\xe7\x2c\x2d\xdc\x87\x94\xfe\xe4\xe8\xdd\xf6\x81\x4d\xb7\xa4\x07\x5f\x5b\x33\xae\x60\x90\x15\xaf\xd3\xff\xc9\x4f\x6d\xeb\x80\xba\x04\xea\x4a\xa7\x50\x35\x57\x9f\xe3\xa5\x13\xc3\x05\x92\x1d\x3b\xb8\x63\xc7\x78\x97\x39\x3d\x37\xcd\x0b\x9d\x41\x32\xcd\x8b\xad\xcc\xe9\xf0\x92\x0c\xa7\xf6\x00\xce\x4d\x73\xa8\x47\x0c\x2f\x9a\xe6\x82\x7e\xf4\xdb\x79\x5f\x5f\x21\xda\xf8\x5f\x79\x27\xbb\x78\xe9\x94\x40\x90\x23\x5d\x6b\xe1\xea\xfa\x15\x97\xfb\xdb\xf5\x18\x1c\x44\x5b\x92\x56\xb1\x4b\x15\xc9\x58\x15\x13\x3a\x61\xda\x43\x49\x37\xb9\xb3\x05\x5e\xf4\x8f\x8a\xc7\x56\x78\x0e\xe7\x78\x01\x17\xb8\x82\x5c\x99\x15\xe5\xe4\x91\x49\x49\xad\x05\xac\x70\x32\x55\xb6\x6a\xb5\x55\x7e\x94\x17\xec\x1a\xcf\xe0\x0a\x5f\x92\xab\x1a\xd8\x76\x1e\xa2\x1b\x6c\x8a\xe4\xd7\x78\x31\xc9\xa7\x3b\x57\x30\x57\x0f\xa3\xab\xc6\x85\x12\x53\xa8\x31\xb7\xca\xa0\x0e\xf3\x80\xc7\x78\xae\xee\x4d\x76\xae\x60\x89\xe7\x93\x52\x0f\x4a\x70\xbe\x1b\x5b\xcb\xdd\x35\xc4\xb8\xde\x8d\xad\x64\xe7\x6a\xf7\xca\x5a\x4d\xea\xa9\x55\x40\x81\x2c\x1e\x5d\xab\x1b\x82\x84\x46\x73\x6b\xbe\xbb\x84\xd5\xa4\xb6\xed\x29\xc6\x3b\xd7\x01\x8d\xc3\xa2\x63\x87\x22\xb2\x2c\xe9\xaf\x7a\x67\x90\x6c\xdb\x0a\xa4\x66\x8b\xb6\x6c\xed\x1f\xaa\xf6\xc1\xbd\xcb\x41\x8f\x94\xfb\xf3\xed\x52\x39\x7d\x51\xa8\x5c\xa4\x0c\x1f\x2a\xf8\xe7\xbd\x82\x07\x11\x91\x41\xa0\xe5\xfc\x4a\xa3\xb2\xa5\x4b\x1e\x0f\xcb\x3e\xb7\xa1\xd8\x83\xfb\xc9\x43\x1e\x91\x65\xf1\xda\x85\xa9\x41\x83\x54\x95\x77\xff\x37\x60\x63\x57\x03\xeb\xcc\x54\x07\x73\xec\x76\x30\x55\x0d\xdf\xa3\x14\xfb\x25\x4c\xef\x17\x30\x3d\xa5\xc3\x75\x9c\xbb\xe5\x36\x3a\xe5\x3a\x95\x95\x2e\x4d\xcf\xd1\xfa\xcb\xe9\x0b\x79\xa0\xa6\xd7\x87\xb5\x3c\x50\x62\x37\xaa\xab\xe2\x21\x4f\x90\x84\x25\x45\x39\x51\x25\xda\x5d\xfc\x0d\x33\x8c\xa3\xa4\xd7\x5b\x7e\x02\xcb\x4d\xf9\x53\x1b\xe6\x14\x98\x93\x27\x07\x35\x16\xb0\xb4\xb1\xe0\x90\x87\xae\x69\x2e\x43\xb7\xe3\xee\xe5\x4e\xde\x34\x39\x24\x38\x6b\xbf\x89\x60\x2e\x14\x3c\x58\x86\x45\x50\x58\x98\xf3\xc4\xc2\xd2\xea\xfb\x0a\xc8\x79\x50\x87\xaa\x7c\xbe\xed\x50\xcb\x17\x9c\x43\xac\x6a\xea\x0d\xdb\xb0\x12\x7e\x5b\x61\x1a\x25\xd6\x5f\xce\xfd\x12\x27\x8b\x82\x44\xeb\x2f\xe7\x41\x59\x12\x8f\xd2\x4d\x66\x72\xeb\x4b\xa1\x4f\x9f\xe6\x3f\x0d\xab\xb6\x8c\xdb\x4f\x9f\x7e\x33\xc0\x58\x18\x1c\x8c\x27\xa6\xf1\x00\x46\xb7\x02\xf7\x53\xee\x27\x9b\xc2\x5c\x7d\xd8\xed\xd0\x47\xdd\xbe\x7b\x4a\x13\xbf\xc0\x42\xab\xca\x35\x2e\x9c\x18\xe6\xfd\xbd\x3a\xac\xb0\xda\xbc\x5c\x63\x72\xe7\xc6\xbd\x67\x17\xf6\x05\x87\x1e\x94\xd8\x97\x62\x7f\xc1\x25\xb0\x21\xa3\x48\x5e\xe5\x70\x18\xe7\x4d\x53\x3a\x69\xc5\xbe\x29\xe3\xa2\xcb\x23\xc6\x60\xac\x66\xdf\x07\x73\x91\xe5\x2b\x99\xd1\x56\x06\x86\xc5\x96\x91\x71\xaf\x06\xf8\xb1\x12\x60\x81\xc3\xa5\x69\xaa\x84\xcb\x47\x56\x82\x76\xcc\x3c\xee\x2c\x2a\xc1\xbe\xf1\xa8\xf4\x3b\x37\x74\xdd\xc7\xfe\xdb\x65\xe8\xda\x5c\x17\x6c\x4d\x7c\x3a\x77\x04\xf6\x89\xa3\x85\x23\x6c\x0f\xe6\xca\xaa\xe3\xfb\x09\xab\x31\xdf\xb9\xe1\x2f\xdc\xe8\xc6\xaa\xfd\x7a\x4a\x0b\x0b\xda\x4b\xbc\x5a\xb3\x39\x0f\xdd\x88\x82\x85\xb9\xbf\xf2\x4b\xa8\xf1\x07\xfc\x20\x6f\xa3\x27\x45\xcc\x21\xd1\x90\xdc\x20\x45\x32\xf7\x73\x95\x1d\x54\xb2\xa2\x5c\x80\xb4\xb5\x92\xd7\x9c\x83\x37\xa4\x10\x68\xb5\xa6\x08\x89\x57\x78\x0d\xd7\x28\x61\x85\xc9\xdd\x91\x12\x57\x9c\x22\x17\x09\x73\x2c\xdb\x90\x6a\xd3\x37\xe7\x14\xdc\xc8\x4e\xef\x49\x7c\xc5\x44\x17\x4b\x72\xb8\xd6\xab\x27\x1d\xcc\xce\xa4\x13\xc4\xaa\x43\x49\x6e\xa1\x94\x38\x25\xae\x9c\x12\x17\x4e\x09\xf9\x2e\x8e\x21\xc3\x57\x8c\xac\x6b\x0e\x5f\x79\x0b\x77\xc1\x9d\xd9\x65\xc9\xb8\x42\xfd\x15\x4b\xa0\x7a\xac\x97\xbf\xf0\xa2\xc9\x6a\xeb\x0c\xe0\x7a\xeb\x65\xea\x4f\x92\xed\xbe\x6a\xbb\x0f\x7e\x60\xad\xdd\xf9\x2a\xd7\x35\xc2\x0f\x23\xdf\x2d\xc7\xda\x12\x4d\x43\x06\x38\x72\x77\x85\xa3\xf3\x41\x7a\xee\xbb\xfc\x5a\xa5\x15\xd7\xf9\xf5\x2f\xa2\xa1\x55\x57\x4d\x65\x09\xde\xa5\x07\xc8\x41\xe8\x5d\xf5\xf1\x1e\x18\xa2\x55\xf7\xaa\xfe\x67\xd8\x65\x35\x99\xe0\x4d\x53\x84\x17\x14\x03\x8d\xd0\xe5\x4d\xb3\x9e\x15\xa5\x38\x4e\xf3\x59\xc5\x04\x57\x72\x32\x64\x02\x09\x9d\x7b\x37\x0d\xca\x8f\x5d\xe7\xd7\xcc\x92\x20\x78\x97\x61\xf9\x3d\x9a\xb3\xdf\x47\x37\xd6\x98\xfb\x2e\x6c\xa4\xb0\xad\x48\x2d\x76\xc6\xea\x57\x5d\x8b\xb4\x6e\x19\x0c\x2b\x27\x6e\x2b\x45\x33\xd3\xac\xfa\x6c\xa8\x0a\x8c\x36\xaf\x98\x71\x5d\x1e\xbc\x62\xc5\x68\xcc\xa1\x2b\x5a\x0e\x24\x6e\x7c\x3c\xc8\x4c\x53\xa5\x35\xe4\x5d\x30\xf2\x0e\x98\x3b\xd9\xf8\x0a\xbf\x39\x73\x79\xc5\x2a\xce\x21\x53\x56\xf2\x77\xf8\xda\x5b\xc9\xbe\x48\xfc\x9f\x9b\x35\x55\x15\xb7\xff\x2b\x33\x0d\xe3\xfd\xf6\x60\x35\xa7\x3c\x76\xa6\x5d\x7c\x5b\x11\xff\x62\xe5\x88\x60\x2b\x28\x45\xc4\x3c\x92\x14\x6c\x18\xdd\x1d\x99\x01\x6e\x28\x55\x14\x49\x6a\x9d\xbc\xfd\x0c\x8d\xb3\xd9\x99\xe1\x2b\x57\x9c\xe8\xdb\xfb\x07\x2d\x92\xea\x0b\xd3\xf1\xd3\xee\x13\xd3\xe8\x35\x4b\x59\x06\x39\x07\xb7\x11\xe0\xb9\x20\xb9\xff\x5b\x88\x64\x73\x42\x7c\x12\x25\xaa\xcf\xef\x86\xd0\x62\x55\x17\xd1\xf5\x8b\xb6\xcc\x5e\xd4\x59\xdc\x66\x7b\xd4\xf3\x3f\xbf\x0b\xd0\xf7\x0f\x57\xb3\xb4\x16\xe7\x09\x4d\xcf\x7f\xbf\x38\x7f\x24\x13\xae\x53\xdb\x1b\x51\xbb\xdd\xd0\xbf\xab\x3a\x25\x75\x3e\xdb\xd4\x4b\x54\x9b\x58\xd6\x6d\x7a\x6a\x8a\xd0\x6d\x1a\x81\x88\x59\x94\xf9\x99\xed\xdd\xa9\xaf\xd8\x54\x56\x68\x21\xf3\x40\x6e\x8a\x50\x72\xf5\x9d\x8a\x65\x18\x81\x0c\x8b\xd6\x03\xcd\x50\xa8\x6c\xa3\x65\x18\x50\xe1\x8d\xdd\x7f\xcb\x51\xd9\x76\x90\x51\xf4\x67\x65\x3c\xc8\x2d\xcc\x6e\xdb\x42\x90\x3b\x5f\x25\xe6\x77\xbf\x4a\x94\x3c\xe8\xdd\xc0\x7c\xf3\xbd\x9f\xe5\x35\x8d\xc7\x37\x88\xca\xfb\xb9\x41\xe1\xc4\x90\x53\x54\xa4\xbe\x29\x2a\x49\xa7\x3b\xa5\xaa\x9f\xa1\x18\x2f\x73\xc4\x56\x96\xea\x61\xa6\xc3\x34\x87\xca\x89\x29\x30\x37\xcd\x61\xae\x8a\xba\x9a\xa6\xbf\x0d\xab\xa2\x22\x72\x7d\xbb\xf4\x6b\xe5\xb8\x0c\xb1\x87\x51\x6b\x00\x6e\x58\x43\x81\x09\x62\x0a\x43\xd9\x34\xc3\x9c\xf7\x5e\xb1\xeb\x0f\xe5\xdf\x95\x2e\x6b\xb9\x73\xc5\x96\x84\x69\xd7\xae\x8b\x8b\x58\xd2\xa7\x5c\xf8\x0b\x96\xf6\x74\xe2\x51\xe2\x93\x33\xef\x06\x65\x58\x07\xb5\xce\x22\xcb\x49\x3d\x1d\x62\x3e\xa9\xfb\x60\x9e\x5a\x42\x6a\xe8\xa0\xf6\x9f\x49\x63\x1a\xb9\xfe\x66\xb9\x0d\x15\xf3\xbb\xb7\xb7\x4c\xe8\x8f\x7f\x42\x72\xa6\xab\x10\xb7\xaa\x7d\x6a\x62\x8c\xf6\xa3\xbf\x89\x2e\x8e\x1c\xa8\x52\xb8\xa9\x81\x78\xae\xde\x37\xe5\xe7\x3d\x8b\xea\xef\x91\xc4\xd6\xb9\x95\x0f\xbe\xff\x21\xf7\x46\x45\x5b\xb5\x2a\x94\xef\xbf\x77\xa2\xbd\xb6\xdf\x80\x6e\x38\x46\xda\x76\x90\x4f\xe4\x74\x17\xb3\xb6\x1e\x6c\x52\xa0\x3b\xb5\xf0\xbc\x4f\x03\x88\x2e\x30\x26\x42\xf1\xa0\x78\xd1\x4f\x2e\x2c\x8b\xe7\x93\x62\x1a\x56\xea\x6b\x5d\xad\x53\xf2\x49\x61\x79\x24\xce\xfa\x01\x5d\x0e\xfa\xc9\xa2\xae\xe9\xa8\x6a\x5c\x6a\x98\xee\x60\xd5\xeb\xcf\xed\xbb\x80\x7e\x67\xc9\xb6\x7e\x64\x9b\xaa\xa2\x48\x6c\x22\x75\xcb\x70\x0c\x4b\x6c\x5c\x62\xc1\x2d\xe6\x86\x59\x64\x90\xdf\x24\x2c\x83\x5b\xd9\x06\x60\x7a\x87\xc5\x75\xd9\x5a\xd6\xb9\xc5\x86\xeb\x18\x81\x65\x65\xe4\x04\xab\x6f\xd0\x04\x16\x96\xe8\x0b\x0c\xab\x8d\xc8\x5a\x56\x16\x56\x9b\x69\x06\x64\x36\x56\x81\x6d\x6f\x4d\xb5\xb0\xd0\x33\x2b\x65\x33\x36\x75\x65\xfa\x93\xf7\x2d\x9c\x33\xbe\x89\xd1\x36\x98\xc6\x1b\xe6\x18\x08\xbc\x63\x48\x81\x2c\xf4\x9c\x09\xee\xaf\x88\x0f\x68\x33\x33\x1d\xf7\xeb\x6a\x87\x4f\x73\x8b\x7d\x72\x3e\xcd\x77\x79\xd4\xd0\xaf\xc5\x99\x98\x58\xf6\x34\xa2\xc7\xe8\xc9\x88\xdc\x26\x65\x70\x63\x21\x53\x58\xe9\x67\x75\xd5\x0a\xd7\xd8\x56\xeb\x0e\x2e\xf3\x3c\x15\xb3\x6c\x90\x17\x83\x4b\x99\xcd\x8a\x9b\xc1\x9c\xc2\x4d\x03\xae\x50\x7f\x49\x25\xb3\xc5\x60\x95\xcf\x85\x01\x97\xdd\x87\xe9\x03\x62\xd4\xc1\x72\x56\x0e\x56\x79\x21\x06\xd5\x72\x96\x0d\xbc\xa7\x83\x52\x2e\x32\x99\xc8\x78\x96\x55\x1a\x48\x69\xc0\x39\x1a\xae\x37\xde\xdb\x7f\xfa\xec\xe0\xf9\xe1\xec\x32\x9e\x8b\x64\xb1\x94\x5f\xbe\xa6\xab\x2c\x5f\x7f\x2b\xca\xaa\xbe\xba\xfe\x7e\xf3\xe3\xe5\x6f\xaf\x5e\x1f\x1d\xbf\xf9\xd7\xc9\xef\xff\xdf\xe9\xdb\xb3\xf3\x77\xff\xff\xfb\x8b\x0f\x1f\xff\xf8\xf3\xaf\xff\xfa\xef\x27\x9f\x0d\x38\x43\x4f\x78\xfb\x70\x83\xde\x3e\x5c\xdc\x2f\xec\xf5\xe0\x3d\x4e\x3c\x32\x3f\x9e\xeb\x82\x27\xf6\xc0\x13\xfb\xe0\x89\xa7\xe0\x89\x67\xe0\x89\x03\xf0\xc4\x73\xf0\xc4\x21\x78\x82\x06\x09\xcf\xa3\x3f\x63\xfa\xb3\x37\x85\x97\xea\x43\x8e\x23\xf4\xc4\xa1\xfa\xa2\x4a\x55\x51\x1a\xdd\xf1\x6c\x8a\x9d\xe7\x22\x91\x99\x30\x4d\xfd\xeb\xcc\x56\x73\xae\x1f\xd9\x43\x53\x33\xbb\xdd\x7c\xb7\x69\xd4\x99\x1e\x37\xdf\x54\x7f\xab\x0b\x1b\x61\x9a\xfa\xd7\x21\x2f\xab\xa8\xf4\x05\xc0\xdd\x26\x9c\xc1\x70\xc9\xab\xe2\xe6\xe7\x12\x0b\xf1\xad\x96\x85\x60\x6d\x3d\xa8\xc1\x6f\xe3\x59\x15\x2f\xd9\x6b\xfe\xf3\x56\x73\xa0\x70\xfa\x2f\xcb\x70\x76\xdb\x66\x05\xfe\x63\x34\xfa\xcf\x41\x99\xd7\x45\x2c\xde\xce\xd6\x6b\x99\x2d\x3e\xbe\x3f\xc5\x79\x1e\xdf\xf9\xf7\x1a\xce\x6a\xb6\xfe\x8f\xff\x17\x00\x00\xff\xff\x2f\x88\x72\xca\xa2\x43\x00\x00") + +func bignumberJsBytes() ([]byte, error) { + return bindataRead( + _bignumberJs, + "bignumber.js", + ) +} + +func bignumberJs() (*asset, error) { + bytes, err := bignumberJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "bignumber.js", size: 17314, mode: os.FileMode(420), modTime: time.Unix(1484232218, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _web3Js = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\xbd\xf9\x7a\xdb\x38\xb2\x38\xfa\xbf\x9f\x02\xd6\x3d\x37\x92\x62\x46\xf2\xd6\xe9\x34\xdd\xee\x8c\xb3\x74\xc7\x73\x92\x38\x5f\x12\x4f\xcf\x1c\x8f\x4f\x3e\x4a\x84\x24\x74\x28\x52\x3f\x92\xf2\xd2\xb1\xdf\xe5\x3e\xcb\x7d\xb2\xdf\x87\xc2\xbe\x70\x91\xed\xf4\x36\xf6\x1f\x89\x08\x14\xb6\x42\xa1\x50\x28\x14\xaa\x72\xfc\x7f\x96\x24\xc7\xfb\xbd\xc9\x32\x1d\x97\x24\x4b\x11\xee\x95\x41\x1a\xe4\xfd\x2f\x32\xa5\xe8\x65\xc1\xb2\xff\x85\x4c\x7a\xeb\xe9\x49\x76\xca\x7e\x95\xf0\xeb\x2c\xca\x51\xb4\x5f\x5e\x2e\x70\x36\x41\xa2\xae\xfd\x8e\x28\xda\x79\xf0\x80\x27\xee\xd1\x32\xcb\x07\x0f\xa2\x7e\x8e\xcb\x65\x9e\xa2\xa8\x97\x05\xeb\x9b\x7d\x9a\x4e\x44\x1a\xe1\x69\xb4\xd6\xc9\x7e\x8a\xcf\xd1\xcb\x3c\xcf\xf2\x5e\xe7\x79\x94\xa6\x59\x89\x26\x24\x8d\xd1\x3c\x8b\x97\x09\x46\xdd\xce\x46\xb6\xd1\xe9\x76\xfa\x7b\xe5\x2c\xcf\xce\xd1\x64\x30\xce\x62\xbc\xdf\x79\x73\xf4\xe2\xf8\xf5\xcb\x4f\x6f\x8f\x3e\x7e\xfa\xf1\xe8\xf8\xed\x8b\x4e\x30\xb9\xa6\xf5\x25\xfb\xb4\xef\xfb\x5f\xf0\xc5\x22\xcb\xcb\x22\xfc\x72\x7d\xbd\x47\xc7\x70\xb2\x79\x3a\x18\x47\x49\xd2\x4b\x06\x3c\x2b\x10\xbd\xef\x61\x36\xc0\x74\x1f\x00\xb7\x4e\x4f\xf0\xe9\x1e\xef\x6a\xd1\x4b\x9f\xa6\x21\xee\x5f\x07\x49\xa0\x4a\xe2\x80\xe1\xee\x9a\x43\xd1\x26\x45\x26\xf4\x82\xb4\xc2\xd5\x24\xcb\x7b\x14\x3a\xdb\xdf\xdc\xcb\xbe\xcf\x07\x09\x4e\xa7\xe5\x6c\x2f\xdb\xd8\xe8\x17\xbd\x9c\x22\x5e\x76\xe3\xba\xdf\xfb\xb2\x15\x9e\xc8\x2e\xf3\x2a\x02\x86\xa5\x80\xb7\xdd\xff\xb2\xc6\x12\x44\x67\xf6\x4f\xd6\x10\xfa\xb2\x86\x10\x42\x9d\x71\x96\x16\x65\x94\x96\x9d\x10\x95\xf9\x12\x07\x2c\x95\xa4\x8b\x65\x59\x74\x42\x74\x02\xdf\x02\x1a\xf2\xd2\x68\x8e\x3b\x21\xea\x7c\xca\xce\x53\x9c\x77\x02\x95\x43\x47\x47\x73\xa2\x38\xce\x71\x51\x74\x78\xce\x35\xfc\x7f\xca\xab\x16\xc5\xe1\x7f\x9e\x96\x2d\xcb\xe6\xf6\xb2\x4f\x5a\x11\xa3\xbd\xd1\x65\x89\x8b\x9d\x6d\x7f\x7b\x02\x48\x62\x7a\x0d\xa1\xeb\xe0\x4e\x10\x70\xa3\xfe\xc8\xe1\x68\xd8\x6b\x87\x80\x95\x51\xfd\x47\x1d\xfa\x38\x4b\x4b\x9c\x96\xb7\x1e\xfc\x9f\x72\xde\xe9\x8c\xfd\x61\xa6\x7d\x12\x25\xc5\x6f\x37\xf4\x1c\x17\x38\x3f\xf3\xad\xfa\x3f\xfa\xa4\x15\xcb\xd1\x7b\x3c\x25\x45\x99\x47\xff\x01\x93\x17\xd4\xd5\x81\xcf\x8f\x6e\xc5\xf7\xcb\x3c\x4a\x8b\x89\x97\xf5\xfd\x59\x70\x90\x5b\xa4\xb0\x3a\x12\x0a\x5c\x7e\xa8\x27\xa9\x3b\xc3\x85\xdd\xf4\x6f\xd2\xe8\x57\x9e\x80\xa8\x0d\xe2\xeb\x2a\x58\xe4\x64\x1e\xe5\x97\xde\x7e\x64\x59\xd2\x38\x79\x07\xbc\xad\x3f\x2f\x0a\xcd\x3d\xb8\xb6\x9a\x2a\x24\x3c\xaf\xdc\xc6\xff\x48\x48\xf0\xf6\x3e\x26\x45\x76\x9e\xde\xa2\xe7\x51\x9a\xa5\x97\xf3\x6c\x59\xac\xd0\x75\x92\xc6\xf8\x02\xc7\xc6\xde\x75\x67\x13\xab\x2a\xd7\xba\x63\xd6\x7e\x4e\xd2\xdb\x30\xee\x83\x25\x60\xe2\x65\x1a\xe3\xb8\x63\xa1\x09\x9f\x51\x42\xf8\x0b\xe0\x68\x44\xe2\xb8\x1d\x8e\x6e\x56\xff\x59\x94\x2c\xbd\xdd\x5f\x92\xb4\xdc\xfe\xe6\x71\xfd\x14\xbc\xc5\xe7\xcf\xc8\xef\x88\xfc\x5b\xad\xb9\xe7\xb3\x28\x9d\xfe\x9e\xa4\x73\x27\x94\x53\x51\xb7\x26\xd5\xd7\x52\x8d\x17\x33\xef\xd8\x6e\xd4\x88\xa0\xb5\xd3\xb5\xb5\xeb\xe0\xcb\xf5\x69\xb0\xfd\xbb\x1d\xfa\xff\x42\x67\xde\xdf\x49\x76\x9c\x2c\xd3\xf8\xc6\xa4\x72\xeb\x8d\xeb\xfe\xd8\xfb\xe7\x3e\xf6\xde\x1f\xfa\xfe\xc8\x67\x0e\xef\xe0\xf9\x79\xe1\x8f\x26\x6d\x7e\xdd\xcd\x5c\xed\x55\x3b\x77\xb6\x57\xad\x3a\xef\x93\x3c\x9b\xdf\x72\xda\xcb\xec\x96\x47\xcd\xdb\x09\x7c\xbf\xef\xba\xf9\x23\xe0\x8f\xa4\x31\xc9\xf1\xb8\x3c\xf4\xee\x99\x2b\xf4\xe4\x76\x13\x41\xc6\xd1\xe2\xe3\xef\x3a\x19\x7e\x4c\xb6\x3b\xed\xe2\x45\x56\x90\xba\x83\xfa\x22\xba\x8c\x46\x09\x36\x85\x82\xdf\x85\x2b\x55\xd1\xdc\x9d\x1c\xbf\x6e\x47\x03\x07\x62\xbc\x2f\x4c\x7c\xfe\xf6\x27\x99\x3b\x41\x52\x45\xdd\xed\xe8\xec\x77\x40\xff\x1f\x16\xeb\x77\x71\x7e\xbc\x31\x9f\xfc\xda\x58\xb7\x99\xde\x3d\xda\x5b\xa2\xfd\xd6\x1b\xd7\xd7\x9e\xd9\x43\xcf\x96\x56\x27\xc7\xed\xb6\x91\xe3\xc0\x78\x03\xed\x0b\x0b\x87\x5e\x77\x30\x9c\x64\xf9\x3c\x2a\x4b\x9c\x17\xdd\xfe\x1e\x00\x7c\xc8\x12\x12\x93\xf2\xf2\xe3\xe5\x02\x9b\xb0\xb4\x7d\x0a\xb5\x36\x7c\xf8\x70\x0d\x3d\x34\x20\xb9\xce\x1d\x91\x02\x45\x68\x91\x67\x19\x05\x46\xe5\x2c\x2a\x51\x8e\x17\xf4\x90\x95\x96\x05\xe2\x73\x87\x68\x26\xad\xe1\xb0\x44\xf3\xa8\x1c\xcf\x70\x11\xd2\x4f\x9e\xad\xfd\x3c\x39\xd5\x3f\x76\x8d\xaf\x53\x33\x73\xc7\xfa\x3e\x3d\x79\x7c\x7a\x72\x1a\xa0\xc1\x60\xb0\x86\x1e\x0e\x9d\xb1\x89\x1e\xef\x23\x69\x4d\xd3\xeb\xf3\x29\x2e\x67\xa4\x18\x7c\x82\x85\xf1\xa3\x40\x10\x05\x1c\x30\x74\x1d\xd2\x8c\xc3\xb4\xdc\xd3\x80\xd9\xbe\xed\x83\x3e\x82\x1c\xde\xdc\xde\xda\xf5\xde\xda\x9a\xa7\x1f\x83\x45\x9e\x95\x0c\x6b\xfb\x28\xc5\xe7\x46\x5f\x7b\x5f\xae\xfb\x7b\xf5\xa5\x06\x20\xbd\xe4\xcb\x71\x99\xd1\xc6\x3d\xb0\x4d\xed\x0e\x48\xc1\xe7\x5c\x21\x84\x92\xa3\x40\x0a\xb7\x6b\x59\x5f\xa7\x89\x03\x98\xb7\xde\x90\x63\xbb\xf7\xef\x93\xde\xc9\xe6\xa3\xef\x4e\x1f\xf6\xff\x7d\xda\x7f\x3a\xec\xb3\x71\x9a\x07\x87\xca\x6e\x5d\x07\x5f\x3a\x3a\x29\x76\xc2\xef\x82\x0e\xa3\xb7\x4e\xb8\xb5\x7b\x7d\x1a\x7c\xf3\x3b\x93\xf7\xb3\x2c\x4b\x1a\x68\x7b\x44\x41\x2a\x08\x9b\xe6\x89\xff\x19\x95\xc2\xaf\x5d\xf5\xf3\x54\x4b\xde\xd1\x3f\x9a\xc8\x18\x7a\x76\x53\x1a\xa6\x85\x57\x21\x62\x06\x6f\x53\x30\x4d\x5d\x91\x7c\xcd\x22\x35\xb4\xcb\x5a\xac\x2b\x7b\x13\xaa\xfd\x5f\x8a\x5a\x93\x66\x1f\xfe\x57\x2b\xa2\xe5\xfd\x69\xa6\xd8\xc7\xbf\x37\xc5\xd2\x3d\x4c\x92\x6c\xe9\xa7\xd9\x72\x86\x11\x6c\x76\x40\xb8\x03\x1f\xe5\xd2\x5c\xf9\x83\xd3\x25\xfc\xdc\xd5\x7e\x9f\xea\x19\x3b\xc6\x97\x49\xbf\x88\x6f\xad\xf2\xe7\x13\xa3\x1e\x5e\xd4\x43\xe5\xd0\xc9\x1b\x93\x39\x2d\xbd\x12\x9d\xb3\x02\x0e\xa1\xd3\xe4\x55\x29\xdd\x2c\x53\x47\xea\xac\xd1\xda\xd2\x37\x23\x76\x5a\x09\x23\xf5\x2f\x5b\xc1\x75\xff\x66\x84\xcf\x7b\xd7\x4c\xf9\xdf\xb6\xa1\xfc\xe1\x43\xe8\xf0\xc7\x19\x29\xd0\x84\x24\x98\x52\xea\x22\xca\x4b\x94\x4d\xd0\x39\x1e\xed\x0c\x7e\x29\x06\x6b\x00\xc2\xbf\x28\xc0\x24\xc7\x18\x15\xd9\xa4\x3c\x8f\x72\x1c\xa2\xcb\x6c\x89\xc6\x51\x8a\x72\x1c\x93\xa2\xcc\xc9\x68\x59\x62\x44\x4a\x14\xa5\xf1\x30\xcb\xd1\x3c\x8b\xc9\xe4\x12\xea\x20\x25\x5a\xa6\x31\xce\x81\xe0\x4b\x9c\xcf\x0b\xda\x0e\xfd\xf8\xe9\xed\x31\x7a\x8d\x8b\x02\xe7\xe8\x27\x9c\xe2\x3c\x4a\xd0\xbb\xe5\x28\x21\x63\xf4\x9a\x8c\x71\x5a\x60\x14\x15\x68\x41\x53\x8a\x19\x8e\xd1\xe8\x92\x53\x11\x46\x3f\xd2\xce\x7c\xe0\x9d\x41\x3f\x66\xcb\x34\x8e\xe8\x98\x03\x84\x49\x39\xc3\x39\x3a\xc3\x79\x41\x67\x68\x47\xb4\xc5\x6b\x0c\x50\x96\x43\x2d\xbd\xa8\xa4\x63\xc8\x51\xb6\xa0\x05\xfb\x28\x4a\x2f\x51\x12\x95\xaa\xac\x8b\x02\x35\xd2\x18\x91\x14\xaa\x9d\x65\x62\x65\x93\x12\x9d\x93\x24\x41\x23\x8c\x96\x05\x9e\x2c\x13\x26\x38\x8e\x96\x25\xfa\xf9\xf0\xe3\xab\xa3\xe3\x8f\xe8\xe0\xed\xbf\xd0\xcf\x07\xef\xdf\x1f\xbc\xfd\xf8\xaf\x3d\x74\x4e\xca\x59\xb6\x2c\x11\x95\x28\xa1\x2e\x32\x5f\x24\x04\xc7\xe8\x3c\xca\xf3\x28\x2d\x2f\x51\x36\x81\x2a\xde\xbc\x7c\xff\xfc\xd5\xc1\xdb\x8f\x07\xcf\x0e\x5f\x1f\x7e\xfc\x17\xca\x72\xf4\xe3\xe1\xc7\xb7\x2f\x3f\x7c\x40\x3f\x1e\xbd\x47\x07\xe8\xdd\xc1\xfb\x8f\x87\xcf\x8f\x5f\x1f\xbc\x47\xef\x8e\xdf\xbf\x3b\xfa\xf0\x72\x80\xd0\x07\x4c\x3b\x86\xa1\x86\x66\x44\x4f\x60\xce\x72\x8c\x62\x5c\x46\x24\x11\xf3\xff\xaf\x6c\x89\x8a\x59\xb6\x4c\x62\x34\x8b\xce\x30\xca\xf1\x18\x93\x33\x1c\xa3\x08\x8d\xb3\xc5\x65\xeb\x89\x84\xca\xa2\x24\x4b\xa7\x30\x6c\x49\x65\x08\x1d\x4e\x50\x9a\x95\x01\x2a\x30\x46\xdf\xcf\xca\x72\x11\x0e\x87\xe7\xe7\xe7\x83\x69\xba\x1c\x64\xf9\x74\x98\xb0\x0a\x8a\xe1\x0f\x83\xb5\x87\x43\xc1\x6c\xff\x06\x64\x3b\xce\x62\x9c\x0f\x7e\x01\x16\xf9\xb7\x68\x59\xce\xb2\x1c\xbd\x89\x72\xfc\x19\xfd\x77\x56\xe2\x73\x32\xfe\x15\x7d\x3f\xa7\xdf\x7f\xc3\xe5\x2c\xc6\x67\x83\x71\x36\xff\x01\x80\xe3\xa8\xc4\x68\x7b\x73\xeb\x1b\x60\x78\xcd\x5b\x41\x8d\x00\xab\x95\xe1\xf2\x98\x6f\xef\xe0\x92\x82\x06\x4c\x77\x41\x1f\xe4\x61\x5a\x9a\x80\x24\x2d\x7d\x70\xc7\x0e\xe0\xb2\x02\xf2\xc5\x65\x1a\xcd\xc9\x58\xb0\x71\xad\x44\xcc\x72\x80\x47\xf9\x4a\x7e\x28\x73\x92\x4e\xcd\x32\x05\xa4\xf9\xa0\xdf\xe3\xc8\x1a\x63\x8e\x23\xef\x18\x8f\x5d\xd0\x65\x15\xac\xa7\xdb\xb2\xbf\x00\x4c\x0a\x3e\x40\x83\x33\x17\x5a\x15\x01\xec\xb0\x9c\x4f\x0b\x0b\x71\x2d\x7f\x20\xab\x80\x6d\x84\x01\x5f\x5d\xc9\xd3\x23\xaa\x80\x3e\xc8\xf3\xe8\x92\x81\x33\x26\x6e\x89\x02\xcf\x29\x7d\x6a\x12\x00\x5f\x49\x8c\x43\xc4\xa8\xcc\x10\x4e\x29\x0d\x0f\x63\x4c\xff\x93\xad\x50\x66\x1c\x31\x36\x49\xb9\x12\x97\x6b\xcd\x8d\x99\xd5\xad\x8f\x98\x82\x15\xe6\xce\x0c\x49\x68\x1f\x6a\x28\x8c\x2e\x02\xef\x9f\xe3\x72\x96\xc5\x9e\x6e\x31\xe5\x7a\x96\xcf\x11\x93\x5c\x32\x63\x46\xd6\x10\x5b\x83\xbc\xf8\x27\x3e\x33\x3c\x0b\xfd\x0d\x7a\x8f\xbe\x30\xe2\xb9\x96\x62\xf9\xdf\x18\xe6\x0b\xf4\x45\xaf\xec\x1a\xb2\xe0\xad\x42\x81\xbe\xc0\xbb\x86\x6b\xc4\x3f\x09\xe5\x0d\x4c\x22\xa2\x64\x08\x7d\xa1\x3b\x11\x65\xf7\x80\x10\x03\x19\xda\x4e\xad\x77\xc9\xc1\x91\x40\x11\xc5\x66\x61\x8a\x77\x1a\xd6\x06\x13\x92\x94\x38\xef\x69\x65\xfb\x9a\x0e\x82\x53\x51\xc9\x85\x02\x41\x04\xa0\x53\xe8\x9f\x6c\x9e\xee\x31\xfe\x49\x26\xa8\xb7\xae\x37\xa2\xd7\xc1\x1e\x68\xb0\xa7\x1c\x5d\x92\x9e\x45\x09\x89\x15\x0d\xd0\x1a\xd7\x43\xd4\x45\x1b\x48\xaf\x7c\x4d\x97\x35\xf4\x9a\x4d\x0a\xac\xa0\x34\xb4\x48\x22\x92\x32\xfa\xb2\xa6\x91\x01\xbc\xe3\x39\xd5\xb3\xc8\xd3\x8f\x46\xbf\xe0\x71\x79\x6d\x55\x28\x26\x59\x95\x63\xd5\xc6\x16\x5c\xf5\xd4\x69\xdd\x70\x66\x2e\x60\xe5\x2d\x81\x0b\x26\x4d\x2b\x56\xf4\x4e\x28\xf0\x69\x80\x4e\x00\xfc\xb4\xdf\x0e\x35\x09\x29\x40\x02\x62\x8b\xaf\x1a\x3b\x85\x8e\x06\x60\x01\x0c\x3b\xbe\xf4\x85\x2a\x50\x85\x18\xa7\xd9\x56\xb8\x29\xdc\xa5\xcf\xb1\x53\x54\xd1\x77\x21\x08\x7c\x8a\x4b\x7d\x05\x16\x9c\x73\x70\x92\xa5\xc5\x78\xdf\x68\x09\xa3\x86\xc1\x3c\x5a\xf4\xaa\x78\x2c\x68\xe5\x3c\x6b\xc4\xe0\x9d\xac\xe6\x1e\xeb\xe9\x09\x14\x39\x65\xec\x59\x7c\xc9\x55\xa4\xf5\x87\xef\x53\x47\x93\x49\x81\x4b\xa7\x53\x39\x8e\x97\x63\xac\xf5\x2b\x1a\x8f\x03\xd4\xd0\x39\xc0\x4e\x19\x95\x64\xfc\x2e\xca\xcb\xd7\xf0\x92\xc8\xaa\x79\x60\xe7\xf7\x3c\xfd\x14\x75\xe5\x94\x29\xe1\xf8\x83\x5b\xe5\x9b\xa8\x9c\x0d\x26\x49\x96\xe5\xbd\x9e\xd3\xe2\x06\xda\xd9\xea\xa3\x21\xda\xd9\xee\xa3\x87\x68\x67\x9b\x0f\x5a\x43\x5f\x34\x1e\xa3\x0d\xd4\x93\x9b\x8e\x81\xf5\x0a\x14\xa2\xa7\xda\xde\x85\xd0\xce\x36\x0a\x8d\x84\x8a\xce\x0a\xd4\x07\x68\x53\xc7\x7e\x8e\x8b\x65\x52\x0a\xea\x61\x33\xf8\x66\x99\x94\xe4\x67\x52\xce\xd8\x9c\x08\x0a\x34\xfa\x16\x48\x3a\x0a\xcc\x19\x14\x95\xf3\x11\xb2\xfa\xcd\x13\x9f\x9f\xf4\xad\x56\x7d\x6b\xa0\x65\x0f\xb4\x35\x22\x87\xd7\xe9\xec\xa9\x85\x83\x93\x09\x1f\x31\xef\x2c\xdf\x15\xb2\xfc\x65\x34\x9e\xf5\x6c\xc6\x44\x74\xda\xa2\x5c\xbf\x72\xbe\xd4\x5c\x9d\xf6\xf5\x42\x0c\x21\xd0\x95\x0d\x57\xdb\xd9\x33\xbb\x2f\xd6\x91\x46\x84\x72\xed\x52\x2a\xc6\xc9\x84\x83\xd8\x73\x04\x1d\x70\xbb\x24\xf0\x04\x1f\xf6\x64\xe9\x4d\x98\x4b\x71\x63\x1f\x61\xfe\x0c\x0f\x0d\xd1\xb6\x02\xbd\x46\x38\x29\xb0\x35\xbc\xe1\x10\xc5\x59\xda\x2d\x51\x14\xc7\x88\x97\x2a\x33\xb3\xca\x01\x22\x65\xb7\x40\x51\x92\xe3\x28\xbe\x44\xe3\x6c\x99\x96\x38\xae\xc0\xd2\x57\x1a\xe7\xb5\x5a\x84\xc3\x21\xfa\x78\xf4\xe2\x28\x44\x13\x32\x5d\xe6\x18\xd1\x03\x5b\x8a\x0b\x7a\x02\xa4\xa7\xb4\xcb\xc2\x64\x56\xbf\x05\x91\xfc\x71\x26\xd9\x9c\x0c\xac\x23\x50\x60\xa5\x62\x99\x4b\xb4\xe6\x78\x12\x81\x3a\xe6\x7c\x96\x25\x98\xf5\x90\xa4\xd3\xf5\x06\x46\x50\xc3\x03\x6c\xce\xcf\x07\x1d\xa0\xcc\x59\xf9\xc6\x22\x17\x73\xd2\x28\xea\x7b\xb6\xb8\x9e\xab\x1a\xd3\x08\x88\x35\x8c\xce\x23\x45\xd6\x05\x2e\x9d\x39\x65\x64\xf5\x36\x9a\x63\x7b\x1f\x52\x39\xba\x9c\xe9\x96\xf5\x6c\x3e\xf5\xfb\x99\xaa\xd8\x53\xa7\xe4\x8b\x1c\x83\x4a\xaa\x15\x7f\x35\xc3\x16\x95\x2c\x72\x7c\x46\xb2\x65\x21\x3b\xb4\xbd\x47\x51\x42\x52\x44\xd2\xd2\x29\xd1\x84\x7f\xad\xbf\xbe\x06\xe9\xdf\x24\xcb\x11\x3c\x12\x26\x68\x1f\x6d\xed\x21\x82\xbe\x17\x03\x10\xef\x85\x11\xd9\xd8\xa8\x2a\x4e\xff\xac\x3e\x6f\xec\xa3\x8d\x9e\xc0\x01\x41\x8f\xd0\xd6\x29\x95\xf0\xd1\xd5\x15\xda\xdc\xab\xac\xa4\x86\x95\x73\x7a\xd8\x40\x04\x3d\xac\x9a\xb9\x0d\xbb\x17\x54\x38\xa8\x62\xfb\xe2\xef\xda\x49\x35\x53\xae\xfb\xbd\xbe\x35\x85\xc3\x21\x9a\x90\xbc\x28\x11\x4e\xf0\x1c\xa7\x25\x3d\x5f\x31\x34\x05\xa8\xf8\x4c\x16\x88\x94\xab\x4c\xb9\x81\xfd\x4d\x1f\xf6\x29\xfe\x6a\x67\x00\x9e\xce\xc7\x31\xa1\x8d\x44\x89\x5c\xe4\x1c\x9f\x0e\xff\x71\xf1\xed\xe7\x8b\x8a\x74\x2a\x18\xc4\x09\x41\x1b\x68\xeb\x54\xf0\x09\xb4\x81\x9c\x6e\x78\xd0\xde\x88\x60\x8b\xf9\x79\x20\xf9\x56\xe9\xa1\x7d\x46\x15\x37\x66\x3d\x7f\x68\xa6\x42\x85\x2d\x13\x53\xb7\x5c\xfc\x0d\x94\x89\xaa\x18\xd2\x66\x1d\x43\x42\xad\x68\xba\x91\xa3\x0c\x87\x68\x1c\x25\xe3\x65\x12\x95\x58\x08\x3e\xf4\xc8\xc7\xfb\x82\x48\x89\xe7\xb7\x60\x47\x94\x15\x9d\xfc\x89\x98\x52\xdf\x86\xbd\x5e\x69\x5f\xb9\xe5\x84\xfc\x7e\x0c\x46\x67\x2e\x5f\x9d\xb7\x20\x47\x5b\xc4\xfb\xd1\xa0\x0d\xe1\xba\x48\x7e\x33\x99\xd5\x68\x8c\x18\x64\x6b\x8d\x91\x48\x97\xb7\x9a\x52\x25\xe2\xd7\x25\x55\xeb\x41\xb4\x86\x3d\xe2\x1f\xd4\xef\xd3\x11\x69\xc5\x94\x8e\x88\x41\x83\x6c\xd3\x06\x2d\xb5\x4a\xa2\x0a\x84\x54\xe9\x88\xaa\x11\xc2\x4b\xc0\x09\x03\x5a\x53\x88\xa9\xd7\x10\xe9\x43\xf4\x9d\x8e\x0d\xdc\xac\xae\x20\x12\xa5\x18\x15\xeb\xf0\x8c\x88\x0b\xef\x29\xdc\x3a\xee\xdf\xb1\x46\x89\x0d\xb9\x07\x23\x13\xeb\x4b\xa9\x45\x0c\xbd\x88\xa8\x51\x69\x98\xea\x54\x0e\x6a\x54\x8d\x7a\x06\x1d\xa3\x8c\x03\xd1\x32\x77\x3d\xd2\x36\xea\x28\x79\x12\xf5\xc9\xc1\xbc\x6b\x95\x4c\x72\x38\x44\xc5\x72\xce\x6e\xe8\x3c\xbb\x14\x17\x11\x25\x3c\xaf\xee\x84\x9c\x52\xae\x28\xbf\x60\x4b\xf2\xf1\x1f\xd1\xbc\x89\x08\x21\x6d\x3a\x28\x18\x0e\x51\x8e\xe7\xd9\x19\x5c\x63\xa2\xf1\x32\xcf\xa9\x7c\x2a\x85\xd3\x0c\x92\x79\x37\x49\x01\x3d\xf7\xf4\xb6\x58\x45\xe3\x27\x90\xd9\x5a\xf3\x67\x8c\x0c\x3d\x72\xea\x6f\x4d\x69\x1f\xac\x75\x58\x71\xad\xe3\x3d\xb5\x0a\x1e\xe7\xa1\xb2\xd2\xba\x72\x10\x64\x45\x77\x30\xfd\x92\xc4\xbc\xbf\x60\xbd\xa5\x6d\x8d\xf9\x2d\x93\x6e\x6a\x01\xbd\xef\x31\x7b\x55\xdb\x04\x83\x5f\x8b\xf6\xfa\x81\x37\xfb\x59\x96\x25\x55\x79\x54\x08\xa9\xc8\x3a\xae\xc9\xd3\x2f\x37\x2b\x9b\xad\xcb\x64\x5c\xb8\x2a\xf7\x3d\x8e\x2a\x7b\x7c\xcc\x32\xd7\x28\x41\xb8\xf6\x1b\x80\x3a\x69\xb3\x21\x0c\x67\xc3\xdd\xa0\xc3\xee\x7e\x3b\xe1\x37\xf0\x93\xf6\xad\x13\x3e\xa6\xbf\xf5\xeb\xd8\x4e\xf8\x24\xf0\xd9\x7a\x90\xb4\xec\x84\x5b\x9b\xf4\x67\x8e\xa3\xa4\x13\x6e\x6d\xd3\xdf\xec\x56\xb6\x13\x6e\xed\xd0\xaf\x25\x83\x82\x06\x96\x1c\xec\xf1\xf5\x69\xf0\xe4\xb7\xb4\x8b\x6a\xb8\x86\xbe\x99\x35\x91\x5e\xc9\x2a\x46\x45\x66\x39\xdb\xb6\x48\xcf\x5d\xd1\xc4\xc8\x5f\xb4\xc6\xd2\xc8\xec\x49\x9b\xba\x6e\x61\x77\x54\x61\x6c\xd4\xaa\x51\xed\x4a\xdc\x3b\x5d\x82\xed\xe4\x4b\xdc\xc2\x84\xc9\x1a\x76\xb3\x25\xd3\x77\xf7\x96\x4c\xf7\x96\x4c\xff\x29\x96\x4c\x6a\x21\xdc\x95\x39\xd3\x33\x32\x7d\xbb\x9c\x8f\x80\x15\x4a\xee\x3c\x22\xd3\x14\x12\x07\xbf\x48\x4e\xbe\x2c\x49\x62\xda\xd7\x0c\x86\x90\xc6\xfe\x15\x60\x63\x2f\xc8\x38\x4b\x27\xc4\x31\x06\x12\x27\x33\x6d\x57\x80\xb3\x0b\x6c\x0b\x62\xe0\x8c\x57\x17\x08\xf8\x3d\x82\x07\x1b\xf4\x9c\x45\xf9\x96\xb2\x92\x85\xa5\x40\xe7\x06\x94\x33\x0f\x29\x8e\x19\x24\x29\x50\x8a\xa7\x51\x49\xce\x70\x20\x38\x11\x5c\x1c\x95\xe7\x59\xb7\x40\xe3\x6c\xbe\x10\xd2\x2a\x94\xa2\x73\x2b\x4b\x4e\x92\x2c\x2a\x49\x3a\x45\x8b\x8c\xa4\x65\xc0\xae\x43\x29\xd9\xc7\xd9\x79\x6a\x9d\xe9\x4c\x35\x89\x7b\x7c\xbb\x62\x58\xbe\x92\xf8\xbe\x16\x63\xa1\x4b\x29\xc5\x38\x86\x53\xf4\x48\xcd\x71\xec\x37\x86\x01\xa4\x5d\x4b\x3b\x1f\xb3\x5d\x83\x01\x43\xfd\x82\x0b\xcb\x76\x07\x6c\x2e\x7a\xe3\xc1\xcb\x8f\xaf\x3e\x3d\x3b\xfc\xe9\xed\xf1\x9b\x67\x2f\xdf\x7f\x7a\x7f\x74\xfc\xf6\xc5\xe1\xdb\x9f\x3e\xbd\x39\x7a\xf1\x52\x3b\xc3\x49\x4d\x1c\xcc\xe4\x60\x11\xc5\xaf\xf1\xa4\xec\xb1\xaf\x32\xfb\x78\x9e\x15\xcf\x25\x16\x79\x9b\x83\x32\xe3\xe2\xd2\xd6\xe3\x7e\x80\x1e\xef\x9a\x37\x3c\xfa\x6e\x09\xc3\xe9\xb1\x46\x4c\x03\x0c\x73\xe2\xc5\xe1\xb7\x02\xe7\xcf\xe4\xd9\xd8\x3c\x34\xaf\x8a\x43\x57\xea\x30\xb0\xe8\x41\x48\x99\xbd\xc2\x17\x62\xdc\xc5\x72\x54\x94\x79\x6f\x5b\xc3\x5f\x62\x5d\xed\xb3\xe2\x42\xcb\xbd\x81\x1e\xef\xf4\xd1\x50\x47\x91\x8d\xee\xf7\x64\x3a\x2b\x79\xb1\x00\x25\xe8\xe1\x57\xc6\x27\xdf\x81\xef\x14\xad\x95\x32\xdd\xad\xb1\x2b\x8e\x67\x26\x5a\xa5\x76\xee\x77\x9b\x01\x4b\x6d\xca\x1a\xeb\x0f\xd8\x9a\xdf\x40\xcd\x13\xd4\xc4\xe9\x98\x24\x5f\xbd\x22\x3e\x88\xfc\xdb\xce\x9d\x34\xee\x6c\x3f\x6b\x93\x3c\x9b\x1f\x97\x93\x27\xf7\x13\xe7\x99\x38\xfe\xce\xa8\x8a\x91\xf1\x57\x48\x62\xd2\xe8\x37\x8e\xd2\xd5\x19\x99\xfd\xe4\xa8\x7a\xce\xba\x9b\xb7\xfb\xeb\xa2\x0d\x5e\x3d\x7a\x8a\x50\x77\xab\x8b\x42\xd4\xdd\xec\xde\x9e\x47\x35\x61\x92\x9e\x58\x69\xa9\x7f\x50\xb8\x02\x51\xc1\x78\xbe\x4c\x4a\xc2\x84\xca\xd1\x25\xda\xfe\xdf\x39\x15\xcf\xa5\x0d\x5d\x44\x6b\x2e\xf1\x14\xe7\x35\x5b\xc9\x7b\x5e\x6b\xd3\xfe\xbd\xea\x8c\x70\x5b\xe6\x8a\x19\xe1\x68\xb2\xa8\x8f\x62\x4d\xb6\x28\x37\x57\x32\xc7\x85\x95\xb5\xdd\x1f\x2c\xb2\xf3\xde\xd6\xf6\x93\x7e\xdf\x44\xe9\xf3\x19\x1e\x7f\x46\x64\x62\xe0\x54\x13\x8b\x2c\x44\x14\x64\x9a\xe2\xf8\xb0\x78\xab\xb2\x1d\x45\xb4\xac\x63\x86\x2f\x78\x8f\x4d\x64\x08\xa2\x85\x43\x1f\xb4\x5d\x9a\x92\x58\x46\x8f\x2c\xe7\x84\x8a\xe1\x51\x52\x28\xab\x65\xbb\xf5\x46\x7c\xf9\x30\x24\xd8\xcd\x66\x80\xb6\xfa\x01\xda\x7a\xac\xc9\x23\xdb\x7d\x23\xb7\x8f\xf6\xf7\xf7\x29\xc9\x7a\xa9\x30\xa7\xec\xe3\x51\x94\x40\xa7\x10\x53\x1d\xa8\x0b\x0f\x26\x6a\xba\x44\xc4\x14\x09\xb6\x10\x68\x90\x87\x63\x07\x4b\x71\xa6\x04\xc3\x9a\x76\xa5\x70\x08\xcb\x82\x4c\x11\x93\xd3\x2d\x7a\x93\x5d\x30\xf0\x67\x18\xc5\x52\x60\x36\x8f\xfb\xac\x37\x9a\x2e\xb3\xd7\x47\x57\x57\xa8\xb3\xd9\xe1\x3a\xe2\xe1\x10\x8d\x25\x15\x51\xe1\x59\x4c\xa4\x6c\x9d\x01\x91\x92\x4d\xb4\x94\xb4\x5d\x21\x5b\xdc\xdf\x5a\xf3\xcc\xe7\xd6\xa3\x82\xf4\xcc\x2f\x9b\xd2\x39\x49\x97\xf6\x2a\xe8\x4e\x6e\xf9\xd7\x85\xba\x45\xe5\x5b\xf2\x7a\xac\x45\x87\x6e\x40\x41\xcb\x7a\x12\x3a\xae\xa5\x21\x1f\xf5\xe0\x95\xc8\x87\x37\xef\x12\xce\xf1\x5d\x50\xce\xd7\x41\x19\x67\xf9\x55\x28\x73\x78\x77\x23\xca\x00\x63\x9a\x48\x6c\xa2\x88\x37\xe7\xa2\xc8\x61\xe6\x3e\x8b\x73\x6b\x31\x72\x98\x41\x4c\xce\x48\x8c\xe3\x67\x97\x35\x3c\xfc\x26\xd4\xd4\x80\x9b\xe3\xbb\x46\xce\xb2\x12\x3b\xc7\x2b\xa3\xe7\xf8\x36\xf8\x71\x6f\x61\x59\xd5\x12\x45\x55\x12\x97\x7a\x30\xdd\x1a\x2f\x62\x67\x33\xe7\xa2\x12\x47\xbc\x69\x17\x45\x8e\x7c\xe6\xc3\x90\x67\x79\xc1\x7e\x75\x4b\x81\x6d\xab\x8b\x9e\xb2\xad\x99\x7b\xc6\x58\x0d\x9b\x95\x27\x47\xed\x5d\x6e\xcd\xde\x97\xe0\x89\x42\x1c\x95\x20\x6a\xce\x36\x8e\xe8\x91\x46\x73\xcc\x1e\xf8\xd0\x5f\x96\x08\xc6\x61\x68\x9d\xb2\x06\x0f\xe6\x9d\x43\x28\xb4\x11\x20\x5d\x59\x4e\x0b\xf1\x27\xd6\x68\x1f\x55\xbd\xd4\x7d\xd8\x1f\x6a\x47\x9a\x82\xfc\xca\x79\x62\x01\xb7\x54\xbc\xfc\xc9\xd6\xa9\x29\x0a\x77\x37\x2f\xa8\xc8\xec\x4e\xee\xa0\x48\xc8\x18\x53\xc9\x64\x1b\x3d\x84\xea\x56\xa4\xf3\x86\x99\xd1\x4f\xe1\x77\x36\x41\xab\xa2\xbf\x52\x15\xe0\x6c\x32\xf2\x88\x68\xf1\x01\x86\x38\x7e\x09\x66\x63\xee\xf1\x6e\x9f\xef\xe1\x65\xc6\xe1\xfb\xe8\xa1\x38\x55\xfa\x66\xc0\xaa\x88\x49\x87\x8f\x77\x03\xde\xfe\x6a\x53\x50\x73\x2a\x67\xc3\xf7\x1c\xcb\xef\x14\xfb\x51\x31\x26\xa4\x0e\xff\x9e\xe3\xfc\x6f\x88\x79\xa1\xd5\x01\xed\x40\x3b\xfc\xaf\x36\x01\xca\x3d\x4d\xd5\x0c\x1c\x28\x07\x36\x15\x53\x50\xc9\xdb\x2b\x50\x2e\x2b\x74\xb1\xed\x73\x60\xb3\x82\x34\x65\xe0\xae\xb3\x79\xd1\x41\x1b\x88\x9f\x71\x00\xed\xec\xb7\x34\x2b\xd8\xdd\x0c\x90\x9e\x54\xe5\x33\xe0\x8b\x30\xfd\xd0\xce\x9a\xa1\xf5\x1d\xd8\x30\xb0\x62\x43\x27\xc5\x81\xd3\x17\x78\x58\x95\xe1\x94\x62\xc8\x0c\xdd\x24\xb7\x1f\x59\x96\x84\x76\x82\x03\x45\x25\x90\xd0\x4e\xd0\xa1\xa4\x58\x16\xda\x09\x2e\xd4\xb1\x03\x76\xec\x85\xd3\x1b\x55\x29\x9e\xfa\x5c\xc0\x63\x3f\xa4\x3e\x58\x95\xe2\x81\xd3\xb1\xad\x25\xb9\x90\xbe\xe9\x71\x73\xdc\x72\xe6\x04\xe9\x69\x2e\x2c\xa7\xfa\xd0\xbb\xee\xae\xc5\xb5\xae\x79\x39\xd4\x09\xb7\x9e\x04\x1d\xf3\x52\xa9\x13\x6e\x83\x05\x03\x2c\x8c\x4e\xb8\xb5\x15\x74\xf4\xab\xa9\x4e\x68\x7e\x5e\x9f\x06\x5b\x9b\xbf\xb3\x4b\x97\x43\x66\x1b\x5f\xe3\x83\x88\xa4\x65\x95\x0b\x22\x7e\x7b\x45\xd2\x92\x79\x67\xa1\x3f\x76\xe5\xaf\x53\x95\xb8\xa3\xfd\xb6\x9c\xb7\x90\xb4\x64\xae\x5b\x48\x5a\x3e\xde\x95\x60\x4f\x54\x45\xdb\xdf\x3c\xae\xa8\x8b\xc2\x37\xb8\x32\xb2\x8f\x86\x5f\xd1\x1b\x17\x80\xdb\x66\x08\x87\x69\xb9\xa2\xe5\x85\x51\xa2\xc6\xe0\x02\x9a\xab\x29\x79\x23\xf3\x0a\x92\x96\x42\x54\x7c\x7a\x23\x97\x2e\xac\x57\xcd\x66\x10\x5b\xad\xa2\xd8\xdd\xdb\x41\xdc\xdb\x41\xfc\x79\xed\x20\x90\x32\x84\x60\xa2\xd2\x1d\xd9\x40\xb4\x30\x6d\xb0\x59\x3d\x33\x5d\xc8\xc0\x20\x5d\x79\xee\x18\x78\x24\xd4\xf3\x19\x4e\xe5\x7b\xc5\x80\xd9\x7e\x53\x01\x5c\x3a\x70\x10\x92\xe5\xd0\x6b\x1b\x61\xa9\xbf\xed\xe7\x89\xc0\x49\x85\xfc\xc8\xfe\xbf\xba\x42\xdd\xae\xc6\x67\x33\xf1\x72\x81\xfd\xd8\xd3\x9e\x1a\x92\x94\xb7\xde\xda\xe3\xc7\x14\x97\xba\xc9\x2f\x18\x90\x77\x0b\xf1\x10\x14\x78\x09\xad\xc4\xb0\x76\x57\xf2\x3d\x33\x76\x35\xa5\x68\xa1\x66\x52\xb5\xea\x95\xa1\x9e\xe8\x63\xdf\x30\x68\x07\xf4\xe8\x06\xed\x76\x23\xb5\xa6\x68\x60\xe5\x6f\x1c\x3b\xf4\xeb\xc7\xd6\xc8\x18\xe7\x98\x12\x93\x58\x0f\xa6\x5b\x16\x46\xee\x31\x99\x4c\x30\x18\x24\x33\x94\x5b\xe7\x92\x73\xf9\x2e\x44\x3f\x8e\x08\x94\xf0\x59\x12\xb6\xcb\xa9\xf7\x10\x62\x1e\x5d\xe8\x76\xe8\xeb\x47\xb4\x60\x1c\x46\xf6\xa2\x1a\x95\xe7\xfe\x37\xb3\x26\xdd\x55\xde\xea\x29\x82\x94\xa4\xba\x0a\x46\xb3\xf9\x88\xa4\xae\x87\x9b\x32\x9b\x62\xca\xdd\x69\x0d\x78\x3a\x60\x8b\x2a\x5a\x2c\x70\x0a\x6b\x29\x4a\xd9\x1b\x08\x0b\xbb\xbc\xb6\xa6\x7b\x18\xce\x98\x66\x64\x4c\xd9\x93\xe8\x55\x73\x61\x7e\x81\x9a\x4d\x38\x2c\xec\x43\xb5\xa8\x15\xc3\x6b\xd2\xfb\xd5\xa1\x55\xea\x2d\xd8\x95\xc9\x1e\x6a\xc6\xee\x38\x4a\x12\x8e\x5f\x71\x8d\xc3\x46\x34\x8b\xd4\xd2\x2d\xc8\xaf\xdc\xb9\x20\x5c\xd7\xcd\xa2\x22\xa0\xff\x0b\x42\x03\xf7\xbf\x9e\x7b\x3b\x1d\xdf\xd2\x16\xd4\xaf\x33\xad\x45\x8d\xdf\x3b\x93\x6f\xe1\xf2\x55\xb1\xbe\xbf\x0f\xd2\xc5\x84\xa4\xd6\x5b\xa5\x26\x24\x28\xaf\x45\xbc\x2a\x7e\xc3\x6c\x2b\x0d\x58\xee\x41\xf1\xac\xfa\xe8\xcf\x34\xbe\xae\x86\xa6\xc5\x32\x33\x6a\xaf\x1b\xf4\x3a\x8c\x5a\xb9\x00\xe8\xa3\xa7\xa8\xdb\x45\x61\x3b\x83\x2c\x0d\x65\x5e\xb3\xac\x15\xf0\x46\x79\x3f\x53\x4e\x48\x99\xd1\xf7\xdc\x4b\xe9\x2f\xfc\x38\x13\x7b\x8f\xb8\x15\x8e\x74\x86\x1f\xcd\x75\x22\x03\x12\xaf\xc5\xa2\x6a\xcc\x8b\x42\xf0\xab\x64\xe3\xcf\xe7\x9f\x49\x2e\xaf\x3d\xc4\xae\xfc\x50\x05\xdd\xf1\x09\xeb\xad\x8e\x3a\x63\x5b\xab\xc0\x9d\xb6\x29\xf9\x91\x27\x12\x22\x71\x09\xdf\x02\x8b\x78\xbe\x28\x2f\x75\x95\x60\x8b\x4d\xb4\x71\x15\x9a\xf4\xa8\xb1\xa7\x10\xa4\x8f\x15\x70\x23\x3c\x4e\x55\xfa\x9a\xf2\x62\xa2\x76\x20\xbc\xca\xa6\x31\x18\x17\x2b\x1b\x1e\xb1\xe0\x26\xe3\x50\x8f\xf1\xaa\xfd\x43\xbd\x26\x45\xe9\xbc\xfc\x3b\x31\x46\x73\xea\x71\x0a\x55\x3b\x7a\x55\xb3\xbb\xbd\xc8\x77\x41\xe2\xa6\x7e\xb9\x88\x99\x65\x2b\x7f\x07\x27\x55\x91\x65\x56\x6a\x6f\x5d\x59\x61\x21\x1c\x31\xbf\x43\xc8\x78\xdb\x27\x9f\x10\x72\x50\xf3\x59\x91\xb1\xb7\xc9\xf5\xc8\xb6\xaf\x8a\x05\x69\xdf\x7e\xd9\xce\x42\xcc\xe6\xd1\xbe\xde\x63\x05\xab\x0f\x63\x63\xdf\x55\xf4\xf3\xd7\x5a\xee\x0b\x2d\x06\xa9\x44\xa0\x5e\xa6\xbf\xba\x95\xaf\xe6\x86\x43\x31\xdd\xf8\x0c\xe7\x97\xe5\x0c\x7c\x91\x68\xf5\xe8\xd8\x71\x1d\x4f\x09\x8b\x34\x07\x3f\xc6\x4b\x5d\xff\x0d\x85\xf4\xbd\x74\xa7\x4d\xb8\x4a\xe7\xeb\x00\x75\xbb\x42\xf9\x5e\xa3\xa4\x78\xc7\x66\xc9\xd2\xe9\x49\xf5\xdd\xf5\x69\xb0\xd5\x2a\xd6\xde\x57\xd4\xc9\xc1\x6d\x74\xbd\x52\x2e\xa7\x20\x15\x5a\x39\x61\x66\x46\xff\x67\xaa\x32\xf8\xb5\xab\x7e\x9e\x6a\xc9\x3b\xfa\x87\xa5\x9b\xa3\x69\x4c\x39\x47\x7f\x09\xed\x1c\xfd\xfd\x44\xab\x4e\xd3\xcf\x39\x35\xb6\xd0\xd0\x39\x77\xef\xab\xa8\xe8\x68\xe1\x55\x74\x74\x0c\xde\x56\xd2\xd1\xd4\x15\xb5\x74\x66\x91\x1a\x35\x1d\x6b\xb1\xae\xec\x4d\x14\x75\x14\xb7\x15\x8a\xba\x76\x8e\xf2\x79\xb7\x5a\x28\xea\x5a\x45\xf3\xfa\x5a\x8f\xeb\x3c\xb7\x7f\xab\x90\x07\x2b\xbe\x0a\x81\x88\x12\x36\x89\xb0\xf4\x15\x89\xc4\x2e\x54\x43\x26\xa2\xdd\xfa\xf2\x37\xd2\xe9\x32\x49\xaa\xcd\x9b\x39\x4f\x7b\x77\xfb\x5a\x4e\x8e\xb2\x05\xdd\xdd\x7d\xf4\x91\xda\xf7\x3b\x1e\x3e\xac\xb9\xb8\x25\x45\x7b\xdf\xb6\x63\x9c\x97\x11\x49\xfd\xfe\x6d\x1d\x44\xb2\xdb\xa4\x06\xa2\x66\x40\x03\x33\xbd\x9e\xac\x79\x11\x2b\xa3\xd1\x1b\x44\x89\xf3\x39\x3d\xf2\x93\x09\xd4\x6c\xf6\x3b\xe6\x5e\x6b\xd1\x94\x9c\xe1\x54\x98\xb4\x98\x47\xea\x2a\x77\xb9\x96\xfd\x0b\x3b\x66\x2b\x8b\x5b\xc0\x32\xab\xdc\x69\xd7\x6f\x7f\xab\x43\xb4\x5f\x22\xcc\x39\x6d\xa7\xf4\x0a\xc7\xd9\x19\xce\xf3\xf3\x9c\x94\x25\x06\x73\x2f\xd6\xab\x0e\xda\x80\xde\xb7\xc6\xdd\x39\x68\xd9\x0b\xfd\x21\x3f\x58\x41\xa8\xa3\x28\x49\x39\x0a\x4b\xd7\xef\xb0\xfd\xd6\xbe\x15\x32\x5d\xad\xa4\xd5\x9c\xd2\xda\x56\xe0\xcd\xe3\x42\xc0\x8f\xc1\xe1\x10\x54\xe1\xd1\x9c\xae\x0a\xf0\x7a\xc8\xb5\x59\x74\xbc\x94\x13\x60\x76\xc7\x90\x90\xcf\x18\x45\xa8\x20\xe9\x34\xc1\xd2\x0f\x17\x40\x0e\x0c\x93\x68\xa0\x60\xe6\x66\x86\xb9\xe5\x60\xad\x5d\x5d\xa1\x93\xee\xc9\xd6\x69\xf7\xb4\x2f\x85\xc1\x06\x37\x00\xbc\x7b\x26\xde\xe9\x97\xee\xda\xb0\x42\x74\x67\x36\x50\x0c\x15\x60\xab\xb0\x15\xa0\x47\x60\x8f\xbd\x09\x7d\xd9\xd2\x1d\xd1\xa8\x0e\x39\x82\xac\x70\xd4\x10\x08\xd7\x0e\x55\xa7\x05\xe1\xd0\xe1\xa1\x00\x54\x0d\x0c\x87\x28\x4a\x12\x34\x8a\x0a\x32\x66\xfe\x0f\xe0\xb1\xc0\xce\x36\x57\xe0\x24\x19\x3d\x19\x8b\xde\x04\x68\x67\xbb\xc9\xe8\xc4\x5c\xd8\x9c\xa3\x89\x13\xb8\xd0\x45\x22\x3c\x05\x01\x12\x82\x42\x9d\x9c\x76\xd0\xfe\x0f\xb0\x3e\x55\xda\x2e\x4b\xac\x55\xa6\x1d\x88\xda\x56\xe5\x00\x33\x5c\xd9\xb3\x9a\xd5\xae\xb7\x5a\x49\xb3\xca\xed\x97\xe1\x10\xc6\x21\xba\x3d\x6b\x1b\xd5\x8a\x3c\x78\x80\xf4\xef\x13\xed\xb7\xe6\x02\xee\x54\xec\xba\x32\x32\xc6\x70\x7a\xa3\xb9\xe1\xcb\xb7\x6e\x6a\xc4\x2c\x98\x73\xc3\x27\xcc\x9c\x1a\xcd\xe3\xda\x2d\x67\xc6\xea\x57\xcd\xc4\x68\x6d\x7e\xed\x79\xb9\xcb\x89\x31\x5d\x9f\x28\x46\xaa\xcd\x04\x9c\x8d\x3a\x60\x8b\xb0\xcd\x90\xce\x0e\x49\x1d\x6e\xac\xb0\xc5\xa7\x62\x6b\x57\x02\x6e\x9f\x9e\xec\x70\x50\x91\xc6\x40\x24\xc4\xd6\xa9\x95\xa0\xbe\xdd\xdd\x01\xb0\x7a\x83\xed\x41\x1f\x0b\x1f\x62\xf3\x9e\xa0\x35\x76\x47\x13\x49\x26\xa8\xa7\x65\x69\x1c\xd2\xe6\xc7\x37\x9c\x58\x60\xd8\xbe\xd7\x10\x5b\x35\x53\xce\x37\x09\x71\xaa\xf6\xcd\x33\xcc\x9b\x6f\xaa\x3b\x32\xfe\x9e\x33\xe1\xfc\xb3\x63\xcc\xbb\x51\xd1\x89\x59\xb9\x3e\xdd\xca\xfb\x5a\xab\x79\x96\x19\x6c\x28\x3c\xbf\x72\x7e\x0d\x2f\x8a\x95\xbb\x3d\xf7\x56\x94\x44\x45\x89\x4e\x4e\xa9\x30\xc1\xea\xbd\xd1\xb4\xaf\xfb\xe7\x5d\xce\x01\xc8\x59\xc8\xf1\xb1\x04\x07\x1a\xf5\x12\x0a\x3e\x25\x0d\xb4\x21\x92\x1a\xe3\x58\xed\x08\x23\x39\xb0\x7d\xd3\x84\x46\x97\x28\xc6\x93\x68\x99\x80\x22\xb4\x58\x52\x39\x55\x6e\xcc\x1d\xee\xa6\x26\xe0\x61\x1e\xed\x59\x34\x8e\x51\x37\x60\xc0\x6a\x47\x5c\x51\x14\x6e\x79\x7a\xab\x34\xaa\x17\xbe\xda\x85\x8e\x58\x5b\x22\x85\xbd\x46\x80\xe2\x39\x29\x9f\x74\x28\xc5\x07\xa8\x43\x17\x01\xfd\xef\xb4\x73\xaa\xa8\x9d\x43\x68\x69\x50\x28\x5d\x26\xf6\xb3\x07\x6d\x36\x5b\xa1\xcd\x76\x30\x67\xf5\xb7\x61\x21\xb8\x4e\xaa\x9c\x95\xc0\xf6\x06\xee\x2c\x8f\xcd\x7a\x01\x37\xbc\x74\x38\xc6\x78\xe9\xbf\xb0\xea\x2d\x22\xe6\xdc\xaa\xf7\xef\x13\x76\x1a\xff\xf7\x69\xbf\x59\x44\xe0\xca\x5b\xe9\xed\xa1\xfa\xde\xc1\x0a\x63\x21\xa0\xdb\xb3\x0e\xf1\xf6\xd4\xbd\xcb\xb2\x70\xe6\xb9\xb4\xe0\xf7\xe8\xf6\xc6\xe0\xf5\x47\x6d\xde\xca\x70\x57\xa8\xc2\x09\xaa\xcd\x16\x1a\xbc\xc1\x4a\xfb\x6f\xdd\x98\x78\x0f\x55\xfe\xf9\x1d\xa3\xba\x7e\x65\x71\x32\xd1\xfd\xc9\x72\x56\xe6\x14\x92\x2f\x93\x4f\x4e\x7d\x4e\xc4\x07\x8b\x65\x31\xeb\x39\x9e\x49\xc5\x4b\x6d\xe1\x66\xd4\xad\x99\x8e\xc5\xf5\xb9\x7e\xe6\x73\x00\xaa\xb7\xa4\xf9\xf1\xec\x9d\x05\x48\xf7\x2f\x6b\xb9\x27\xbd\x95\x53\x5f\x3e\x81\xba\x33\xdf\x5b\xcf\x1f\x74\xdd\x91\x3a\x38\xe2\x7f\xfb\xf9\xf3\x79\x64\x6d\xf0\xc4\x5a\x39\x11\x74\x36\xc1\x55\x6a\xcd\x7c\xac\x3c\x1b\x6b\xce\x1d\xa1\xa5\x3b\x32\x96\xa4\xe6\xd1\xb6\x8d\x4f\x50\x76\x3f\x3a\xc9\xb3\xb9\xd7\xdc\x80\x41\xf9\x78\xcb\xc8\x7e\xb0\x63\x19\x08\x19\x96\x41\x2b\x3c\x98\x12\x4c\x8d\xb5\xdc\x82\x45\xf1\x81\xe8\x2c\xca\xf0\xa7\xd9\xc0\xaa\xbe\x0a\xaf\x82\xbd\x49\xbf\xb1\x64\x82\x2e\x7f\xe2\x03\xdd\x13\x82\x0e\x47\xd7\x43\xb4\x0d\xc6\x0f\x7d\xe1\xd1\x99\x23\xaf\x6a\x11\xd5\xd6\xa9\x37\xef\x54\xec\x5b\x51\x50\xe0\x43\xc9\xee\xd8\xf5\xd2\x1b\x68\x87\x39\xbd\x67\xbb\x6d\x41\x41\x0a\x14\x4d\x4a\x9c\xcb\x45\xa2\xf7\xf7\x46\x6b\xd5\x5f\xc6\xe7\xbb\x5b\x71\x8e\x0a\x9f\xdd\xa8\x16\x7b\x3c\x74\xcc\xdb\xaa\xfa\x75\xbf\x1e\x95\x6e\xa4\xed\x98\x37\xb5\x8c\xa6\x25\xa7\x41\x0f\xeb\xfb\x46\x61\x37\xf6\xeb\x61\x5a\x31\x2a\xd3\xe1\xac\x36\xed\x1b\x88\xdc\x2d\xd7\xfa\x43\xec\x21\xfa\x5f\x4b\xea\x17\x06\xa9\x2d\xff\xfe\x50\xc4\x7f\x4f\xfb\xda\xdf\xef\x42\xfb\xc8\x4b\xfa\x7a\x80\xc6\x9b\x92\xbe\x1d\x46\x6c\xc5\x4d\xc5\x21\x56\xbb\xfe\x76\x3b\x8b\xd9\x8b\x55\xea\xe7\xf3\xe7\xa5\xb7\xc4\xa1\x2f\xff\xfa\xab\x5e\xc2\x0b\x7e\xeb\xe7\x1a\xa9\x36\x75\xbf\x87\xb6\xd0\x86\xd9\xbb\x3e\xf3\xc9\xc4\x22\x89\x79\xa6\x9e\x79\x20\xb6\x2e\xdd\x8c\x07\xdb\x35\xfe\xec\x0d\x5c\x5b\x16\x5f\x06\x17\x5b\x5b\x71\x6c\xfa\x9c\xcb\x95\xb5\xdd\x37\xd5\xaa\xde\x8b\x44\xab\xeb\x8d\x17\xbc\xd5\x57\xbb\xf2\x4d\xdc\xf5\x69\xb0\xf5\x7b\x87\xde\x3f\x6e\x7e\xf6\xb6\xac\x79\xf7\xc6\x3d\x91\xc0\xff\xcc\xd6\x65\xa9\x9e\xbe\x2d\xb5\xb7\x6f\x4b\xfd\xc1\xda\xd2\xf3\xfa\x6d\x29\x9f\xbf\x2d\xb5\xf7\x6f\x4b\xed\x01\xdc\xd2\x7c\x01\xe7\xd4\xd8\xc2\xc2\xc6\xf1\x8f\xf2\x15\x1f\xc1\x1d\x7b\x5f\xc1\x1d\xaf\xfe\x0c\xee\xb8\xed\x3b\xb8\x63\xf7\x21\xdc\xf1\x1d\xbc\x84\x5b\xde\xfa\x29\xdc\x71\xeb\xb7\x70\xbf\x77\x5c\xff\xe3\x16\x16\x67\xcb\x3a\x93\x33\xe1\x5a\x85\xfd\xe0\xc4\xa9\x59\x9d\x2d\x75\xb3\xb3\xa5\x61\x25\xb6\xf4\x19\x9e\x2d\x95\xe5\xd9\x52\x37\x3d\x5b\xea\xb6\x67\x4b\xcb\xf8\xcc\x53\x6f\x9b\xc5\xf1\x9b\xda\x9f\x1d\xfb\x0d\xd0\x8e\x6f\x60\x81\x76\xdc\xda\x04\xed\xd8\x63\x83\x66\x97\xbe\xd9\x1a\xa9\x31\x43\x6b\xbb\x48\xda\x1b\xa2\x7d\xdb\x66\x95\x74\x97\x05\x06\xc5\xec\xb8\xec\xb2\x80\x7c\xd3\x0c\xe1\xf4\x0c\xc5\x19\x06\x6b\x05\x78\x1d\x18\xa5\x31\xf8\xb0\x45\xff\x7c\xf3\xfa\x55\x59\x2e\xde\xe3\xff\xb3\xc4\x45\xb9\x06\x82\xd9\xe5\x02\x67\x13\x2b\x87\xf9\xb1\x91\xef\x37\xba\x02\x2f\xbc\xe1\x81\x0d\x8d\xbe\x5c\xef\xad\x19\xc1\x22\x2b\x21\xcd\x04\x90\xd4\x7f\x29\x66\x74\xf7\x21\xd3\x34\xcb\x71\x98\x90\x14\xaf\x5d\x33\x8b\x55\x8a\x87\x56\xde\xee\xef\x5f\xce\xde\xbf\x9c\xfd\x13\xbf\x9c\x65\xaf\x66\xb9\x0d\x9b\xf1\x6c\x96\x6d\x38\xe8\x66\xaf\x67\xf9\xde\x77\x5c\x92\x04\xea\x64\xfa\x4c\x58\x3b\xec\x79\x92\x03\x46\xca\x4b\xc9\x12\x55\x91\x71\x12\x15\x05\x3a\x81\x22\xa7\xbc\x9b\x2c\x43\x31\x61\x56\xd5\xda\x10\xee\x8d\x60\x95\x72\xe5\x2a\xe5\x20\xa8\xc6\x99\x75\x7b\x3f\xe7\x00\x49\x6b\x3a\x7e\x7b\xf8\xf1\x03\x3d\x5b\xc3\x24\x74\xcf\x31\xe9\x32\xd2\xec\x7e\xd6\x7e\xbf\xd1\x7e\xff\xa4\xfd\x2e\x7e\x8d\x46\x99\xf8\x98\x90\x34\xc5\x97\xf2\x0b\xcf\xcb\x0c\x9e\x32\x8a\x94\x05\x19\x9b\x09\x69\x94\x9a\x09\x73\x32\xce\xed\x94\x24\x21\x4e\x21\x03\xde\x00\x15\x1f\x46\x91\x69\x1e\xa5\xb1\x1c\x8a\x91\xf5\x93\xf1\xf5\xd1\xf8\x7a\x67\x7c\xbd\x34\xbe\xfe\xc7\xf8\xfa\x97\xf1\xf5\xd6\xf8\x7a\x61\x7c\xfd\xc3\xf8\x3a\x66\x5f\x6b\xa7\xd5\xae\x6b\xe8\x1c\xbd\x3b\x78\x41\xa7\x38\x44\x3b\xdb\x81\x4c\xfc\x70\xf8\xd3\xdb\x83\x8f\xc7\xef\x5f\x7e\x7a\xfd\xf2\xed\x4f\x1f\x5f\x85\x68\x57\x65\xc2\xac\x86\xea\xa7\xca\xa9\xa0\x9c\x10\x7d\x41\x56\x82\xf2\xa3\x0e\x19\x9f\x5e\x1c\xfd\xfc\x16\x5d\xab\x9a\xde\x1d\xbd\x7e\x4d\xa1\x3f\x1e\xbe\x79\x79\x74\xfc\x31\x44\x5b\x9b\x9b\x9b\x43\xde\x43\x7e\xe3\xfd\x2c\xc9\xc6\x9f\x43\xd4\xa5\xac\xb3\x28\xbb\x46\xde\xc1\x18\x42\x19\x87\xea\x6d\x23\x7b\x80\x41\xf7\xf3\x26\xdf\x27\xf7\xa1\x30\xee\x37\xb2\xbf\xfa\x46\xb6\x26\x5d\x40\x14\xb3\x68\xe7\xae\x3c\x40\x3c\xcf\x2f\x17\x65\xf6\xf7\x0f\xfa\xe6\x30\x86\xb4\x47\x2a\x02\x06\x6d\xd0\x0b\x30\xa4\x39\x5d\x6f\x74\x27\xd7\x7d\x03\x50\x5c\xa1\x3f\x50\xe5\x49\xe8\xc1\x03\x91\x3b\x10\xfe\x22\x98\x98\x3c\xc3\x17\x5d\xfb\x15\x9d\xe1\xf9\xeb\x07\xb4\x4d\x4b\xdb\xde\x8f\xb7\x85\xbb\x48\xb3\x38\x12\x97\xe1\xf2\x82\xdf\xf2\xcf\x8e\xac\xd7\x76\x0c\x54\xe0\x88\x76\x6e\xf0\x0a\x5f\x0c\x40\x7b\xc9\x3d\xf7\xfa\x6c\x8c\x28\x56\xc4\xb0\x55\xeb\xec\x44\xc7\xd4\x6f\x21\xda\xfe\xe6\x31\x2b\xa9\x3d\x4e\x16\x6f\xce\x28\xcb\x93\x38\xee\x84\xdf\x7c\x17\x74\x4c\x94\x77\xc2\x27\x9b\xd7\xa7\xc1\x76\x2b\x9f\x4f\xf7\x7c\xef\x9e\xef\xfd\x79\xf9\x9e\x62\x7b\xec\x9d\xff\x1d\xf0\x3d\x4b\x76\x5f\x5d\x74\xf7\x48\xee\xa2\xa0\x4f\x70\x5f\x29\xda\x90\xcd\x6b\x07\x43\xce\xee\x55\x38\xa2\xc9\x13\x1d\x80\x7e\x4b\x11\x7e\x99\x92\xf2\x4d\xb4\x90\xe2\x62\x57\x48\xd4\x21\xe3\x41\xdd\xcd\x6e\x80\xc4\x73\x68\x90\xee\x43\xc5\x1a\xbb\x5b\x86\xac\x1f\x6a\x19\x9b\x9b\x9b\x22\xef\xbf\x6b\xf2\x46\xd1\x68\x14\x4d\xb1\x6c\x4d\xcf\xd3\x0e\x00\xa1\x9d\x37\xf7\xd4\xa9\x65\xbf\xa9\xcf\x4e\xb2\x33\x9c\x44\x63\xd1\xac\x9d\xad\xce\x19\xa1\x2f\x7b\xea\xaf\x5c\x83\xf8\xa9\x11\xa2\x98\x45\x69\x9a\xa5\xc6\xb8\x4d\x08\x75\xb6\x09\x6b\x20\x1a\x5a\x81\xd3\x55\xe8\x81\xd0\x51\xa9\xce\x4c\x61\x3d\x50\x53\x4d\xfc\xfc\x16\x7a\x81\x8c\xca\xe4\x99\xcc\x1e\x9b\x07\xd0\x3f\x44\x13\xd0\x20\x59\x0f\x9c\x06\xfa\xd9\x84\xf5\x81\xea\x73\x0d\x27\xbf\xda\x8a\xf5\xfe\xb6\xaa\x5b\xaf\xbe\x6d\x01\xad\x4c\xb9\x42\x19\x5a\xcc\x6f\x70\xa5\x9c\x31\x2c\xa2\x98\x9b\x93\x82\xb9\xe7\xc5\x02\x8f\xe9\x06\x26\x4d\xf4\x75\xc3\x2b\xee\x41\xc5\x67\x3d\xa5\xaa\x18\x61\x0a\x17\xf3\xa8\x5c\x96\x1d\xd6\x78\x16\xe5\xd1\xb8\xc4\x79\x21\xd4\xfc\x70\x37\xcf\x4b\x6b\x7b\x89\xb7\x0d\x32\x4d\x03\xcd\x1e\x1a\x6d\xae\xf9\x5d\x7f\x90\xe9\xac\x44\xc2\x2b\xad\xe5\xe1\x97\x8f\xc1\x90\x38\x19\x48\x00\xbd\x2b\x02\x68\xc7\xe3\x67\x88\x59\x89\x00\x0c\x04\xa6\x85\x17\xab\xf2\x96\x78\xab\x3f\xf8\x25\x23\x29\x04\x6c\x40\x4f\xa1\x0e\x14\xa2\xce\x66\xa7\x8f\x36\x38\x70\x85\xf1\xdb\x8d\xe7\x02\x82\xf6\xfc\xd9\x27\x03\x06\xb1\xe2\x6c\xf0\x1e\x6e\x30\xaf\xcb\x37\x9d\x97\x2a\x63\x44\xd3\x19\x0d\x6c\x9f\x60\x8a\x08\x01\x3d\x5c\x3f\xd3\xd6\xbc\x30\x8f\xcd\x35\xb3\x42\x52\x5a\x89\x1f\x59\xba\x4f\x6a\x8f\xb3\x24\xda\xb8\x32\x3d\x64\x5e\x48\x8e\xd9\xf6\x2e\xc5\xfa\x19\x8b\xf9\x3c\x1c\xa2\x1f\x49\x1a\x23\xf6\xc0\x8b\x77\x54\xc6\x6c\xa6\x52\x45\xa7\xa3\x6e\xf3\xc1\xfe\x25\x80\x30\x52\x33\x7c\x21\xcc\x98\xe5\xb9\x8b\xa6\xb1\x93\x0f\x3d\x75\x54\x9f\x97\x68\x35\xdb\xfa\xdb\x17\x30\xb0\xe1\x76\x35\x7b\x88\x6c\xec\x6f\xeb\xe0\x22\x1e\xb2\x6e\xdf\xa1\x9a\xea\x11\xda\x0e\x0f\x7f\x21\x5b\x98\xa0\x1e\x2b\xb2\xbf\x8f\x36\xfb\xc6\x49\x6d\x94\xe3\xe8\xb3\x02\xa5\xa3\xdc\xd8\x47\xfc\x65\x39\x9d\xc1\xe7\xb3\x28\x7f\x9e\xc5\x18\x6a\xf0\x1e\xc4\xe8\x64\x0b\x93\x9c\xa2\xcc\xdb\x51\x08\x9b\xb4\x95\x48\xe4\x80\x16\xf9\xed\x68\x04\x9a\xfb\xcf\x21\x92\x9b\xcc\x7c\x51\x56\xbd\x50\x37\x27\xdb\xe3\x67\xbe\xb7\xc8\xf1\x84\x5c\xb0\x40\x5a\x9b\x17\x7d\x3a\x0b\xc0\x35\xfc\x2e\xee\x79\xc4\xb7\xea\xd9\xf7\xda\x2f\xc3\x31\x34\x4a\x80\x9b\xd7\x06\x14\xf0\x45\xfa\x34\xfc\xed\x73\xd7\xeb\xbc\x1b\x3a\x55\x50\x8a\xe7\x98\x67\xb3\x0f\xcb\x81\x9b\x6e\xb3\xe5\x20\x66\x84\xb6\xa4\xa8\x63\x92\xe5\xb6\x19\x5d\x51\xe6\x55\x51\xf1\xb5\x19\xa5\x50\x63\x3e\x37\x07\x65\x8f\xdc\x6c\xa5\x83\x85\x22\x0f\x10\x6e\x78\x6e\x53\x20\xb4\xbf\x1b\xfb\x28\x15\xfb\xc2\xf7\x68\x1b\x3d\xa5\xa7\x1b\xb4\x81\xe8\x7e\x90\xfa\x68\x82\xbb\x91\x9f\xe1\x8b\xbb\x24\x0d\x2b\xee\x80\x4d\x1b\x0d\xac\xe1\x37\x23\x0e\x87\x67\x68\xd4\xf1\xdb\x50\xc0\xef\x36\xad\x96\xd7\xd2\xc9\x32\x49\x24\x1a\x86\xf8\x0c\xa7\x25\x7b\x2c\x00\x2c\xff\x97\x22\x4b\x51\x34\x22\x36\x8f\x17\xae\x13\x3f\x66\x3f\x2e\x93\xc4\x7e\x47\x29\x1e\x14\xd0\xd2\x8f\x58\x69\xf7\x41\x14\x6b\xd8\x69\x57\x31\x76\xb7\x0d\x43\x90\xa2\x95\xeb\xea\x53\xfa\x3d\x00\x33\x0a\x92\xc6\xf8\xe2\x68\xd2\xeb\xf6\xba\x7d\xf0\x0f\xf9\x68\xcb\xf3\x24\x52\xc2\x3b\xb6\x82\xe5\xe5\x02\xf3\xe6\x00\x08\xa8\xc8\xf4\x69\xd6\x23\xfd\x2f\x22\x8c\xf0\x80\xc2\xef\xa1\x6b\x2e\x8a\x99\xd6\x7f\xb2\x15\xb4\x81\xba\x3d\x3a\x73\xb2\xf6\x0d\xd4\xed\x77\x5b\xad\xbd\x98\x14\x8b\x24\xba\x64\xf3\x02\x7e\x46\xd3\x92\xca\xb6\x12\x1b\xf6\xbb\xb5\x0b\xc8\x7e\xc1\x8a\xd5\xbd\x72\xa5\xb5\x99\x93\xef\x5f\x5e\x46\x0f\xe8\x96\x66\x51\x0c\x9e\x0e\x44\xcc\xc5\xcb\x1e\x37\xad\xeb\xa3\x47\x3f\xc8\x44\x39\xad\x6e\xdf\x6a\x1f\x3f\x4b\xbb\x4d\x67\x66\x0d\x34\x73\x30\x36\xd9\xe8\xa9\xfd\xae\x95\xbf\x09\xa3\x6b\x46\x39\x1c\x19\x0e\xd5\x40\xb3\x33\x9c\x27\x59\x14\xe3\x58\x2a\x83\x3d\x6b\x42\x1f\xc0\x47\x45\x24\x55\xef\x1a\x87\xe8\xe3\xd1\x8b\xa3\x10\xcd\xa3\xcf\xa0\x1e\x26\xe9\xd9\x32\x49\x71\x1e\x8d\x12\x7c\x97\x03\x54\xa7\x01\xfb\x05\xef\x16\x7a\x84\xb4\xec\x7e\x7f\x90\xe3\x45\x12\x8d\x71\xaf\x8b\xba\xe0\xd8\x8d\x9e\x16\x3a\x66\xa0\xc8\x2c\x3d\xc3\x79\x59\xa8\xb0\x9b\x20\xf7\xc5\x78\x4c\xe6\x51\x62\x33\x59\x92\xfa\x99\x7d\x99\xbd\x60\x05\x5c\xca\xab\x0d\xa1\x69\xba\x36\x64\x02\x1e\xaf\xa9\x31\x08\x64\x99\xb9\x31\x32\x65\x08\x9a\x36\x63\x6c\x94\x6d\x29\x4f\xbc\xab\x71\x69\x75\xd5\x07\x68\x4d\x85\xa6\xd4\x1d\x9f\x27\x3c\x37\x57\xa1\x9a\x3b\x8a\x71\xd8\x67\x00\x09\x2e\x8a\x8f\xb3\x28\xed\x6d\x82\x23\xd9\x47\xcc\xf2\x9c\x5b\xf0\x73\xc2\xda\xea\x43\x08\x57\x2d\xc7\xc0\xe2\xc1\x12\x5c\x35\x73\x54\x46\xe9\x25\x77\xbe\xc3\x5d\x92\xa6\xd5\x68\x1d\x70\xbc\x1e\xa4\x31\xbb\x02\x60\x34\x44\x26\x97\x05\x77\xa6\x5e\xa0\x11\x9e\x64\x39\x1e\x38\x74\xf5\x8a\x1f\x1d\xea\x71\x7f\xc5\xf7\xa0\x06\xd2\x7a\x05\xfb\xbc\x81\x7c\xb9\x7e\x1f\x72\x73\xb1\x79\x74\xc1\x42\x57\x5e\x90\xf2\x32\x44\x4f\x40\x8d\x2d\x76\x1d\x52\x70\xb7\xc6\x50\xb4\x6f\x6f\x32\xda\x24\xf7\x36\x28\xc4\x9e\x51\x54\x9f\xce\xfa\xc2\x4e\x59\x36\xbe\xea\x82\x10\x59\xe9\xef\x1f\x8e\xde\x0e\x24\x6e\x19\xb0\x72\x5d\x09\x4e\x63\x0b\x14\xd9\x71\x3c\x03\xb4\x88\x8a\x82\x72\xac\x72\x96\x67\xcb\xe9\xcc\xa4\x7b\xd9\x05\x4e\x61\x50\xab\x7b\x2d\xa9\x78\xd9\x23\x38\x23\x79\x24\xdd\xca\x71\x0a\x00\xfe\xaa\xc3\xac\xae\xa1\xb6\x33\x61\x39\xaa\x55\x80\x7a\xeb\xa4\xf8\x91\xa4\xa4\xc4\x16\xc6\xac\x6e\x80\x5c\xa8\x75\xc2\x94\xad\xdc\x8e\x6a\xab\xe1\x3d\xdf\x4a\x18\xf5\xd3\x53\x52\x0a\x3c\x1f\xfd\x8c\x6d\xf1\x69\x8a\x4b\x88\x55\x7c\x34\x39\x4e\x89\x57\xc7\x05\x65\xcb\x19\xe6\x3f\xe4\x32\x43\x65\x16\x48\x9d\x94\x74\x85\xee\x8d\xd7\x28\xfb\x21\xab\xe9\xb1\xce\xf4\xa1\x08\x38\xec\x2a\x10\xce\xf3\x2c\x17\xce\x68\x58\x8f\x0b\x94\x66\x25\x1a\x67\x79\x8e\xc7\x65\x78\x2e\x57\x8b\xd9\x6b\x63\xd9\xd0\x82\x82\x04\x96\x2c\x13\xfe\x7b\x0a\xff\x0d\xca\xec\x75\x76\x8e\xf3\xe7\x51\x81\x7b\xc0\x52\x98\x96\x57\x71\x2f\x0a\xf5\x0f\x7e\xbf\xcc\x2f\x6d\x4e\xe8\xff\xa7\xea\x00\xae\x81\xe8\x1e\xbf\x75\xc2\x63\x3e\xc8\x52\x7c\x8e\x5e\xd2\x51\xf5\xba\x70\xc9\x0b\x1d\x01\x2b\xd5\x7f\x77\x4b\x84\x2f\x48\x51\x16\x01\x5a\x24\x38\x2a\x40\x18\x86\x91\x67\xa9\x44\xd5\x24\x4b\x92\xec\x9c\xa4\x53\x28\x59\x50\xde\x67\x2d\x23\xde\xc3\x00\x3c\x2b\x04\xea\xc1\x47\x4d\x7c\x58\xd9\x7b\xf0\x7b\x65\xfa\x13\x8e\x3e\x63\x58\x84\x8c\xcd\xc3\x35\x34\x01\x4b\x5a\xc9\x5a\x19\x09\x50\x06\x0b\x5e\x2a\xd8\xc4\x33\xd4\x72\xca\x7a\x97\x15\x05\x19\x25\x6c\x0a\xc1\x79\x06\x37\xe7\xfb\x70\x48\xa5\xca\xbc\x64\x3f\xa9\x20\x2d\xb0\xf5\x72\x32\x21\xd3\x4b\xfe\x71\x24\x48\xe9\x11\xfa\x4c\x9b\x67\x7f\xea\x92\x0a\x3e\xf9\x7d\x16\x03\x9b\x2b\x30\x79\xa5\xc4\x3e\xc5\x05\x14\x83\x9b\x2a\x38\x79\xeb\xc3\x3e\xf9\x35\x91\xca\x63\x05\x1e\x3d\x92\x0b\x53\xdd\xde\xb0\x02\xbf\x46\xa3\xcc\xc8\xf3\x94\x10\xb7\x2f\x6c\x00\x70\x69\xa3\xe7\xb1\x12\x5a\x2f\xb4\xc2\xec\x93\x63\x41\x03\x41\x16\x84\xf6\x01\x57\x28\x1c\x21\x58\xe1\x70\xaa\xfd\x2e\xc5\x6f\x5b\x90\x60\x7c\xc1\x3a\xef\x5e\x49\xe9\x9c\x91\xc3\x38\x4a\xe9\x79\x20\x92\xac\x99\xa7\x73\x0d\x59\x96\xa3\x08\xbd\x7a\xf9\x4f\x38\x7a\x0b\x19\xed\xce\x18\x8a\xdc\x5d\xc5\x81\xee\xe7\x19\x16\x1e\xf6\x22\xed\x12\x97\xc7\x3f\xd1\xc2\x04\xd0\xf5\x14\x15\xe8\x1c\xd3\x05\xa2\x5c\xab\x88\x61\xac\x69\x32\xd0\xcf\xd8\x38\x88\x8b\x71\xea\x2c\x85\x09\x38\xb4\x66\xc1\x24\x74\x51\x88\x95\xd0\xe3\xc5\x9a\x9c\x8a\x71\x27\x4b\x0a\xd2\x37\x5f\x5e\x01\x7a\x6a\x34\x12\xea\x5f\x9a\x3c\xd5\xb8\x7c\x23\x86\x63\xcf\x0a\x3e\xc7\xe4\x7e\xc1\xfe\xa7\x2c\xf1\x32\xab\x5b\xe0\xda\x29\xe1\x37\x5b\xea\x74\xb5\xfd\x8e\x8b\x1d\x10\x72\x37\x4b\xbd\x24\x73\x5c\xfc\x1e\xcb\x3c\xe5\x2a\x45\xba\xb8\xa5\x82\xaa\x60\x87\x7b\xd8\xa2\x91\xb4\x62\x71\xc8\x41\xf6\xa4\x15\x51\x28\x32\x10\x37\x86\x74\xee\x15\x2d\x98\xb5\x49\xff\x56\xaa\x02\x05\x20\xf1\xaf\x9b\xdd\x58\xb3\xd0\x70\xea\xf9\x86\x0a\x81\xb0\xec\x45\x79\xfe\xe3\xea\x0a\x6d\xee\x79\x8f\x34\xbc\x5e\xe7\x70\xc2\xd2\x8d\xb3\x0c\xc7\xb9\xe8\xc9\x83\x07\x88\xff\xf6\x09\xfd\xb4\x49\x3b\x57\x3f\x61\xf8\xbc\x9f\x19\xb2\x18\x2f\x2c\x35\x21\x9b\x17\xdd\xa0\xdb\xd5\xaf\x59\x2c\x1f\x69\xbe\xd2\x3a\xa1\x54\xca\x74\xa9\x88\x1a\xeb\x21\x15\x49\x27\x0c\x4c\xc4\xef\x90\x47\x31\x6e\x30\x09\xb0\xe5\x79\xd6\x2d\xd0\x58\x46\x73\x71\x48\xcb\x0c\xf6\xd2\x86\xbe\x2a\xa8\x46\x3b\x1a\x9b\x75\x9a\x6a\x2e\x83\x64\x28\xf8\x48\xa3\x2c\xdf\x82\x85\xc7\xde\x3d\xcd\x5f\x9d\x2c\xa0\x2b\x22\x1a\xa7\xae\x33\xb9\xe5\x5f\x07\x66\x79\xb0\x48\x96\x85\xea\x02\xff\xf6\x3a\x36\x94\x40\xa6\xfe\x68\x86\xc7\x9f\x0b\x71\x6c\x62\x3c\x52\x5c\x6e\x16\xfc\x99\x5c\x72\x09\x1e\x7c\xbd\x71\x88\x19\xc9\x8f\xbd\x31\x88\xcd\x68\xc2\x5a\x03\x74\xfd\x47\x0a\x5e\x77\x69\x07\x61\x95\xf8\xcc\x59\x75\x1b\x13\xc7\x2b\xb5\xf4\x66\xc3\xff\xdd\xbc\x38\xd9\x7c\xf4\x5d\xf4\x68\x72\xfa\x65\x77\xf3\xfa\xbf\x86\x64\x50\xe2\xa2\x94\xe0\x2b\x8c\xbd\x66\xc8\x5f\x67\xb0\x2d\x86\x09\xe7\xff\xe1\xff\xf6\x36\x2f\xfa\x4f\x6b\xc7\xa9\xd3\xdf\x70\xa8\xa2\x64\xb1\x38\x58\xd0\x3b\xe6\x3b\x98\x9b\x1b\xce\xe1\x05\x2f\xdd\x8f\xb5\x51\x9b\xf4\xcb\x5d\x00\x22\xd3\x49\x85\xb7\x33\x66\x5f\x28\x9b\xd3\xc0\x0e\x1e\xfd\xe8\x05\xb3\xba\x0c\x41\xbb\xba\x05\xb8\x39\x2e\xe6\xf4\xdf\x71\xb4\x28\x40\x76\x48\x12\x24\xbe\x03\xdd\x37\xa3\xdd\x63\xe6\x72\x5e\xeb\xb0\xd1\xc0\x91\xdc\xde\x19\x76\x70\x34\x9e\xa1\x71\x54\x38\xd5\x90\x82\x11\xca\x72\xce\x67\x48\xa3\x26\xb6\xca\x58\x40\x91\x76\x54\xc5\x5a\x2b\x96\xf3\x39\x8e\x2b\x09\xcc\x6a\xf0\x8e\x09\xcd\xaa\xbd\x82\xe0\x90\x16\x5d\xe7\xb9\x07\x43\x91\x2c\xcd\x7f\x39\xfb\x90\xd2\x8a\x70\x88\x57\x51\x01\xce\x68\x66\xd1\x8e\x68\xc8\xd4\xa8\x08\x99\xc7\xe7\xf0\x65\x77\x13\xee\x27\x11\xed\x9a\x3e\x8f\xe0\xbd\xbb\x9c\xa1\x04\xc3\x7b\x6a\x2d\x04\xdf\x62\x81\x73\xda\x5d\x31\x17\x29\x84\x2f\x9c\x12\x16\xe1\x2e\x2a\xf0\x3c\x5a\xd0\x39\xd9\x32\x14\x7e\x3d\x69\xbe\xa0\xf5\x1a\xfc\xb2\x6d\x3d\xee\xa3\x1f\xd0\xb7\x74\x57\xe7\x59\x27\xe4\x74\x50\x66\xc7\xb4\x21\xae\x12\x5a\xdf\xdf\xd7\x32\x81\xf6\xeb\x2b\xfc\x7e\xdf\x53\xa3\xae\x64\xb2\x6a\xac\x70\x16\xae\xad\x4e\xc5\xf9\x0d\xfe\x0f\xab\x01\x26\xd5\x20\xd7\x37\xfc\xd4\x27\xc8\xb2\x82\x26\xcb\xec\x2e\x69\x52\xa8\xaf\xe5\x16\xdd\x92\x24\x25\x13\xe4\x4f\xb0\x25\x0d\xda\x6f\xaf\x79\x43\xdd\x2e\x27\x28\x97\x58\x0d\x24\xdf\x88\x74\x35\xa0\xb1\xd3\x7d\x5a\x51\x0d\x31\x8b\x5e\x68\x17\xef\x0e\x61\x03\x07\x9c\x29\xeb\x3f\x4a\xaa\xdf\xd1\x53\xd0\x84\xf9\xd1\x17\x97\x71\x8a\xce\x0d\x3a\x6e\x22\x63\x93\x90\xec\x11\x6c\xec\x57\xd2\xb8\x46\x65\x36\x5b\x6d\xac\xa9\x96\x42\xad\x92\xa6\x1c\xaa\xe4\x4e\x83\xa5\x96\x19\x95\x2f\x49\x8c\xb6\x37\x99\xef\xa0\x47\xfc\x92\x90\xb5\xc9\xde\x29\x6c\x5e\x20\x66\xe0\xe1\x1a\x78\x35\x12\xb3\xff\xc6\x9f\x7b\x21\xd0\x39\xb8\x34\xe2\x6a\xb7\x8d\x5b\xc2\x8d\x77\x1b\x14\xce\x75\x05\x3e\x34\x89\x9e\xed\xbd\x75\xdb\xae\xa7\x22\x7e\x01\xe6\xab\xcf\x84\x10\x21\x18\xe1\x5a\x49\xd6\xa8\x5e\x55\x05\x68\x77\xd3\x7f\x67\x20\x1c\x12\x8b\xb3\x75\xa1\x64\xde\xe6\x60\x9b\xde\x73\xa5\xef\xfa\xcb\x08\xc0\xc9\x36\x35\xdf\x89\x10\xf5\x58\x37\x2c\x29\x51\xf4\x2d\x2d\xca\x28\x1d\x53\x3e\xa2\x0a\x5f\x5d\x49\xa4\xf1\xc2\xf0\x8a\x0d\x7e\x19\x0e\x34\xbc\xa9\xcc\x3e\x02\xb8\x91\xac\xb2\xdb\x16\x51\xe2\x74\xdc\x84\xa5\x0f\x8e\x81\x51\x4b\x14\x79\x42\x25\x79\xf1\xc3\x99\x2b\xef\x19\x8c\x86\xf5\xad\x7b\x77\xe8\x61\x7d\x69\x8d\x1b\xd1\xe3\x66\xec\xfc\xa8\x0c\x49\x56\xc5\x8f\x28\x7a\x23\x0c\x89\x12\xdd\x96\x23\xa2\x7d\x2a\x9b\x87\xc3\xba\x7e\x83\xc1\x1c\xf1\xbe\xdd\x60\x28\xec\x77\xdb\x81\x8c\x58\xdb\x2d\x56\x37\x03\xbc\xc9\xda\x66\x49\x37\x1a\x0c\xef\x5e\xdb\xd1\x80\x67\xbf\xe6\xb1\x38\x81\x32\x5a\x8e\xc4\x0d\x76\xd1\x92\x43\x41\xc1\xda\x31\xd8\x27\x0d\xb6\x2d\x82\xd9\x5b\x26\x88\xc8\x1c\xc4\xdf\x0b\x73\x99\x28\xa3\x82\xda\x31\xd0\x62\xf6\x43\x00\xe9\x11\x29\xbf\x74\xb7\x9d\xf5\x75\xb8\x76\x64\xaf\x6b\x95\x7d\xea\x35\x1a\x43\x34\xa7\x1e\xf6\x6c\x55\xfa\x69\xd3\xef\x23\x88\x15\xe1\x3b\x55\x28\x7e\x04\x22\x15\xde\x2b\x84\xf2\x17\x4b\x87\xfd\x2c\x64\xff\x89\x14\x7e\x0d\x1e\xaa\x9f\x2c\x47\xbb\x22\x0f\xf5\x0f\x51\xee\xb8\x9c\x3c\x09\xf9\xff\x22\x0d\x2e\xdd\x43\xf1\x43\xd5\xc3\x60\xc5\x2f\x95\xce\xe1\xe5\x4f\x5e\x8f\x6b\x2f\x18\xfa\x12\x19\xb4\x6b\x86\x16\x7a\xd2\x0c\x58\x61\xf1\x15\xda\x09\x62\x1c\x3f\x63\x18\xc5\xcf\x58\x1b\x03\xa4\xf1\x1f\x02\x4e\x6e\x72\xa1\xfe\x21\x72\x4d\xbd\x5b\xe8\xa4\x48\xac\x31\xf9\x22\x54\x3f\x59\x8e\xb6\xa9\x87\xfa\x87\xc8\x35\x04\xa8\xd0\x4e\x10\x50\x5a\xbe\x95\x63\x1d\x3a\x42\x37\x49\xf4\xd0\x81\x74\x92\x44\x9d\x62\x0f\x09\xb5\xdf\x7a\x7f\xd3\x69\x28\x7f\x89\x74\xc6\x3b\x42\xf9\x4b\x8e\x9e\xad\xbd\x50\xfd\x94\x63\xa2\xdc\x20\x14\x3f\x44\x2a\x5d\x98\xa1\x58\xd7\xd7\xd2\x65\x16\x7f\x67\xda\x09\xb7\xbe\x0b\x6a\x3d\x6e\x04\x9d\x65\x39\x79\xd2\x09\x9f\x7c\x73\x7d\x1a\x6c\x6f\xb5\x79\x83\x6e\xae\xca\x7d\xb6\x26\x3b\xfc\xe9\x75\x27\x44\x9d\xcd\xc1\xd6\x93\xc1\x56\x67\xed\x5a\x38\xa7\xda\x6e\x15\x3b\xf5\xfe\x6d\xfb\xfd\xdb\xf6\xbf\xc2\xdb\x76\x5e\xcb\x9a\xeb\x9d\xea\xef\x78\x32\xc9\xf1\x25\xfa\x99\x24\xe3\xcf\x18\x7d\xff\x0b\x9e\x4c\xec\x07\xee\x2d\x7d\x58\x01\x18\x89\x52\x74\x44\x85\x85\x08\xa0\x48\x94\xba\x60\x3f\x46\x23\x0a\xf6\x8f\x6c\x8a\x93\xa2\xc4\x49\x82\x73\xf4\xfd\x04\x12\x5d\xe0\x9f\xa2\x33\xf4\x73\x96\xc5\xe8\xfb\x69\xe5\xc3\xfb\x5d\xe5\x70\x84\x7b\xa7\x7b\x13\xa5\xd1\xd4\x7c\x0d\x3f\x18\x52\x2c\x0c\x73\x06\x30\x67\x00\xe2\xd5\xfb\xe1\x08\xe4\x3a\x1b\x98\x8c\xa2\x54\x80\xbc\x04\xa3\x62\x1b\x82\x49\x31\xc5\x10\x97\x33\x01\xf8\xe2\x59\x0d\x5c\x3c\x92\x1e\x30\x67\x75\xf5\x15\x33\x59\xdf\x5b\xf0\x95\x5c\x05\x98\xe2\x52\x00\xbe\xc3\x79\x01\x0f\x3b\xaa\xa1\x17\x1c\x44\x76\xe2\x3c\xca\xe7\x75\xdd\xa0\xf9\x12\x18\x97\x25\xc4\x91\x71\xe1\x0b\x9e\x25\x40\x05\x57\x31\x20\x05\xbb\xa0\xc2\xa0\x72\x37\x40\x12\xab\x42\x2d\xd0\x75\xb5\xd7\x02\x06\x24\xfc\xc3\x70\x33\x72\x9c\xc6\x9e\xbe\xb1\x0c\x01\xf6\x0c\x84\x3d\x17\x6a\x44\xd3\x25\x26\xf3\x6c\x81\xf3\xf2\xd2\x03\xb7\xe0\x59\x02\xf4\x55\x59\x2e\xde\xe5\xd9\x19\x89\xbd\xe4\x46\x17\xea\x82\x67\x4b\x62\x5b\x8c\x6b\x4a\x90\xc5\xd8\x2e\xd0\xce\xc7\xda\xda\x9a\x94\x85\x7f\xc6\xa3\x1d\xd4\x13\xd5\x98\x7e\x42\x73\x7b\x85\xa4\xf8\xdc\x5a\x36\xaa\xa4\xe6\x32\x94\x07\x7f\xd4\x7a\x2e\xa0\x34\x20\xcc\x2c\xef\xf1\x39\x5d\x2e\xe0\x3a\x5c\xaf\x22\x1e\xf1\xcc\x17\xcf\x9c\xbc\x62\x26\x4a\x7e\x98\xb9\x25\x53\x58\x03\x34\xf7\x2d\x2e\x9d\xdc\x85\x22\x7c\x0a\x22\xd6\x81\x03\x37\xfa\xf5\x57\xd1\x06\xa5\x6b\xb7\x0f\x8a\xc0\x01\x88\x7f\xf6\x74\x18\x45\xd9\xea\xb0\x10\x2d\x48\x28\x37\x43\xfe\x3f\x3b\x33\xe8\x9d\xe4\xd8\x2a\x8c\xa2\x3a\xf9\x84\xc6\x57\x20\x61\x34\x7a\x09\xf5\x0f\xa7\x89\x4f\x72\x0d\xb0\x1f\xce\x00\x39\x40\x4f\xb5\xcf\xc9\x99\xe0\x22\xd4\x7e\xf7\x98\x91\xc1\x75\x7f\x8f\x4a\x4c\xc3\x21\x38\x05\x2d\x30\x52\x63\xc8\xd8\x4e\x0c\x5e\x4a\xd6\x28\xb9\x79\xc6\xd7\x34\xb6\xca\x71\x51\xa1\x51\xd4\x29\x22\xfc\x61\x9d\xf2\xf4\x28\xa6\xcd\x34\xae\x17\x5e\x99\xb4\x3d\x7d\xc9\x31\x73\x5f\xaf\x7a\xf1\x19\xe3\xc5\x61\xf1\xe1\x32\x1d\x93\x74\x5a\xdb\x15\x28\x6b\xc1\xb7\xa3\x40\x4f\x47\x74\xbe\xf0\x4c\xdd\xab\x5b\x50\xc2\x28\x9f\x39\xb8\x81\x2f\x0f\x8c\x78\xc0\x27\xa0\xe0\xdb\x03\xc7\x5f\x81\x0a\x30\xfa\xe9\x40\xe9\x0f\x02\x19\xa0\x4c\xf1\xc2\x1a\x75\x8a\x04\x4f\xdb\xea\x75\x87\x68\x9e\xa7\x78\x6b\xb5\xa1\xb5\x34\x4f\xdd\x3a\x2e\x45\xed\x75\x38\x65\xa6\x57\x02\xf2\x67\xec\x1f\x99\x0e\xc5\xbf\x1d\x38\xfd\xca\x9d\x41\xca\x14\x0f\xac\x7b\x45\x25\xca\x3c\xb7\xef\x2d\x9c\x3e\x57\x95\x75\x72\x3c\xed\x1e\x3e\x3b\x78\xab\x35\x46\x3f\xe9\x9e\x63\x2f\x53\xb6\x51\xeb\xaf\x40\x99\x32\xd9\xf4\xce\x66\xaa\xf9\xe1\x36\xcb\x86\xac\xba\x76\x89\x49\x0e\x3a\xa9\x71\xb4\x00\x1b\x6e\xed\xe2\xc3\x83\xff\xc3\xe7\x07\xef\x8c\x95\x4a\xcb\xe9\x76\x36\x84\x09\x7e\x74\xb1\x51\x19\x90\xe5\x1b\x0f\xc5\x28\xc4\x80\x37\x23\xd6\x21\x38\xa3\x90\xdc\xb2\x2e\x62\xe1\x89\xe4\xb4\xb0\x33\x71\xe1\xa1\x67\xde\x55\xa5\xa0\x04\xe9\x8a\x1d\x24\xcd\x62\xdc\x0d\x0c\x88\x29\xdc\x2a\x87\xa8\x4b\x45\x84\x4f\xe3\x84\xe0\xb4\xfc\x07\x03\xef\xaa\xbb\xac\x7e\x70\x93\xd6\x70\x79\x9e\xe5\x9f\xab\x1a\x4c\x71\xf9\x89\x83\x5a\x20\xa6\xc3\xf1\xd0\x5e\x93\xb7\xec\x16\x58\x53\xe2\xe5\xbc\xaa\x5f\xb8\x9c\x7d\x82\xb9\x1e\x67\xc9\x3f\x7e\x87\xfe\x9d\xcf\x48\xb1\x90\xbe\x55\x9d\xee\x15\xb3\xd9\xad\xd1\x06\x3f\x4f\xbd\x9c\x9f\x14\xcf\xb3\x34\x65\xfe\x5e\xb4\xe5\xd6\x37\x68\xaf\xe7\xdd\xdc\x1e\x3c\xf0\x6e\x7a\x7a\x95\xbd\xbe\x7f\xbf\x61\x2f\x9c\x85\x04\x5d\x49\xf3\x60\x62\x06\x9e\xd7\xb9\xfc\xe1\x55\x9c\xd2\xba\x85\x37\x42\x5d\x9e\x67\x0a\x22\xe3\x18\xd0\x09\xb7\x37\x69\x92\x7e\x80\xe8\x84\xdb\x5b\x34\x4d\x09\xef\x9d\x70\x7b\x57\xa6\x30\x41\xa7\x13\x6e\x3f\x91\x49\xba\x28\xde\x09\x77\xb6\x65\x06\x5d\xe1\x9d\x70\x67\x47\x25\x28\x11\xbc\x13\xee\xa8\x4a\xd5\x21\xae\x13\xee\x7c\xeb\x24\xe3\x72\xd6\x09\x77\x9e\x38\xe9\x29\x2e\x3b\xe1\xce\x77\x4e\xba\x10\x5b\x3b\xe1\xee\xa6\x93\x59\xcc\x66\x9d\x70\x77\xcb\x4d\xa7\x92\x6b\x27\xdc\x55\xdd\x17\x27\x92\x4e\xb8\xfb\x8d\x4c\x34\x8f\xb9\x9d\x70\xf7\xb1\xcc\x12\x32\x46\x27\xdc\xfd\xb6\x5e\x13\x77\x7d\x1a\x6c\xef\xdc\xeb\xc9\xee\xf5\x64\x7f\x6d\x3d\x99\xe6\xfb\x36\x4a\x12\x78\x9d\x7e\x3b\x47\x90\x9a\x3e\xca\xd1\x5c\xf8\x54\x17\x22\xce\xc4\xcb\x33\x66\x18\xac\xa9\x04\xa0\x37\x02\x4e\x45\x9d\x68\x0a\xaf\xe2\xaa\x55\xbc\x7a\x95\x1f\x49\x52\xda\x4a\x88\x09\xa4\x09\x88\x73\x16\x3c\xc5\x04\x11\xbc\x88\x67\x4a\xf7\x90\x07\x49\x62\x0c\xc5\x94\x8c\xcc\x93\x50\x00\x77\x82\x01\xb2\x6c\x52\x2a\x74\x14\x66\x82\x7e\xa2\xfd\x85\x5d\x03\xd2\xff\xf4\x64\xc7\xd2\x8a\xed\x42\x4e\x0f\xeb\xe3\x04\x5b\x62\xab\x70\x28\xbc\x2f\x7f\x5d\x5d\x41\x00\x0d\x64\x3f\x1a\xa7\x89\x90\x7a\xd2\xa5\x62\x28\x38\x26\xef\x06\xa8\x5b\x66\xec\xe7\xe9\x80\xa1\x59\x0b\x98\x36\xf1\x5c\x3f\xf2\x66\x4e\x26\xa7\x60\x7f\x27\x4d\xcb\xf8\x8d\x64\xdf\x13\x75\xd7\xaa\x86\xf6\x87\x16\xdf\xd7\x88\x87\xf9\xdf\x80\x8e\xb0\xe3\x8d\x8a\xa2\xa5\x1a\x14\xb7\xa3\xea\xfd\x07\x3c\x64\x57\x78\x35\xf0\x6c\x3e\x12\xd1\x9f\xb6\xd7\x61\xdc\x13\xf6\x34\x8e\xca\x48\x8c\x80\xfe\x1e\xd0\x7f\xd0\xbe\xf6\xfb\xea\x0a\xec\xe9\x24\x40\x99\x2d\xc8\xb8\x10\x20\xfc\xeb\xea\x4a\x85\xef\x03\xe5\x20\x6d\xfa\x23\xcd\x33\x01\x4f\x36\x4f\x07\x05\xe5\x08\xd2\x47\x33\x85\x9e\x73\x09\x47\x51\x98\x3b\x5d\xbf\x78\xa6\x4b\x6f\x65\x9f\x5b\xe9\x71\xf1\xce\xbd\x36\xed\xfd\x22\x9f\xb9\xf6\x4f\x36\x4f\xb5\xf7\x1b\xeb\xd0\x7e\x1f\x7d\x01\x9b\xe9\x28\x4d\xb3\x12\x4d\x48\x1a\xb3\x7e\x91\x74\xca\x1a\x7a\x2a\x9b\x1f\x67\x69\x91\x25\x78\x70\x1e\xe5\x69\xaf\xab\x97\x60\xae\x36\x28\x2f\x4e\xb2\x69\x57\xb3\x99\xe3\x3d\xa6\xa8\x70\xdc\xb5\x60\xce\x86\xf4\xd0\x3e\x30\x77\x3d\xdf\xea\x0c\x58\xb7\x02\x93\x20\xcc\x33\x14\xd4\x28\x3c\xa5\xc1\x14\xb7\x58\x8e\x17\x78\x4c\x45\x00\xcf\x7a\x0c\xc0\x9d\xcb\x28\x1a\x7f\x96\x41\x08\xe1\x45\x33\x3f\x9b\x8a\x0b\xcf\x5e\x94\x4f\x97\x60\x52\x7e\x22\x7f\xe9\xb1\xf6\x0d\xdb\x34\x51\x23\x04\x8f\xad\x2d\xa6\x3b\x9d\xea\x39\x10\x74\xe2\xb7\xcc\xe7\xf0\x8a\x6d\xa4\xcb\x24\x71\xd0\x9d\x09\x4a\xe3\xae\xb3\xd4\x09\x58\x40\x4c\xb4\x30\x4d\x4c\x91\x0a\x98\x1c\x8c\x88\xa9\xe3\xd3\xe4\x6f\xc6\xd9\x2b\x26\x2c\x0b\x04\x5f\xa7\xc7\xac\x5e\x3f\x50\x2d\x68\xa8\x6d\x9e\xa2\xa8\x2c\xa3\xf1\xec\x63\xf6\x5c\xb8\xcf\xd1\xe7\x4a\xf8\xd4\xd1\x4f\xdb\x6a\x4e\xd9\x80\xd9\xa7\x33\x0e\x51\x74\x10\x25\x89\xdc\x48\x38\x70\xc5\x69\xc2\xe9\xa6\x3c\x5a\x78\xce\x16\xde\xc3\x05\xd0\x68\x27\xdc\x06\xb9\x9e\x2d\xf7\x4e\xb8\x0d\x52\xbb\x1e\xed\x69\x07\x80\xad\x1d\xb0\x13\xee\xee\x50\x61\x79\xf7\x5e\x58\xbe\x17\x96\xff\x63\x84\x65\x38\x75\xdf\x55\xa4\x88\xbf\x17\x59\x9a\x2f\xc6\xa6\xa0\xf9\x0b\x4b\x94\x57\x7c\x79\x9e\xd9\xb2\x2f\x4b\x93\x22\xa8\xab\x9c\xa0\x83\x35\xa4\x4b\x47\xb8\x04\x74\x7c\xaa\x14\x31\x79\x46\xc1\x43\x02\x37\xb8\x17\x8b\xe2\x58\x78\x82\xa3\x7c\x98\x17\x06\xe7\xba\xd0\x35\x9e\x60\x59\xc1\x45\x71\xec\x31\xe3\x43\x7c\xfc\xac\x50\xa9\x0c\xe8\x86\x6b\x30\x4e\x9d\x15\xc7\xb1\x4f\xd8\xf6\x0d\xbc\x60\xf1\x84\x05\x44\xe3\x88\x04\xd3\xae\xeb\x3f\x87\xf1\x76\xcd\xb7\x91\x9b\xaf\x93\x25\x7e\x8d\x6e\xba\x53\xa0\xee\x73\xd2\x98\x29\x98\x04\x6c\xa0\xd5\x8d\xf3\x3c\xe0\x22\x68\xe1\x0a\xc3\x8c\x7c\xd8\x2f\x2e\x25\x2a\x00\x8e\x1f\xdd\x31\x9d\x44\x65\x80\xe0\x75\x6c\xc5\xc3\x17\x5e\xe5\x09\xc0\x9c\xea\xe7\x82\x4a\x49\x9d\x15\xa9\xa8\x96\xca\x33\xa2\x3f\xbc\xd2\x81\x23\xf4\xd8\x05\xd6\xf9\x22\x1a\x90\xe2\x1f\x51\x42\xe2\xf7\xb8\x58\x64\x69\x81\x79\x53\xce\xa3\x1d\x67\x0c\xfe\xf6\x7a\x6c\x8d\x0d\x0e\xd3\x33\x6f\xad\x7b\x4e\xa5\xd7\x6e\xff\x2a\x2b\x67\x3e\x5f\x9c\xc1\xb2\x3d\x17\xde\x96\xfb\x32\x78\xe3\x03\xde\x07\x78\x75\xae\x27\x38\xf1\xaf\xd5\x54\xc8\x83\x0d\xf2\x8b\x12\x40\x59\x4a\x33\xc9\x06\xdf\x09\xb7\x41\x83\xc6\x57\x64\x27\xdc\x01\xeb\xb4\x56\xf1\x81\xef\x37\xfc\xfb\x0d\xff\xcf\xbb\xe1\xab\xfd\x5e\x8a\xe5\x77\xa4\x1b\x6b\xa9\xa4\xa2\x47\x9d\xdc\x02\x2b\xb8\xac\x3f\x84\xcc\x55\xf5\x68\x02\x4e\x7b\x69\xa1\x2b\xc0\xc4\x13\x0a\x0e\x7d\xa0\x1d\x42\x34\x30\xa9\x2a\x34\x82\x15\xfb\xf6\x4f\xa6\x57\xd2\x9f\xa5\xc0\x36\x6f\xbf\x6d\x64\x70\xcf\x15\xd8\x3b\x01\x25\xe5\x02\xb0\xb3\xbd\x46\xc2\x03\xac\x99\xea\x6d\x80\xfb\x08\xf5\x57\x6d\x3e\x0e\x1b\x91\x80\x97\xb3\xee\x73\xa2\x11\xf1\xe8\x3f\x34\x6f\xb1\xc8\x72\xcf\xca\x42\x03\xef\xef\xa3\xae\xd6\xa7\x2e\x7a\xf0\xc0\x70\xff\xaa\x1d\x98\x59\xb3\x86\x8f\xf0\xeb\xbe\xb5\x0d\xd7\x35\xe8\x71\x28\x8b\x7a\x90\x58\xb1\x5d\x43\x1e\xf3\x33\xeb\xd9\x19\xac\x8a\x28\x58\xe1\x69\x1a\x68\x8f\x9f\xda\x19\x42\x19\xa8\x44\xa3\xa6\xde\x11\x6a\xab\x16\xd2\xa3\x0c\x05\xc4\x5d\xcd\xb0\xa3\xb5\xf7\xf1\x44\x14\xc7\x82\x86\x0b\x75\x0c\xd7\x69\x43\xa4\x5d\xcb\x9a\x2a\xe9\x89\x91\x8a\xbf\xca\xda\x93\xbd\x3a\xae\xdf\x9c\x50\xb4\x77\x4b\xab\xcc\xbe\xae\xa2\x92\x6a\x1f\xd9\x9f\x4f\xb8\x9c\x09\x3d\xb3\xea\xa4\xf9\x6a\xbe\x51\x87\x3a\x71\xd4\x1c\x0a\x01\x4a\x47\xda\x62\x5e\x19\xb7\x68\x35\xa9\x8c\xdf\xdc\xdd\x8c\xda\xf5\x35\x2b\x6a\x04\xc3\xbb\x8b\xb9\x65\xbc\xd7\xd2\x27\x73\xce\xca\xd5\x8c\x92\xc7\x9a\x93\xe7\xaa\xae\x58\xc7\x2a\xa7\xf3\x20\x49\x6a\xa7\x0b\x80\xf8\x0d\xcf\xca\x04\xc6\x74\xa0\x0d\x1d\x5c\x9d\xda\x8c\x77\x47\xae\x52\xad\x8a\xda\xea\xc8\x4d\x3a\xda\x00\x1b\x3d\x31\xe9\x53\x5c\x16\xdc\x6c\x25\xb9\x44\x31\x5e\x24\xd9\x25\x8e\x85\x29\xdf\x28\xc9\xc6\x9f\xc7\xb3\x88\xa4\xb6\x8b\x58\xa8\xed\xc7\x2c\x17\x3d\xf2\xbc\x56\x16\x07\x56\x1f\x49\x8a\x75\x79\x2d\x55\x8b\x6b\x86\x8b\xcd\x63\x71\xab\xa1\x5e\x77\x55\xb4\xa8\x9b\x3a\x88\x96\x34\x85\xa5\x22\x5f\x08\xf5\x0a\xf1\x27\x1c\xfd\xee\x8f\x10\xdf\x78\x5f\xbc\xec\x82\xfc\xe1\x10\x9d\x47\x84\xe9\xc9\x41\xe4\x5a\x94\x4a\xf7\x2a\xae\xc8\xcc\x79\xe7\x4b\x41\x86\x9a\x55\x1d\xc3\x7d\xd3\x73\xeb\x3a\xa6\x1b\xdf\xba\xd1\xbe\xbd\x2b\x41\x7f\x37\x36\xf6\xcc\x63\xd3\x70\x88\x8a\x32\x5b\x30\x5d\x2d\x49\xa7\x28\x9a\xd0\xae\x7c\xb3\xc9\xe6\xaa\x40\xbd\x92\xcc\x71\xb6\x2c\xfb\xce\xd1\x91\x21\xe0\x07\xf4\xcd\xa6\xf7\xb0\xc8\x7a\x3f\xa0\xb5\xff\xcc\x2b\x57\x9e\xd8\xfb\xe8\xcb\xb5\xe7\x4c\x67\x23\x90\xb9\x35\xf1\x9e\x43\xe5\x8c\x78\x4f\x9b\xea\xe4\xa7\x1c\x8b\x4a\xc6\x04\x17\x25\x11\x5b\x19\x63\x4a\xd8\xe0\x64\x74\x44\x25\xe6\x65\x1a\xdb\x18\xe8\xfa\x0e\x9f\x38\xd1\x9c\xa7\xe8\x7f\x8e\x3b\xd3\x1b\xb7\x4a\x97\x9f\x5e\xb3\xf4\x40\xe0\x62\xcd\xa0\x9a\x29\x2e\x3f\xaa\xa6\xde\x33\x52\x53\x1c\x45\xeb\xc6\xab\xa8\x98\xe9\x44\x15\x08\xc2\xec\xfb\x8f\xf0\x64\xd2\xe3\x00\x7e\x6a\xf3\x16\xf2\x76\x10\x02\x9f\xf0\xba\x06\x63\x73\x01\x9a\x3d\x82\xe8\x28\xfe\xee\x88\xbf\x2a\x9f\xcf\x8f\xa5\xcf\xe7\xaa\x3f\x32\xe9\x99\x14\x77\x75\x85\xd6\xa1\xc5\xda\x62\x48\xb2\x6e\x0f\x6d\xea\x7f\x37\x59\x02\xfa\x5f\xcb\xe5\x60\x0f\x29\x8b\xb5\xe0\xb2\x3b\xb5\x33\x23\xfe\x86\x43\x79\xc1\x97\x64\x53\x8d\x6a\xe1\x58\x21\xd8\xf8\x7a\xb7\xdf\xd0\x3c\x32\x44\x35\xc9\x51\x2b\xa6\xba\x45\x65\xc3\x21\x62\x9b\x95\x10\x17\xa2\x34\x46\xfc\x66\x04\x45\xd3\x88\xa4\x7c\xe5\x9c\x63\x1e\x17\xac\xe1\xcf\x2f\x7b\xda\x1b\x60\x43\x0d\xb6\xac\xe3\x6c\xff\x0d\x43\x1a\x33\xa7\x4e\xfc\x36\x90\x6e\x09\x74\x77\x2c\xf0\x38\x4b\x63\x44\x19\x6e\x63\x25\x1a\xe9\x36\x13\x2b\x32\x38\x22\xe8\xc2\xda\x76\xd8\xeb\xf7\xe4\x8e\x3b\xa4\xfb\x7e\xd6\x44\x09\x7e\xa2\xd5\x38\x65\x51\x66\x39\x8e\xa5\x1f\x68\x26\x81\x80\xc6\x67\x1a\x15\x28\x9a\xd3\x0d\x69\xe0\xe5\xd7\xf6\x5f\x25\xff\xb6\xff\x3c\xee\xa9\xef\xa2\x8b\xf5\x3d\xbc\xae\xcc\xad\xe2\x18\x6e\x09\x1b\x52\xd3\x4e\xb6\x3d\x50\x68\x57\x0c\x82\xd0\x7f\x8c\xe8\x31\xfb\x52\x3e\xd7\xb7\xa4\x38\x0b\xac\xe1\xd0\x60\x57\xaa\x1f\x18\xe0\x54\x15\x8d\x88\x71\xb9\xc0\x5e\xfe\x60\x71\x7c\x87\xb4\x68\x44\xd0\x3e\x85\x14\x72\xd6\x43\xa6\x09\x6d\x1e\x93\x3a\x21\xa5\x28\xd2\x44\x53\x5e\x5c\xd4\x22\xc6\x96\xe2\x73\x99\x24\xc6\x94\x5e\x5e\xeb\xc4\x60\xe9\x46\xb6\x84\x31\x41\x94\xf4\x57\x2c\xba\x5d\x53\xd4\x96\x83\x0d\xc9\x82\xbb\x53\x10\x8a\xe2\xd8\x29\xed\x93\x94\x39\x84\x94\x96\xd5\xf1\x4f\x24\xc9\xb6\xd4\xc4\x43\xa1\xa1\x9a\x08\x8a\x52\xdf\xf5\x0b\x92\xf2\xb2\x3c\x17\xea\x14\xd5\x13\x33\x1b\xc8\xf9\xd4\x79\xd2\x70\xc8\x62\xac\x29\x83\x09\xa3\x52\x65\xf6\xf0\xe5\x7a\x8f\x02\x8b\x71\xaf\x9b\x6d\xf3\xa1\x6a\x15\xc3\xa9\x35\x87\x57\x30\x40\x9a\xfa\x03\x83\x84\x8c\x31\x5c\x1e\x28\xd3\x0b\x2b\x0c\x98\xcf\x0c\x04\x4c\x39\xaa\x8d\x3f\x90\x63\x00\x52\x0c\x16\xd9\xc2\x70\x32\x65\x76\x2f\x89\x8a\x92\x43\x3a\x55\xfb\xbb\xc3\xe3\x4b\xd0\x82\xe0\x91\x75\x5d\xbe\xf5\x80\x80\x94\x90\x6e\xf7\x49\xa1\xb0\xa1\x4b\x5a\xb8\xfb\x01\x8b\x53\xf0\x03\xda\x74\x63\xd3\xe7\x3a\x35\x1f\x88\xd5\xd9\x7c\xae\x17\x7f\xb7\x52\xf2\x69\x68\xb2\xd8\x1f\x57\x90\xfd\xff\xff\x9f\x34\x9b\xd3\xc7\xb5\x6e\xf6\x79\xb0\x88\x2e\xa3\x51\x82\x7d\xfd\x73\x25\x7c\x66\x0b\x55\xe0\x34\x56\xa1\x69\xd2\x2c\x7d\xc4\x2b\xd1\xf1\x61\x73\xfe\xeb\xaa\xb9\x07\x07\x5f\x94\xd9\xf9\xb5\xaa\x3d\xb1\x56\x02\x18\xb2\x56\xab\x98\x21\xb0\x63\xdb\xd8\x67\x15\xed\x99\xb3\x58\x79\xc9\xa7\x1f\x52\x8d\x63\xbd\x10\xe5\xa2\x38\xb5\x0f\xfe\x31\x46\xe7\x51\x21\x65\xc4\x35\x13\x57\x6c\x6d\xc3\x6d\xaa\x76\x2a\x51\x46\x56\xd6\x95\xea\x2c\x2a\x66\x3e\xa4\xd3\x5e\xe3\x3c\xaf\xba\x5c\xd4\x6f\x11\x7d\x57\x85\x75\x42\x0c\x95\x30\xe3\x98\xdd\x64\x69\x8c\x94\xf6\xc4\xdf\x56\xc5\x49\x0a\xed\x43\x99\x0a\x79\xaa\x52\xe8\x9b\x90\xbc\x28\xab\x65\xbe\x15\xc5\xb6\x0a\xa5\x86\x4f\x93\xe1\xbb\x51\x35\xbe\x9a\xbc\xdf\x41\xc8\x3d\x36\xf0\xa6\x79\xb6\x1a\x6b\x8b\xf2\x46\x54\xaf\x32\x74\x3f\x53\x93\x6a\x76\x06\xc4\xd5\x5f\x1c\xbb\x62\x5f\xa3\x47\xd6\x17\xcc\x46\x14\x92\xf8\xa7\x61\x53\x76\x63\x59\xca\x56\x84\x35\x29\x5c\x3d\xfb\x34\xaf\xe9\xda\x14\x6b\x26\xb2\xfe\xe1\xda\x70\x68\x6d\xc1\xc6\x9d\x8c\x8a\x7e\xa6\x69\x24\xad\xca\x7b\x6c\x63\x1e\x0e\x0d\x97\x9a\x95\x01\x68\xc7\x63\xf0\x8e\x99\xb1\xd8\x2d\x24\x9d\xd6\x88\x5b\xa6\x66\xda\x1c\x39\x9b\xc4\x6b\x97\x13\xe9\x12\x4e\x9d\x74\x83\xbe\x68\x82\x54\x5b\x21\x67\x82\xd2\x4c\xd5\x40\xd9\xdb\x22\x2a\x0a\x1c\x07\xb4\x0a\xe5\x30\x8b\x42\x14\xda\x92\x36\x79\x99\x24\x3c\x98\x01\x0b\x9d\x86\x85\xa3\xcf\x81\xa2\x69\x7f\x8a\x56\x16\xa2\x94\xd5\xbb\x52\x40\x96\x33\xcd\xbf\x1c\xc4\xaf\x80\xa8\x41\xc2\x4e\x40\x76\x29\x10\x05\x46\x78\x1c\x2d\x0b\x4c\x0f\xd7\x71\x96\x96\xe8\x3c\x4a\xc1\xcc\xa8\x58\x64\x24\x61\x17\xdc\x69\x89\xf3\x49\x34\x96\x8e\x72\x5b\x1c\xae\xdb\x1c\xa0\xed\x6d\xaa\x99\x1f\x22\xc7\xc7\xa6\x5c\xd3\xda\xda\xfc\x09\x97\xcc\x69\x2b\xdd\x1f\x03\x74\x3e\x23\xe3\x19\xd8\x01\xd0\xe5\x5d\x66\x7c\x1b\x43\x8b\x64\x59\x34\xdf\xa6\x72\x3e\xd0\x30\xbf\x8a\x79\xf8\x6d\x93\x1a\x64\xd8\xd5\x05\x55\x59\xac\x59\x80\xbc\x8d\xf0\x58\x2d\x38\x6a\x86\xc7\x37\x92\x63\xea\x64\x18\xf3\xd5\xc2\x80\x19\x97\xb7\x67\xbe\x9e\x83\x8c\xf7\x04\xdb\xe2\x46\xbc\x8a\x35\x39\xe7\x5b\xef\xc1\xb6\xe2\x55\x8a\xef\x88\xeb\xee\x7e\xca\xc6\x9b\xe1\xcf\x7d\x88\x82\x3c\xe7\x63\xaf\x25\x92\x45\xb7\x7b\xd2\xa2\xd9\x34\x7f\xe8\x84\xdf\x56\x19\x35\x4b\x23\x85\x4e\xb8\xbd\xe3\x5a\x39\xf3\x91\x77\xc2\x9d\xad\xeb\xd3\x60\xfb\xf1\xbd\x35\xd3\xbd\x35\xd3\x5f\xdb\x9a\x49\x33\x5f\xe6\x56\x8d\x77\x60\xbf\x5c\xe1\x14\x92\xdb\x4b\xb2\x37\x56\x47\x13\xc6\x55\xc3\x0a\x35\x8c\x26\xdd\xf1\xb3\x2b\x2f\xae\x05\xc2\x62\xb1\x4f\x80\xc7\x61\xf1\xda\x0f\x78\x7a\xa0\xb7\xc7\x9f\x71\x83\xf7\x3f\xd5\xd6\x2c\x2b\xf4\xbb\x23\xb7\xb9\xe7\x47\x6f\xdf\xbe\x7c\xfe\xf1\xf0\xe8\x2d\x7a\xf9\xfe\xfd\xd1\xfb\x10\x3d\x97\xca\xd3\x31\xab\x92\x1d\x9e\x63\x8c\xba\x1b\x88\xd6\x87\x36\xba\x03\x7f\x1f\x94\x5f\x97\xb6\xa3\x95\xef\xd3\xd9\x79\xbd\xa4\x84\x4a\x58\x65\xfe\x26\x84\x19\x6a\x88\x6c\x93\xda\xbe\xa9\xdc\x9a\xe3\xa2\x88\xa6\x18\xed\xa3\xf5\x75\xfe\x40\x8f\xee\xa0\xfc\xf7\x80\x05\x6c\x74\x52\x06\xa2\xd8\x53\xe4\x4d\x0e\x91\x9c\xa0\xbf\x7f\x38\x7a\x8b\xde\xbf\x7b\x4e\x01\x79\x97\x3c\x41\x0e\x79\xdf\x9c\x27\x58\x0a\x07\xbc\x6a\x73\xb4\x6a\x36\x3f\xb2\xcb\x5e\x7d\xbc\xf3\xa2\xed\x94\x7e\x3c\x7c\xf3\xf2\xe8\xf8\x63\x88\xf8\x95\x31\x25\x27\xda\xc9\x79\x81\x36\x50\x97\xfe\x17\x8d\x67\x74\x71\x76\x8d\x70\x12\xdc\x59\xe2\xb7\xf7\x1b\xc3\xfd\xc6\xf0\x9f\xb3\x31\xc0\x6b\xc5\x3f\xaa\x91\x6b\xfb\x47\xe0\xad\xde\x9e\xdf\xe1\x13\x70\xe1\xac\x87\x32\x00\x79\x10\xd2\x23\xa1\x14\x86\xc8\xcf\xdf\xa6\x42\x5b\x4a\x30\xb7\x6d\x78\xbf\xf6\xfb\xf1\x85\xb0\x84\xd5\xb4\xd6\x7a\x3e\xf3\x15\x8f\x6a\x9e\xf1\x16\x59\xda\x6f\x78\x7a\xae\x65\xa6\x59\x7a\x39\xcf\x96\xb2\x45\x99\x50\x71\x52\x12\x48\x9b\x62\x81\x2b\x16\x52\x3f\x9a\x83\x9b\x71\x27\x40\x0a\x4f\x93\x47\xa1\x67\x59\x96\x5c\x43\x74\xc3\x18\xfc\x73\xb3\x5d\x02\x33\xc8\x58\x9b\x1d\x78\x5e\x81\x63\xc3\xed\xb6\x38\x5d\x81\xbb\x70\xba\x2a\x79\xed\xc3\x35\x63\x9a\x74\x27\x53\x14\xc2\xf4\xb8\xc4\xea\xb5\x5d\xa4\x6b\xc8\x77\xef\x1f\x88\x47\x56\x20\x03\x5e\x13\x5c\x26\xf0\xdf\x15\xd6\xa2\xfe\xf2\xca\xdc\xb7\xf2\x82\x55\xc7\x36\xa3\xcf\x98\x39\xaf\x06\xf7\x3f\x16\xae\x63\xe5\xd7\xda\x1b\x9e\xc3\x5b\x41\x35\xea\xb4\xea\xea\xbc\xeb\x30\x4a\x74\x5d\x6b\xf7\x14\xbd\xb6\x1f\x1d\xac\x50\xcf\xd0\x4a\xee\x89\xbb\x66\x5c\x7a\xd1\x7a\x7a\x58\x69\x44\xc2\x07\xf8\x8d\x86\x53\x90\x69\x1a\x95\xcb\xdc\x1e\x8e\x9e\x5e\x35\x1e\x1d\xa6\x7a\x3c\x12\xaa\x6e\x40\xf0\xf0\xbf\x7d\xff\xf9\x03\x01\x41\xde\x9c\x23\x45\x69\x2c\xd5\x38\x65\x06\x31\x41\x27\x24\x8d\x12\x65\x34\x8c\xdc\xd7\x03\x3e\x9b\x4c\x7d\x61\x5b\x59\xbc\x7e\x03\x2b\x22\x0f\x9f\xe1\xfc\xb2\x9c\x31\xf5\xf0\x7c\x44\x80\x67\x64\x2c\x4a\x2b\x74\x8e\xb5\x18\xd7\xa2\xcb\xe3\x53\x83\x77\xc7\xf1\x09\x27\x57\xb7\xfc\xa5\x3d\xa2\xbb\xf7\xbc\xa1\xfc\x5c\x48\xc7\x16\x4d\x2e\x39\x84\x12\x71\xdd\xda\x7a\xdc\x7e\xf2\xca\xd9\xc3\x50\xee\x95\x8f\xf9\xa3\x14\xe4\xde\xeb\xbb\xfa\x43\x3e\x4f\x1f\x45\xc7\x6e\xcb\xd3\xb5\x40\x79\xb5\x0c\x1d\x1c\x0c\xf3\x60\xb6\xbc\xfc\x09\x81\xa0\x2e\xd6\xd5\xfb\x99\x1b\xde\x9e\xd2\x8d\x4a\x4e\x97\x49\x52\xf1\x42\x44\xa9\xf1\x90\x71\xfd\x66\x34\x60\x6a\x61\xa1\xde\xaa\xc8\x68\x90\x69\x8d\xea\xac\xe6\x8e\x9d\xcf\x82\xf3\xc6\xa4\xc7\xf6\xb1\x00\x9d\xd9\xd7\xd5\x7d\x5f\x77\x5b\xd7\x06\x7d\x6f\xa0\x3c\x93\x58\xc6\x59\x3a\x8e\xca\x9e\x41\x05\xfd\x6a\x47\x30\x95\xec\x8f\x7b\x81\xa9\x66\x7f\xf6\xb6\x8b\xab\x38\x5d\xcc\x14\xfe\x2e\x2f\xe3\xdc\x81\x1b\xe0\xc0\x59\x81\xd5\x12\xcb\x66\x1f\x3c\x00\xcd\x83\xd9\x8b\xfa\xfd\xba\xc6\x7b\x0d\x20\xe1\x0e\xfd\xd7\x44\xf9\xd4\x5a\x66\x4a\x90\x7c\x6a\x94\x0c\xf5\x2f\xee\xdb\x66\x4b\xf3\x25\xc2\x07\xc8\x6f\x3d\x64\xbd\xf6\x93\x27\x36\x9b\xe8\x8b\x94\xd7\xf4\xfa\xb6\xfb\x7b\x74\x89\xfe\x92\x91\xb4\xd7\xe9\xb8\x95\xcb\xd7\x65\x8c\xde\x18\xa2\xf4\x4b\x05\x90\x12\x7b\x74\xbd\xf7\x03\xbd\x47\xfd\x3d\xa4\xc6\x9c\x66\xe5\xa1\xd1\x59\x89\x43\x8f\xcb\x1e\x05\xdc\xb2\x71\xb0\xff\xef\x07\x56\x2b\xbc\x46\x77\x5b\xd1\x78\x78\xb6\x2c\x17\xcb\xf2\x75\x36\x55\xcc\x3b\x56\x45\x85\xb2\x88\x1f\x5f\x98\xbb\x16\x4d\x4a\x33\xc1\x14\xef\x86\x71\xd9\xde\x94\x18\x0c\xbb\x60\x32\xb8\x6b\x8e\xe3\xe5\x18\x6b\x13\x16\x8d\xc7\x01\xe2\x2e\x1d\x75\xae\x12\x8d\xc7\x27\x3c\x99\x71\x48\x8a\x18\xfe\x2d\x68\xfd\xa9\x39\x6f\x83\x62\x46\x26\x65\xaf\x8f\x42\x07\xab\x22\xcb\x51\x62\x45\xe3\xb1\xd0\x5a\x31\xd3\x69\x46\xdf\x38\xc1\x25\x16\xe3\x50\xbe\x86\xcc\x74\x46\x5a\x37\x60\x1c\xda\xd5\x11\x7f\xa5\xc1\x17\x38\xdd\xf8\x99\x54\x57\xe9\xa6\xe0\xae\xa4\x24\xa3\xe1\x7a\x51\xc8\xe3\x06\xc1\x96\x85\xfe\xe8\x8e\x8d\xb6\x9b\x1d\x1b\xd5\x15\xdf\xaa\xb6\x6f\x33\x2b\x40\x86\x3c\x68\x78\x52\xd0\xee\x92\xd5\x2d\xad\xe5\x41\xc9\x11\x31\xff\x18\xae\x94\x2a\x09\x59\xb7\xa2\x6f\xf1\x3e\xd0\x7a\x20\xe6\x7d\x1c\x58\x4b\x8a\x5f\xcb\x6f\x13\x05\x35\x4f\xb1\x55\xec\x4f\xd8\xf5\x41\x4b\x27\x1a\xc0\xa9\x41\xba\x3e\x00\xdd\x15\x94\xa2\x05\x2f\xe8\x89\xe4\xf7\xac\xed\xd3\xca\x01\x18\xd6\x0a\xde\xbb\x58\x03\x97\x9a\x73\xa9\xba\xab\xd8\x26\x97\x53\x37\xf4\x32\xf5\xa4\x8d\x36\xfe\xb6\xfe\x22\x87\x7e\x3d\xe5\x1b\x46\x83\x1e\x5d\x60\x7d\xec\x0c\x3d\x6c\xc6\xda\x70\x88\x3e\x1e\xbd\x38\x0a\x51\x8e\x99\x21\x54\x80\x8a\x8c\x9b\xac\xc8\x1b\x2e\x65\x03\x13\x31\xad\xd7\x80\x96\x83\x60\xdc\x29\x1e\xe3\xa2\x88\xf2\x4b\xba\x58\x20\xfe\x6c\x41\xc9\xad\x0b\x4e\x7f\xc1\xe5\x32\x3a\xcf\xf2\xcf\x4c\xd0\x9b\x2f\x93\x92\x2c\x12\x2d\x78\x81\x19\x2e\xc4\xef\x29\x68\xf8\x10\x79\x5f\x2e\x7d\x23\xec\xaa\x59\x1d\xa6\xf9\x80\x68\xde\xb0\xdd\x54\x8d\xe1\x98\xed\x1a\xe6\x21\x45\x96\x1a\x08\x1c\xf9\x7c\xc1\xac\xd3\xce\x9d\xb8\xb0\xa7\xbe\x23\x44\x15\xac\xc5\x4b\x91\x63\x57\x68\xf6\x93\xbb\x46\xf2\xd5\xd4\x60\x7e\xe8\xad\xa7\xd2\x70\x59\xd5\xcf\x09\xde\x1e\x93\x03\xe0\x39\x7d\xb3\x1c\x1f\x36\x58\x8e\x64\x7a\xdc\x94\xc6\xec\xa2\xc7\xe2\x92\x17\x2b\x70\x69\x05\x47\xf1\xb9\x8b\xaa\x3d\x8b\xd5\x4f\x37\xc1\x35\xe3\x55\x30\x9e\x21\x57\xd1\x0b\x52\x71\x3d\x2e\x57\x1e\xb6\x2c\x78\x07\x03\x47\x9a\xbd\x26\xbe\x18\x18\xec\x48\x7d\xec\x21\x01\x20\xb8\x10\xfc\xbf\x27\x52\x25\xcb\x61\x3f\x64\xba\xc6\x68\xc4\x4f\x53\x88\xc4\x17\xfc\xa5\xb4\xcb\xcd\x19\x1a\x94\x93\x9f\x0a\xfe\x5c\xc1\x91\x3b\xe1\x0e\x38\x03\xd2\x3d\x6f\x53\xc6\xfc\xdd\xfd\x35\xe9\xfd\x35\xe9\x5f\xfc\x9a\x94\x5d\x91\xf2\xd7\xb3\xff\x11\x21\xe5\xee\xd4\xeb\x36\x1c\x02\x1e\xa2\xe7\x59\x7a\x86\x29\x2b\x8a\x78\xc0\x5c\x38\x04\xc3\x59\x00\xcd\xf0\x85\x0c\xc2\x4d\x09\x38\x4a\x8a\x0c\x45\x49\x92\x9d\x17\x70\x4c\x62\xba\xba\x62\xb0\x46\x2b\x12\x82\xff\x1b\x72\x81\xe3\x6b\x96\xb5\xe6\xde\x71\xac\xc9\xb8\xf0\xc2\x09\xb2\x64\x54\x4c\xf3\x27\x4f\x9b\x3d\x53\x3b\x8a\xae\xae\x44\x38\x63\x95\xd1\x95\xea\xd4\x6e\xdf\xd6\x04\xb0\x83\x1c\x17\x91\x98\x8e\x96\xf5\xa1\x27\x54\x8c\x46\x43\x4c\x09\x71\x34\x01\xad\x73\x1f\x6a\xdf\x74\xea\x04\x48\xce\xf7\xf5\xc7\xa1\xc6\xfd\x91\x88\x1b\x24\xdb\x81\x23\x17\x15\x35\x29\xa7\x15\x17\x41\xb6\x05\x6a\x26\x55\xfd\xfc\xb0\x15\x40\x2c\x7f\x9c\x93\x09\xb8\xc8\xc8\xf1\x38\xa2\x1c\x47\x8b\xf6\xf2\xe0\x01\x4a\xa2\x5f\x2f\x51\x92\x45\x31\x8a\x2f\xd3\x68\x4e\xc6\x28\x4b\x71\x01\xad\xf1\x09\x51\x0d\xf1\x50\xc8\x99\x54\x12\x00\x94\xb0\x6b\x17\x8d\x3b\x50\x74\xb6\xa6\xb8\x3c\x92\x27\x64\xaf\x57\x72\x47\x45\xc0\x71\x2d\x40\xaa\x6f\x36\x0c\x6d\x7e\xe5\xf5\x0a\x93\x85\x87\x5c\xc8\x5e\xe6\x98\x2b\x02\x03\xb8\x74\x1b\x33\x2a\x66\x87\xd8\x19\xbe\xd0\xeb\x52\x7a\x4d\x2b\x41\x73\xba\xd8\x00\x6a\xe8\x24\x99\x4a\xd2\x35\x77\xb2\x74\xf0\x0c\xaa\x8f\x9e\xb2\x8e\x42\x15\x9c\xe8\xfb\x28\x14\xf4\xcf\xc1\x1c\x75\x37\x5b\x33\xb2\x09\xd6\x8d\xd0\xea\x96\xf2\x29\x42\x49\x4e\xe5\xd2\xaf\x40\x2b\xab\x97\x53\xe9\x91\x88\xdd\x2b\x32\x23\x3d\x72\xaf\xa8\x15\xae\x88\xc2\x95\x6e\x8e\x06\xb2\x5c\x5f\xef\xc5\x4d\x6a\xe2\xa5\xfa\x42\x80\x13\xca\x8b\x83\x38\x66\x06\xfa\x52\xa7\x14\xa5\x31\x2a\x70\x59\xa0\xe5\x02\x32\xb8\x7c\x0e\x8b\x88\x94\x38\xa7\xdc\x34\x3b\xe3\xe2\x07\xf7\x91\x39\x58\x5b\xd3\x8c\xf4\x5f\x67\xd3\xe2\xa0\xfc\x50\x46\x79\xb9\x66\x2b\xde\x0a\x9c\x4c\x64\x22\x25\x04\x52\x66\xa9\xe4\x65\x66\x61\x23\xea\x14\x4e\x26\x8e\x5f\x18\xf1\xca\x6b\x8a\x4b\xa6\xd1\xa1\x85\xad\xa7\x5e\x70\xd0\x56\xa3\x2b\xa0\x57\x62\x89\xad\x5b\x6b\x8c\xb6\x32\xf0\x2d\x34\xc8\x98\xe2\xb2\x67\x3d\x3a\xe1\xf6\x7d\x8e\xb8\x3f\x1c\xa2\x38\x4b\xbb\xfc\x99\x22\xed\x23\xc7\x16\x18\x13\xc2\xed\xaf\x48\x14\xb6\x38\xe0\x5d\x61\x30\x18\xa0\x5f\x96\xcc\xb9\x2c\x6d\x93\x32\x21\xe7\xe0\x58\xf1\x32\xaf\xe6\x55\xde\xb5\xfd\x04\xd3\x5a\x62\x72\x18\xfe\xc3\x16\xcb\xf4\x9e\xd0\x98\x79\x63\xd3\x3b\x41\xf6\x7a\xc4\x34\x86\x34\xfa\xd7\xec\xdb\xf3\xeb\x51\xec\x22\x4b\x12\x46\x3e\x7e\x6a\xe5\xb4\xa9\xc0\x6c\xba\x94\x5c\x1b\x14\x97\xe9\x1b\x69\x9c\x6a\x10\x4b\x56\x41\x2e\x7c\x46\x33\x67\x4e\x85\xe5\x01\x25\x3d\x31\x56\xdf\x24\xf8\xde\xed\xf8\x68\x22\x6b\x7d\xa4\x6d\x4b\x1d\x37\xa3\x0c\x65\xbc\x0b\x43\x53\xea\xdb\xa7\x56\x82\xaa\x24\x14\x85\x5c\xd2\xb9\x15\x7a\x6e\x47\xa4\x95\x07\x63\xe8\x93\xed\xe0\x98\x32\x9e\x77\x59\x92\x50\x3e\xa3\x7a\xc2\x68\x30\x64\x45\x88\x88\x5f\x0f\x67\xaf\x01\xa5\x38\x18\x9a\x62\xfe\x0b\x6e\x70\x7e\xc2\x30\x05\xe4\x78\x18\x9f\x06\xe2\xa2\xc6\x48\x0e\x14\x31\xf2\x1c\xdd\x35\x0e\xd3\x94\x02\xfd\xd2\xdd\x52\xc4\xc0\x73\x48\xdc\xb5\xd2\x93\x37\x1b\x72\xa1\x79\x14\xe4\x01\x3f\x50\x3c\xcf\x31\x8c\x06\xec\x97\x9f\x7b\xde\xd8\x01\x9b\x63\x4a\x5c\xed\xd6\xd1\xc0\x84\xa6\xe4\x5a\x45\x5b\x54\xa9\xee\xa9\xd4\x77\xf8\xf5\x4a\x66\x67\x34\x11\x03\x55\xfa\x1f\xaf\x34\x4e\x54\x62\x99\x92\x04\xad\x67\xbb\x00\xe7\x20\xc0\x4c\xd0\x20\xc5\x6c\xbb\xef\x94\xe4\xaa\xe0\x16\x26\x32\x83\x6f\xb3\xcf\xab\xf2\x15\xab\x73\xb2\xf4\xcb\x16\xf9\xbb\xb2\xdf\x83\x14\x9f\xeb\x77\x2d\xce\x3b\x74\xc1\x18\x49\x6c\xb8\x58\xf3\x33\xc4\x86\xa5\xde\x1b\x8f\x3c\xae\xab\xc6\xa3\x46\xde\x87\xa4\xef\x28\x2f\xb1\x3a\xe5\xbd\xfa\x51\x63\xe5\xd1\xf9\x8a\x5d\xd7\x6f\xfa\x53\xfe\x1c\x83\x32\x9c\xca\xdc\x0b\x9c\xc6\x60\x93\x25\xe7\x23\x2a\x40\x21\x90\x16\x94\x8c\xa4\xfb\x0f\x55\x51\x36\x01\x60\x5a\x88\x0a\x25\x7d\xa6\x04\x90\xad\x2f\xd3\xa8\x28\xc8\x34\xc5\xf1\xc0\xed\xa3\x3d\xf9\x3e\x96\xe9\x43\xa4\x14\x81\xc6\xa3\x06\x5c\x7a\x9b\xd1\xad\x9c\xb4\x91\x28\x1b\x58\x94\xe8\xc2\x5b\x94\xe4\x38\x8a\x2f\xd5\x7b\x66\x25\xc7\x15\xb7\x27\x0a\x53\xce\x14\xc2\x65\xd3\xb8\xc8\xa4\x67\xb5\x26\xdd\x7e\x6d\xba\x4e\x98\xd4\x22\x62\x4c\xd6\xe7\x09\x90\x0a\xb9\x65\xc6\xc7\x46\xe6\x73\x1c\x93\xa8\xc4\xc9\xa5\xdd\x2c\x3f\xae\xab\x7b\x5f\xc3\xbf\x6a\x8d\xc9\x11\xf4\x17\xaa\xef\x55\x78\x22\xf0\x39\x2a\xd2\x8f\x4e\x8c\x2f\xd3\xdd\x81\x0d\x46\xbb\x73\x3c\x77\x02\x33\xd8\x7b\xad\xc9\x86\x98\x2d\x9a\xd6\x0f\xa1\x36\x30\xf8\x98\x3e\x1a\x6b\x9e\xf8\xb5\x9e\x3b\x10\x0d\xd7\xda\xdd\xe5\x75\xdb\x81\xe8\xdb\x62\xf3\x78\x9c\x8d\x3d\x5b\x88\x7d\xdd\x1c\x48\x03\x2b\x86\xa7\xc7\xf3\xec\x4c\xa8\xde\x50\x54\x5c\xa6\x63\x79\x36\xf1\xc9\x2d\x3e\x16\xbb\x4c\xe1\x6d\xad\x81\x00\x4d\x04\xb0\xb0\xe5\xf0\x2e\xdd\x78\x7b\x95\x9a\x0d\xb9\xdc\xc1\xe8\xd4\x8a\xa6\xed\x7b\x5c\xef\x6c\xfc\x5e\xbb\x08\x59\xd2\x96\x99\xad\xcd\xaf\xc2\xf4\x6f\x38\x44\x87\x13\xc5\x19\x49\x21\x1f\xa3\x5d\x62\xee\x9e\x03\x91\x12\x29\xc7\x4c\xaa\xdc\xf9\x0c\x83\xb5\x00\x1f\x7d\x1f\x31\xa6\x5a\x20\x52\x9a\x6c\xd5\xbb\xa7\x3a\xc4\x2e\x97\x99\x6f\xf7\xf0\xa1\x9f\xd7\x68\x4f\xa8\xbe\x75\x42\x50\x0c\x0f\x7f\xfb\x8a\xfe\x5b\x2c\x71\x39\xc7\xb6\x9d\x59\x92\x4d\xab\xda\x45\x16\x63\xaa\x11\xfd\xa1\x96\x90\xee\x09\x15\x1e\xd8\xfc\x31\x2a\x4c\x10\x47\x3e\xb7\x07\xd6\x9e\x8e\x1c\x37\x44\x5c\x4e\x3e\x7c\xc1\x12\x42\x4e\x63\xbd\xfe\x80\xed\xc8\xe3\x48\xf8\xa8\x03\xb7\x1b\x38\x46\x74\x75\xcf\xf2\x2c\xcd\x96\x85\x74\x58\xc7\x2f\xb0\xe9\x6e\x6f\x7b\xaa\x61\xd5\x70\x89\xb4\xeb\xb5\x04\x05\xa7\x03\x99\x32\x25\x6b\x43\x40\xae\xa1\x17\xad\xa1\x79\x0e\x6f\x31\x6f\xd7\x0d\xfc\xd8\xb9\xca\x63\xb8\x75\xc2\x7d\xd5\x5c\xe4\x5d\x9f\x06\x3b\x9b\xf7\x57\x75\xf7\x57\x75\x7f\xed\xab\x3a\xf5\xa0\x51\x53\xfe\xde\xe4\x55\x23\x07\x5e\xe1\x8e\xcd\x17\xe0\xab\xf5\x43\xc8\x74\x42\xa6\x5e\x38\x96\x25\x00\x0f\x59\xe4\x7e\xed\x42\x8e\x8c\xa2\xd4\x13\x8c\x03\xd4\xbb\x2c\x9a\x10\x33\xdd\x65\xd7\x6c\x23\x32\xe5\x4f\xeb\x2d\xfb\x3a\x06\xf4\x8c\x4c\x2d\xf5\xb8\x6e\x67\xc7\x54\xc0\x57\x0c\xe2\x4a\xc2\x5e\x9b\x6e\x8c\x54\xba\x6e\x20\x0a\x8a\xbf\x8a\x36\x0c\x39\x88\xf5\xce\xfb\x58\xaa\xcc\x64\x59\x01\xb6\x27\xb5\x32\xa4\x78\x97\x63\x7e\x41\xa7\xe9\xf9\x8d\xba\x47\x2a\xdd\x6a\x60\xa4\x97\xa0\x47\x07\xee\xe2\x1c\x5d\x5d\xb9\x79\xfc\x34\xea\xcf\xc4\x51\x9e\x10\x5a\x54\xeb\x5a\xba\x58\x96\x2f\xf0\x24\x5a\x26\xde\x2b\x88\xa6\x3e\xd2\x3d\xd8\x6e\x47\x5e\x46\x7a\x43\x74\x50\x92\x19\xc4\x5a\x8b\x1e\x6f\x44\xd5\x37\x22\x7a\x17\xac\x51\xfc\x16\xdd\xb7\x9f\x1d\x31\x91\x84\xd6\x52\x31\xc7\x46\xa3\x9e\x0a\xb5\x6c\x0f\x1e\x04\x6d\xbd\xc2\x17\x9e\x91\xf3\x55\xc5\x06\x5b\x68\xe6\x7a\xd9\x04\x45\x86\xb3\xb8\x28\x8d\xc5\xdd\x60\x01\x57\x17\xec\xc6\x9a\xae\xbb\x57\x2f\xff\x69\x2d\x37\xa8\x83\x4a\xc2\xde\x85\x26\x94\xeb\x86\x1f\x55\xc7\x1e\x5b\x5c\xde\x0a\xf5\xbb\x5b\xa7\xf7\x02\xf5\x8b\x71\xfb\x09\x17\x68\xda\x25\x24\x7c\x5e\x5d\x59\x34\x74\x30\x06\xdf\xfa\x9a\x2b\x2c\x1d\xde\xe3\x83\x49\x54\x0b\x7d\xe2\x8e\x89\xfc\x97\x77\xa6\xe4\xa3\x57\x5d\x66\x3c\x1a\x30\x29\xd1\x9c\x4c\x67\x4c\x54\x94\x1e\x6a\xb9\x22\xca\x69\xb9\xcc\x1a\xdb\x2d\x33\xb3\xd5\x93\xee\x34\x2a\xde\xe5\x64\x8c\xbb\x01\xa2\xbf\xe9\x7f\x30\x7d\xf4\x47\x9a\xa5\x63\xec\x7b\x42\xf7\x19\x5f\xd6\x3c\xa2\xfb\x8c\x2f\xdb\x3e\xa3\x83\x9a\x1c\x1c\xb2\x1a\xf6\xb5\x9b\xfe\x17\x78\x4c\xe6\x51\xd2\xd3\x01\x2a\xee\x73\xe5\x85\xf7\xd7\x26\x62\xcd\xb9\xe2\x5d\xd3\xb2\xaf\xea\xbb\x27\xe9\x9b\x52\xed\x3d\xbd\xfe\x96\xf4\xca\x85\x18\x87\x60\xe1\x02\x53\x04\x78\xe1\xd4\xea\x15\x6d\x5a\xd3\xe9\x85\x29\xce\xf0\xf4\x35\x43\x86\x69\xa4\xcc\xf2\xa2\xff\x45\xea\xee\x2e\x06\xfa\xf6\xb7\x2e\xce\xcf\x4a\x67\x65\x02\x48\xbf\x0b\x99\xc0\x9f\x09\x20\x5f\x13\xd0\x74\x0d\x17\xf0\x68\xc9\x5f\xbd\x03\xe5\x6d\xc3\x86\x12\xea\xb9\x8b\x01\x90\x94\xbf\x10\x64\x29\xc8\x69\x54\xf8\xe1\xa6\x51\x61\x40\x01\xf9\x6a\xa0\x4a\xb4\xd3\xf2\x55\x09\x61\x56\xe5\x05\xd7\xdf\x71\x8a\xb3\xf3\xc5\xca\xa4\x24\x42\x89\xdc\x84\xa4\x78\x54\x93\x5a\xca\x92\x41\x76\x56\x21\x2f\xbb\x62\xeb\xda\x51\x8f\x8e\xa2\xa2\xa1\x34\xd0\x9b\x0f\xca\x9d\x33\x0f\x94\xa2\x3c\x91\xd9\x82\xfc\x2a\x41\xab\x9b\xac\x20\x44\x19\xb4\x63\x39\x5f\x26\x51\x49\xce\xf0\x4f\x51\x71\x5c\xc0\x73\xa9\xaa\xaa\x1c\x58\xab\xae\x69\x63\x0d\x53\x59\x4e\x0c\xde\xbc\xfb\x17\x70\x49\x36\xb5\x4d\xcf\x54\x86\x16\x72\xc4\x51\x26\x81\x46\xc8\xab\x4a\xf2\x3c\xba\xa4\xb0\x4d\x7a\x23\xde\x52\xab\x05\x00\xb3\xdb\x9e\xe4\x41\xea\xae\xa5\x72\xa8\xb0\x05\x8d\x9b\x35\xe9\x06\x23\x50\x83\xb4\x18\x19\x0e\x91\x74\x40\x03\xae\xd8\xf8\xe9\x15\x21\xd6\x14\x9d\x9f\xd7\x64\x4e\x4a\xcf\x14\x9a\x00\x1c\x57\x32\xb1\x62\xde\x8d\x7c\xa3\x4c\x41\x7e\xf5\x31\x41\x95\x69\x40\x97\x64\x8e\x8b\x32\x9a\x2f\x2a\x8b\x48\x08\xb5\xae\x58\x46\x5a\xb5\x72\x8d\xec\xaa\x6a\xe5\xd1\x58\xeb\x4c\x4c\x26\x13\x32\x5e\x26\xf0\x70\xc0\xe5\xa1\x36\x90\x39\x90\xac\x8c\x92\x17\x6d\x2a\xb0\x20\x75\x21\xc9\x5c\x33\x1c\x5c\x2d\x73\x73\xe5\xb8\xd9\xae\x08\x42\x4a\x3c\xef\xdb\x4f\x86\x1c\x73\x35\x80\x72\x6f\x1e\x8d\xf5\xe5\xdb\xcc\x59\xc1\xa6\x85\x36\x62\x47\xeb\x16\xcb\x2c\xc9\xa6\xde\xf5\xa4\xaf\x6d\xdf\x6a\x4a\xb2\xa9\xe6\xfa\xc4\x59\x52\x50\xaf\xb1\xac\xf4\x0a\xf5\x45\xa5\xe9\xab\xc9\x84\x7e\x35\xec\x11\x36\x84\x4b\x6c\x16\x84\xa2\x61\x9a\xd1\x62\x5f\xf0\x82\xf9\x9b\xa9\xd8\x0f\x78\x5b\x49\x36\xad\x6b\x43\x66\xfb\xeb\x16\xd9\x96\x3c\x0a\xea\xf9\xe6\xb3\xd3\xf9\x8c\x14\x94\x65\x2e\xb2\xa2\xbc\xc1\xe1\xe9\x5d\x56\xd4\xcb\x0c\x6e\x24\x95\x5a\xd6\xea\x56\xaa\xd3\x00\xed\xa4\xce\x57\xe9\xf7\x60\x11\x5d\x82\x4d\xf7\xbe\xa1\x08\xd1\xb3\x38\xb6\x21\xa9\x2c\x13\xaf\x84\x2f\x32\x75\xd8\xf3\x2c\xff\xfc\x31\x7b\x97\x67\x67\xb8\xba\x8c\x06\xa4\x97\x5d\xe4\x24\xcb\x89\xc6\x6c\x9c\x82\x02\x42\xf3\x26\x3e\xd1\xe3\xc7\x18\xc6\xab\x8c\xeb\xb0\x4e\x32\x27\x0f\x3a\xbb\xd1\xd2\xd1\xbe\xf1\xf5\x14\x9d\x68\x9f\xa7\x28\x94\x57\xd3\xd7\xaa\x55\xa6\x65\x65\x0a\xd7\x24\xc9\xce\xc1\xa4\x5d\x9c\x70\xeb\xaa\xaf\x37\xf5\x66\x11\xd0\x28\x31\xa1\x2c\x4d\x2e\x99\x0f\xf8\x52\x5a\x9c\x6b\xb4\xca\x8a\x7a\x1f\x15\x08\x93\x70\x14\xda\x0f\x06\xea\x8c\xc1\x69\x1f\x5b\xb1\x35\xa9\xf1\x07\xfa\xe7\x86\x81\x5e\x46\xd7\x44\xe9\x7e\xb2\x36\x35\xc7\xf5\x84\xcd\xe9\x1a\xf0\x8b\x2f\x16\x24\xbf\xf4\xac\x78\x2d\x57\x27\xb7\x82\xf9\xad\xf0\x42\xd3\xbc\xaa\x25\x60\x81\x7a\x16\x00\x50\xb6\x4f\xcc\xb0\x20\xfa\x7b\xbe\x55\xf9\x3e\x3a\x17\x24\xc3\x53\xbc\x60\x5a\xf5\x07\xc5\x98\x10\x7b\xf9\x8a\x32\xfa\x46\xfc\xf7\x82\x23\x4e\xc2\xa9\xa0\x0b\x6a\x55\xa8\x06\xc0\xb1\x2b\x44\x3e\xf2\x31\x87\xe1\x70\x95\x15\x01\x6b\x53\x5f\x8d\x95\x8b\x51\x2d\xb7\x5b\xac\x24\x4b\xd1\xcb\x50\xd4\x8e\xfe\x25\x53\xb5\x75\x33\xbe\x08\x09\xba\xe9\x06\x61\x17\x35\x29\x3e\x87\x3b\x9b\x9e\x19\x12\x17\x94\xd9\xa3\x28\x1d\x90\xe2\x1f\x51\x42\xe2\x1e\xf8\xb7\xe7\x29\x2f\x48\x8e\xc7\x65\xcf\xa7\xc9\xe6\x1e\x8d\x00\x90\xd7\xd8\xeb\x3b\x6a\x72\x5d\x06\x52\x61\x47\x44\x0f\x3c\xd5\x1a\xce\xb3\x3c\x15\xb5\xa8\x82\xf7\xcc\xac\x89\xdf\xc8\x5a\x76\x01\xdc\xc1\xb1\x80\xed\x8a\xd0\xbe\x6a\xa1\x7f\xb8\x4c\xc7\x24\xf5\x0b\x32\xdc\xa3\xb0\xd8\xc6\xb8\x3b\x15\x30\x14\x23\xe9\x14\x4e\x15\xde\xc3\x9c\x0b\x66\x3a\xa5\xe1\xfe\x61\x1a\x2a\xd0\xa1\xcc\xf2\x33\x32\x9d\xe1\xa2\xa9\xbc\x0e\xa5\xd1\x02\xcf\xfd\x9c\x66\xe7\xe9\x87\x32\x2a\xed\xc8\xeb\x76\x6e\x75\x03\x7a\x15\x7b\x76\x0d\x8b\x65\x92\xe0\xb8\xa9\x0a\x1d\xaa\xe2\x7c\xa9\xfc\xd4\x54\x78\x01\x6f\xba\xf2\x0a\x1b\x21\x02\x55\x4f\x4d\x05\x0d\x25\x8d\xdb\x90\xd0\x93\xa6\xc1\xfa\x8e\x01\x61\x75\x96\x56\xd2\xe6\x0d\xa1\x3f\x59\x2b\x61\xec\x64\xa1\x27\x8d\xc1\x56\x5d\x98\x86\x95\x39\x7a\x39\xff\x80\xaa\xf3\x2a\xca\xda\x1a\x28\x4f\x15\x36\x88\xd1\x7b\xe3\x9c\x1f\x7a\x53\x75\x78\xfd\x00\x13\x7a\xd2\x74\x58\x0b\x8d\x9e\x44\x1d\xda\xe6\x2a\x61\x45\x3a\xe3\x46\x86\x5d\x0d\xbb\x3a\xe8\x84\x5b\x4f\xaa\xbc\x9a\x50\x96\xdc\x09\x77\x76\xae\x4f\x83\x9d\xad\x7b\x33\x9b\x7b\x33\x9b\xff\x18\x33\x1b\x4e\xe9\x77\x11\x52\x62\x35\x9f\xe0\x2d\x6d\x6b\xee\xd0\x75\x78\x7b\x67\xdf\x51\x92\x0c\xad\xd0\x73\xf0\x60\x91\x0f\x44\xc5\xbc\x72\x5c\x80\x0b\xb3\x5e\x37\x46\x4f\x8d\xeb\x6f\x5f\x90\x9e\x4f\x6c\xeb\xe2\xae\xa9\xf5\xf0\x94\xab\xbb\x8d\x56\x95\x72\xde\xaf\xd7\xca\x92\x6e\x57\x2d\x44\xb6\x8a\xe0\x10\x06\x75\x8a\x6f\x1d\x46\x44\xaf\xe4\x20\xfc\x53\x87\xb8\x13\xb7\xe5\x94\xfb\xdb\x93\x61\x78\xb4\x83\xfb\xdc\xe7\xca\xc1\x9c\x76\x0e\xc8\xa7\x85\x6e\xf5\x72\x83\xa0\xac\x42\x22\x57\x01\xac\xe0\x25\x3a\x70\x72\xf6\xec\x23\x9f\x16\xcc\x37\xf9\x3a\x17\xcd\xda\x75\x58\x17\xb5\x6a\x3b\xad\x77\xef\x07\x87\x94\x44\x8e\x1e\x8e\x8b\x3f\x02\x73\x07\xe7\x1f\x9b\xfd\x2a\xbb\x46\x08\xec\x29\x3c\xb4\x44\x44\x93\xdf\x44\x71\xa0\x85\x9b\x7e\x2d\x84\xaf\xe9\x08\x3c\x7b\xc7\xc0\x3c\x41\xb7\x9c\x25\xac\xbc\xa6\x56\xf8\x50\x8c\x12\xd9\xaa\x32\x7c\x18\xd6\x4d\x99\x6c\xbf\x72\xa2\x9c\x30\x6d\xab\x4f\xdf\xaa\xb3\x67\x46\x57\xab\x08\xdf\xc6\x8e\x7c\x86\x69\x83\xc7\x3f\xb3\x11\x4e\x6d\x1f\x55\xf8\x5e\xf6\xb9\xee\xe5\xa6\xda\xda\x88\x8c\x38\x6d\x35\xc6\x04\x15\xc1\x05\x04\x76\x6f\xe6\x44\xdd\x5b\xbc\x76\x6a\x6f\xe4\x4a\x9d\xbb\x7e\xdd\x0c\xd0\x13\x71\x58\xae\x69\x62\x99\x2e\xa2\xf1\xe7\x23\xa6\xa6\x33\xcc\x65\x20\x49\x5f\xeb\xeb\x66\x92\xea\x82\xe9\x28\x43\x54\xc5\x7e\x48\xea\xda\x47\xdb\xe8\xa9\x48\x14\xde\x69\x91\x10\xab\xd5\x53\x55\xe9\x4f\xb6\xca\x39\xad\xbe\xab\x04\xbc\xb8\x39\xa3\xfc\x68\xaa\xbb\xd5\x94\x31\x8a\x4e\x36\x4f\x51\xe8\x73\x9e\xfa\x1c\xa2\x61\x46\x5a\x00\x52\x81\x2c\x3b\xc4\x69\x94\x24\xfa\xfa\x1d\x0c\x06\x62\x09\x3f\xb7\xcb\x1a\x4c\x03\xe9\x7e\x1a\x4a\x08\xf3\x79\xc8\xa4\x31\x88\x74\x28\x40\xa9\xdc\x1a\xc9\x1a\x02\x33\x92\xb1\x48\x66\x6e\x7a\xe0\xb9\x8d\x90\x61\x23\xe3\x41\x44\x94\xc6\xe6\xab\x7e\x01\xc6\x42\x81\x32\x41\x93\xd6\xc1\x82\x3b\x51\x70\x8e\x36\x2f\xed\xf2\x59\x85\x50\x86\x4d\x54\x0b\xbd\xaa\x0a\x17\xb9\x4a\x2c\x48\xd7\x28\x29\xea\xa3\x2f\x62\xd3\xb3\xcc\x8f\xa4\x8c\xa0\x47\x4c\x57\xde\x2c\x8d\x7d\xb8\xa7\x71\x01\xf0\xc8\x69\x6e\x77\x7a\x11\x7d\xbf\xb1\x8b\x29\x7d\x27\xf3\xa2\x29\x18\xb1\x80\x53\x17\x9a\xeb\xbe\xd7\x67\x4a\x85\x25\x19\x1f\x2e\x67\x0c\x09\xbc\xea\xc0\xe8\x9a\xfb\xd6\x04\x4a\xe9\x4b\xb8\x67\xac\x07\xcd\x13\xbd\xf3\x3a\xac\x4d\x83\x81\xeb\x72\xc1\xe5\x01\x9a\xc3\x05\x61\x52\x6c\xbc\xf4\x0d\xd8\x35\x9b\x15\xbc\x9e\x75\x1a\xc7\x8e\x63\xdb\x32\xbf\xb4\x9e\xca\x68\xa0\xf0\x3a\xa6\x7a\xbc\xc8\x78\xce\x33\x86\xf7\x94\x3d\xc7\x69\x02\xa3\xf8\x7d\x84\xbd\xee\x1a\xec\xce\x8b\xd6\x35\xed\x6f\xed\x46\xd1\x46\x90\xb7\xb7\x0d\xb3\x48\xe3\xae\x60\xb5\xf0\xa7\x5a\x6a\x8d\x6b\x46\x90\x14\x07\x54\xb1\xfa\x41\x8a\x34\x84\x7b\xf3\x29\xe7\xaa\x71\xed\xd5\x7b\x5f\xc7\xa8\xd8\xbb\x5c\x8d\xb0\x3c\xbe\x68\xe1\xe6\x25\xc7\xf5\x9a\xb5\xcc\x2a\xc0\xdb\xfb\x40\xc6\x45\x49\xe6\x51\x89\x7f\x8a\x40\x1f\xd3\x44\x55\x1a\x78\x13\x45\xe9\x35\xdf\x05\x35\x7d\x7d\xea\x68\x37\x43\xda\xb8\x9a\x66\xc7\x03\x5a\x35\x33\xef\x45\x33\x58\x04\x78\x61\xf1\x97\xb9\x6a\x85\xcb\x07\xfe\x48\xcb\xee\xce\x6a\x57\xd3\x34\x57\x4d\xf1\x98\x6f\x36\x4f\xad\x10\x2f\x2e\xbc\xf8\xca\xac\x09\x5e\xec\x95\x9a\x6f\x11\x27\x4a\x2f\x2a\xf0\xac\x91\x7d\x2d\xc2\x7e\xdb\xa0\x51\xb2\xfe\x1b\xc5\x8d\x92\x85\x56\x1d\xe4\xd7\x0c\x22\x65\xc6\xc6\xcf\x17\x63\xe1\x8e\xa5\x60\x07\xe3\x26\x46\xc4\xa1\xab\x2f\xed\x6b\xc6\xc5\xcb\xfe\xb1\xb9\x12\x32\x3c\xe7\x0b\x30\x5d\x4c\x31\xfc\xc0\xeb\x73\xe2\x7a\x2e\xb2\x54\x5c\x4f\x51\x17\x97\xb3\x4f\xb4\xc7\x5d\x14\xb2\x0f\x6b\x27\xe9\x06\x8e\xf0\x12\x2a\xbf\x41\xea\xae\x5c\xf8\x3a\xe2\xc3\x39\xd5\xfc\xe9\x41\xc7\x85\x0b\x3c\xc6\x20\x1b\x89\x41\x78\xbc\xaf\xda\x7e\x64\x20\x89\xfa\xad\xc7\x13\xf3\x41\x9f\xe0\xd2\x10\x74\xd6\x4d\xec\x28\x63\x05\xd8\xe6\x4b\x5d\x86\x12\xcf\xd1\x55\x5a\xd5\x56\x61\xa1\x73\x10\x2d\x16\xc9\x25\x77\x8e\xd1\x8a\xb0\xfa\xb6\x95\x0f\xdb\x02\xac\x66\x68\xe2\x8d\xea\x6e\x98\x07\x1e\x1a\x41\x31\x1e\x15\x1d\xe1\xd6\x61\x11\x3c\x13\xf6\xb5\x22\x23\x88\x74\xb5\xe2\x75\xef\x20\x95\xe0\xfc\xb0\xa9\x30\x5c\x05\xe8\x4a\xcd\xde\xc9\xaf\x2a\x6e\x8a\x48\x6c\x24\x2a\xa9\xb2\x98\xda\xad\x85\x57\x0b\xfa\xf9\xa7\x0c\x0b\x21\xca\x02\x81\x93\x7c\xbc\x4c\xa2\x7c\x7d\x7d\x7d\xbd\x3e\x18\x84\xa0\xa0\xbb\x8a\x07\xe1\xb8\x29\xd8\xbe\xbf\x3f\xbd\xbf\x3f\xfd\x6b\xdf\x9f\xf2\xcb\x53\x0a\x2b\x22\x74\xf8\xfd\x8a\xff\x6e\x1e\xc3\xed\xbb\xd9\xce\xb2\x60\x6e\x9d\xc7\x65\x87\x1b\xc6\x81\x3a\xc5\xba\x55\x65\x69\x22\xe0\xc9\x79\x96\x7f\x8e\x72\x4a\xd9\x74\x0f\xa3\x35\xe8\x23\xa6\xf4\x17\x93\xc9\x04\xe7\x38\x2d\x11\x4e\xcf\x0a\x5a\x86\xd6\xfc\xcf\x37\xaf\x5f\x95\xe5\x82\x3b\x25\x04\xfe\xc4\x03\x93\x90\x69\x9a\xd1\xa5\x9b\x90\x14\x43\x13\xa3\x3c\x3b\x2f\x70\xbe\x06\x92\x01\x73\x02\x76\x4e\xd2\x38\x3b\x07\x0d\x87\xe6\xb4\x1b\x3d\x78\xc0\x73\x06\x66\xf5\x82\xcb\x9a\xa9\x68\xdf\x0f\x5d\xd9\x99\xe1\x10\xa5\x59\x8c\xd7\x0c\x17\x3a\x4e\x9d\x12\x55\x17\xf3\x84\xe2\x82\x6f\x86\xdd\x7e\xdb\x66\xae\x19\xee\xff\xf9\xea\xfd\xb6\x51\xdd\x2c\xdf\xee\xf6\x6b\x30\xc5\xa4\x0d\xda\xc2\x3b\x81\x7e\xf7\xde\x1a\x64\x2e\x7a\x1c\x00\x2f\x72\xcc\x25\x2c\xed\xa5\xbc\xa5\x36\xca\xeb\x62\xc2\x2c\x2b\xca\x40\xc4\xd9\x37\x2e\xa7\x69\x0e\xda\x47\xf0\xdf\xd5\x15\xea\xf2\xf5\x91\x64\xe3\x28\xa1\x89\xe1\x93\x6f\x76\xbf\xe9\x6a\x1a\x4c\x11\xac\x7f\x5f\x86\xed\xbf\xba\x42\x9b\x8d\x42\xd3\x22\xc7\x0b\x08\x9e\x83\xcf\x2d\xb4\x5b\x32\x13\x07\x7c\xaf\x9d\x61\xb4\xb0\xd1\x38\x4a\xaf\x21\x28\x27\x8b\x1b\xcd\xe6\x4d\x61\x8a\x7b\x20\xd3\x0e\x7a\x66\x5b\x86\xd3\x0b\x1d\x5b\x9a\xbc\x65\x76\xc0\xbc\xe3\xa3\xd5\xeb\xa2\x16\xef\x81\xa6\x27\x31\x40\x10\x52\xc2\x15\x0c\xfc\xd5\xfb\x6d\x15\xa9\x4e\x48\x5a\x1a\x46\x35\x04\x73\x91\xc1\x70\xf8\x64\xd5\x66\x0c\xad\x67\x1b\x03\xb2\xca\xb3\x05\x4e\x7b\xdd\x77\x47\x1f\x3e\x76\x03\x35\xe3\x01\xc3\x94\xbc\xc5\x61\xb0\xca\xd1\xe8\x2b\x1c\xc5\x38\xef\x75\xa9\xcc\x89\xd3\xf2\x11\x3d\xbc\x76\x83\x2e\x15\xa6\xc9\x18\xb6\xc1\xe1\x2f\x85\xd2\xe4\xc9\x6b\x20\x8e\x8d\x06\x5a\x60\x9e\xdb\x2f\xd3\xb1\x76\x52\xb5\xd5\xb3\xbe\x0b\xdb\x85\x76\xed\xeb\x0f\xa7\x59\x37\xaf\x85\x1d\x5b\x49\x28\xa8\xdc\xf9\x14\x53\x61\x92\x02\x8f\xcf\xc8\x27\xdb\x54\x9b\x2b\x14\xa6\x71\x0f\x8c\xb1\x99\xf7\x7c\x32\xb9\x94\xed\x48\x53\x60\xd0\x93\xbb\x2e\x42\x99\x46\x95\xb1\xe8\xc1\x21\x33\xc3\x7d\x9e\xa5\x29\xe6\x76\xd3\x62\xf2\xdc\xbb\x06\x79\x85\x27\xba\x21\x1c\x75\x7f\xc4\x17\x65\x45\x7f\x79\x09\xcd\x70\x9c\xdb\xee\x5a\xbd\x6c\xea\xe1\x7b\xde\x54\xcf\xd7\x76\xa3\x81\x6a\xa5\x6a\x07\x68\x24\x6a\x20\x92\x03\xb9\xdc\x6b\x28\x85\x67\xfd\x28\xef\x00\xa5\x32\xa2\xcc\xc9\x74\x0a\xc1\xeb\xb3\x14\x51\xea\x00\xc1\x41\xfa\xa5\xa3\xc8\x68\x22\x28\xe8\x81\x8f\xaa\xcc\xb0\x89\xed\xe8\x0b\x82\x8f\xee\x59\xeb\x37\x05\x3f\xa2\x45\x19\x95\x78\x3c\x8b\x52\xc3\x2f\x77\xcf\xbe\x16\x52\x73\x10\xc5\x97\x60\x23\x0c\xb7\xb1\xbb\x74\x77\xb5\xd9\xcd\xba\x2f\xfa\x61\x0b\x6a\xb2\xc1\xc5\xed\x8e\x16\x65\x43\xd2\x8b\x73\xb5\xd4\x8a\xf6\xc4\x9f\x97\x06\xc5\x9f\xbc\x54\x5a\x99\x1a\x65\xf5\x66\x67\xed\x7b\x28\xa7\x4b\xa6\x8f\x6c\x35\x41\x8a\x7f\x7b\xe6\xc5\xac\xb5\x18\xa8\x05\xfd\x91\x15\xeb\xe9\x4c\x5f\xf2\x88\xaf\xc6\x64\xec\xfe\xd4\xf1\x19\xc7\x75\x3d\x5d\xa9\xea\xce\x3b\xb9\xa4\x2b\x88\xbd\xa0\x83\xe5\x4a\xd7\x49\xc5\x6a\x25\x05\x6f\x01\x9b\xec\x5b\xee\xe9\x42\x4f\x69\xef\xed\xf4\x4c\x90\x76\x4b\x34\x89\x48\x82\xe3\x01\x3a\xa2\x67\xaf\x73\x42\xcf\x13\x11\xc4\x5d\xa9\x5e\x9f\x5a\x9b\xbe\xb9\x31\x71\x2b\x75\x13\x3d\xeb\xd5\x6a\x1c\xa2\xef\xe4\x5f\x60\xe4\xd1\x2d\x30\x5f\x8c\x43\xd4\xdd\x1e\x6c\x76\xcd\x3c\xa1\x5d\xec\xa6\xb8\xfc\x94\x90\xa2\xc4\x29\x49\xa7\x16\x90\xd4\x10\x9e\x2a\x22\xf3\xdc\x39\xab\x18\xe4\xbe\x05\x21\xec\xb6\x28\x3a\xf4\x09\x73\x34\x04\x3a\x9a\xf6\x44\x94\x31\x46\x06\x9d\x70\xfb\x71\xd0\xa1\x52\x6a\x27\x7c\x42\x7f\x19\xe2\x6f\x27\xdc\xfa\x96\x9e\xfc\x77\xee\x4f\xfe\xf7\x27\xff\xbf\xf8\xc9\x5f\x99\x4e\xc3\x33\xae\x3b\x32\x9b\x96\x4f\x41\xf4\x43\xe1\x88\x4c\x99\x33\x80\xc1\x2f\xec\x48\xce\xae\x3e\xe2\xd7\x78\x62\x1e\x3b\x64\xe4\xad\x4b\xed\xe9\x91\xb1\x53\x33\x08\xb6\xfa\xcf\x67\xb4\xf7\x3d\xd3\x26\xeb\x7b\x56\x18\x3d\x44\xdb\xee\xdb\x25\x30\xf2\xeb\xa2\x0d\x29\x99\x21\xdb\x0b\x9b\x47\x64\x7b\xc7\x0f\x74\x51\x8a\x0e\x9f\x1d\xbc\xe5\x93\x1c\xa3\xef\xbe\x45\xe3\x6c\xbe\x58\x72\xc7\xff\xa3\x4b\x34\xcf\xce\x48\x3a\xd5\x42\xda\xec\xa2\xf1\x2c\xca\x61\xdf\x60\x97\xb1\x31\xb3\x9e\x12\x26\xc1\x02\x3a\xc1\xcc\x30\xbc\xcc\x68\x83\x0c\x57\x05\xea\x1d\xa0\x7d\xb4\xb5\x19\xa0\x67\xf4\xff\xad\x00\x0d\x06\x83\x00\xfd\x0f\xda\x47\x3b\xdf\xf4\xe9\xc1\x06\x15\x0b\x3c\x26\x13\xc2\x16\xd2\xe1\x87\xa3\xad\x9d\xc7\x5b\x8f\x6d\xab\x32\x52\x64\x90\xce\xc7\xe1\x7a\x52\xbc\x66\xaf\x04\x69\x47\xe8\x00\xcd\xdb\x34\xfd\x32\x99\x4b\x71\xb1\x00\xe3\x8f\xbd\xcd\xfa\xcd\x18\xdb\xa3\x28\xd5\xe7\x91\x8e\xa8\x7b\xd0\x1d\x50\xb4\x3c\xcf\x62\x7c\x50\xf6\x36\x35\x45\x35\x1d\x5b\xf7\x7f\x9c\x6c\xc6\x00\xd9\x4b\x46\x20\xd6\x32\x3b\x5e\x2c\x70\xfe\x3c\x2a\x94\xf6\x5a\xcb\x2e\x96\xa3\xa2\xcc\x7b\xbb\x7d\xf1\x46\x91\x27\x6c\x06\xbb\xd6\x25\x19\xcb\x5d\x24\xa4\xec\x75\xbb\x7d\xf3\xf9\x66\xda\x37\x0d\xaa\xc6\x59\x4c\x07\x97\xfa\x3a\x8f\x84\x2b\x70\x0a\xf3\xc3\x3e\x3a\xa0\x72\x28\x7c\x7c\xbf\x8f\xfe\xa7\xef\x78\xba\xf6\xcc\x2c\x9f\x58\x03\x52\x3a\x52\x8c\x31\x7a\x84\x0e\xd0\x06\xda\xda\xd4\xc4\x34\x9f\xf7\x67\x11\x09\xce\x91\xe6\xfa\x83\x5f\x32\x92\xd2\x61\xda\xc6\x89\xe3\x25\x78\x99\x84\x29\x7e\x73\xf4\x82\x12\xf6\xd6\xa6\x60\x4a\xdc\xa8\x0f\x28\xdf\x43\x71\xdf\x6e\x3e\xde\xb5\x09\x6e\x9e\xc5\xdf\x7d\xbb\xb5\x59\x45\x68\x26\x7d\x29\xdf\x9d\x8c\x9a\x78\xe1\x5a\x2a\xca\xf1\x3c\x22\x29\x53\xfd\xd0\x3c\x25\x6b\x70\x4f\x18\x26\x7b\xe0\xc0\xca\x1a\x79\xbb\x6f\xf9\xf8\x00\x66\x25\xc0\xa4\x91\xeb\x77\x86\x84\xa2\x9a\x04\x41\xfe\x30\x2d\x99\xfb\x90\x00\x6d\x6d\xf6\xd1\xff\x4b\xb1\xb6\xe1\xd4\xc2\x3c\x88\xb0\x86\xbd\x47\x44\x59\x97\x2c\xa9\xea\x33\xe6\xa9\xf9\xad\x07\x33\x2c\x87\x75\xa0\x87\xe2\x87\x84\x71\x96\xe7\x34\x85\xb1\x4f\x31\x5f\xfe\xc9\x19\xea\x1e\x5e\xfd\x93\xc0\x8d\x9f\xd5\x92\x73\xbb\xea\xc4\xfc\x6b\xea\x27\x86\x50\x1b\xcb\xb9\x78\x01\x61\x11\x15\x85\x39\x90\x39\x4e\xdf\x23\x2d\x4b\x88\xdc\x74\x08\xd7\x92\xad\xe9\x0a\x31\x9a\x33\xd0\x6a\x6c\x7a\x45\x1d\x15\xcf\xc4\x2b\x6a\xe5\x6b\x46\xc4\x8e\x43\x5b\x8f\x35\x16\x36\x8a\x0a\xbc\xf3\x18\xed\x43\x99\x41\x99\x71\x07\x30\x3b\x8f\x8d\x5b\xff\x38\x06\x51\x9d\xef\x81\x3d\x56\x28\x40\x5b\xdf\x98\x7a\x26\xd9\xcf\x67\xa3\x28\xed\xb1\x62\x26\xf3\xb3\x16\x33\x77\xd4\xa0\x2d\xdc\x67\x74\xe8\x65\x66\xec\x5e\x74\xfa\x10\xb8\x1d\xcc\x2f\xc5\x8a\x66\xca\x2e\x30\xd1\x7d\xc7\x3c\x9e\xa7\x59\xc9\x85\xb2\xef\xc9\x0f\x9d\x29\x48\x24\xcc\x01\xc8\x44\x21\xb5\x98\x45\x4c\x5a\x83\xfd\xed\x62\x9c\x2c\x0b\x72\x26\xe3\xa7\x91\x11\x49\x48\x29\x05\x9c\x51\x94\x7e\x1e\x8e\xf2\x28\x1d\xcf\x50\x81\xf3\x33\x32\x16\x1b\x60\xc4\xbc\x20\x76\xbe\x1f\x92\x1f\x06\x36\x0d\x49\x67\xe9\x85\xd8\x85\x26\x38\xa7\xdb\x50\x94\x4c\xb3\x9c\x94\xb3\x39\x8a\x71\x31\xce\xc9\x88\xb1\x25\x2e\xff\xe0\x74\x70\x4e\x3e\x93\x05\x8e\x49\x04\x42\x10\xfd\x1a\x1e\xa6\x25\xce\xd3\x88\x3d\x88\xf8\xf4\x2c\x4a\x3f\x7f\xe2\x2e\x18\x3f\xb1\x79\xfd\x7f\x7e\xe2\x23\x4d\xa7\x9f\xe8\x10\x3f\x41\x2c\x98\x4f\x31\x99\x12\xe7\x81\x86\x98\x1a\x1f\x45\x8e\xc4\x9e\x2a\x66\x40\x78\xd1\x28\x33\xcf\x36\xdb\x82\x56\x9f\xd9\x2b\x72\x64\xb1\x45\x3e\xa3\xcf\xd9\x3e\xd5\xfd\xe7\xcb\xee\xde\x9a\x97\x67\x72\x1e\xdb\xb3\x76\xee\x9e\x5e\xc1\x06\xea\x6e\x82\xa8\x04\xad\xe8\x16\x2e\x14\x1d\x2f\x28\x36\xd0\x3e\xea\x31\x71\xaa\xf7\xdd\x13\xf4\x48\x35\xd1\x17\x2f\x05\x1e\x6d\x5b\xfb\xad\xf4\x43\x60\x36\xa5\xd5\xc9\x1b\x6c\x50\x9a\x71\x26\xa2\xe1\x0a\x08\x9b\x85\x73\x25\x69\x51\x92\x72\x59\x0a\x47\xa2\x24\xc6\x69\x49\x37\x2d\xdb\xd9\x34\xab\xe5\x30\x8d\xc1\xd3\x41\xf5\xcb\x99\x22\x10\xb2\xac\x7c\x3a\x03\x21\x81\x3a\x5a\x4b\x1d\x68\xaa\xa3\xda\xea\xac\xc2\x8b\xcc\x9e\x54\x05\x1c\xad\xe4\x0c\xdd\x97\x1f\x5f\xd1\x79\x10\x0f\x5a\x74\x0c\x68\xa9\xb2\x6f\x7d\x8b\x5f\x67\x75\xfc\x5a\x84\x42\x62\xc8\xe5\xb1\x52\x49\x81\x98\xf7\x04\x8d\x8f\x3b\x72\x27\xf8\x94\xa8\x94\x37\xe5\x5e\xe4\x51\x92\x08\xe5\x08\x29\x55\x4b\x52\xe8\x3c\xd4\x3c\x56\xd4\xca\x09\x44\xf7\x7c\x41\x18\x59\xe9\xc2\x9f\x72\x7b\xd1\xa8\xc9\x97\x58\x80\xae\x03\xfb\xcc\xf3\xfa\x31\x2b\x4f\xe4\xde\x51\x05\x28\xf3\x68\x78\x60\x6c\xba\x66\xc7\x1d\xa5\x45\x09\xc3\xff\xfd\xe7\xcb\x93\xcd\x47\xdf\x9d\x7e\xd9\xbe\xee\xbd\xfc\xf8\x8a\xfe\x3e\x78\xf4\x3f\xa7\x5f\xb6\x76\xae\xaf\xe4\xc7\xce\x66\xb0\xb3\x75\xdd\xff\xaf\xe1\xa0\x04\x05\xac\xdc\xc0\xfb\xe8\xc1\x03\x29\xe5\x54\x31\x06\x0d\x9c\x79\xf4\xd9\x5a\x11\x61\xdc\x55\x1c\x9c\xfe\xbd\x68\x7b\xa1\x96\xe0\xdd\xe0\xed\x85\xbb\x92\x2c\xc4\xa9\x41\xe9\xef\x79\x76\x76\x21\xea\xb2\x3f\xef\x9b\x1b\x0e\x7b\x82\x48\x5a\x31\x70\x83\xfb\xdc\xcd\xd0\xbd\x6c\xa4\xd5\xe0\xb7\x9b\xaf\x37\xa7\xb8\xe4\x22\x25\x1d\x69\xb1\x9c\x53\xc0\xe3\x82\x1f\x1f\xe6\x59\xfc\xe8\xbb\x6f\x1f\x6d\x6d\xca\x6c\x38\xe3\x42\xef\xc6\x59\x82\x7a\x87\x1f\x8e\x86\x87\x2f\x9f\x23\x7a\x6e\x08\xb7\x37\x37\x77\xfa\x36\x4f\xd6\xaa\x75\x4f\xa1\x5a\xae\x33\x70\x91\xd7\x72\xd8\xfc\x4c\xb8\x1d\xa0\xed\x76\xe6\xa9\x3a\x53\x35\xb6\x14\x84\xa7\x03\xf4\xcf\xf7\x2f\x7f\x72\x5c\xab\xc9\x02\xfe\xd1\x54\xd6\xe8\x4e\xaa\x06\xd9\x34\x3c\x45\x00\x3d\xf0\xbb\xe5\x0c\xf9\xdb\x00\xed\xf6\x51\x88\xba\xdd\x56\xe3\x1e\x27\x04\xde\x8e\xc9\x0e\x82\xf2\x89\xa4\xf6\xf8\x28\x16\x7e\x3a\xf8\xc7\xd1\x8f\xff\x3a\x7a\xff\xdf\xf6\xac\x42\x1d\x15\x73\x6a\xd7\xef\x9d\x5c\x06\x74\xeb\xb1\x6f\x6d\xad\x3e\x72\xbe\x9a\xfc\xe7\x12\xf7\xe0\xe1\x0e\xcd\xa9\xc0\x19\x5e\xe4\x39\x87\xe8\x0f\x24\xf9\xe0\x7c\x2e\x99\x8c\x43\x87\x3b\xe0\x5d\xed\x10\x5b\x79\x94\x11\xe7\x0f\x79\x4a\x31\x4e\xa8\xec\x8c\x62\x9e\x67\xb6\x1e\xf7\x03\xb4\xbd\x29\x2f\x61\x0c\x29\x4f\xa0\xd7\x1a\xa4\x28\xdc\x6e\x81\x56\xf8\xf5\x39\x84\x2c\xa6\xd4\xd7\xf5\x8a\x9d\xd0\xfc\xbc\x3e\x0d\x76\x76\xef\xd5\xf8\xf7\x6a\xfc\xbf\xb8\x1a\x9f\xab\xf0\x17\xe3\x7a\xfb\xbd\xbb\xb5\xb8\x6b\xe9\xf2\xa4\xc1\x30\x8f\xe9\x99\x16\x63\xaf\x21\xd7\x22\x2a\x67\x01\x4a\xb1\x61\xf0\xfd\x09\x34\x17\xce\x5b\x53\x71\xf5\xad\x87\x30\x15\xbe\x08\x98\xf9\x41\x04\x8e\x49\xe8\x7f\x2c\x55\x65\x8d\xe5\x7d\x30\x70\xc5\x52\x24\xf4\xbe\x50\xe8\x50\x95\x97\xce\xf9\xac\x62\x83\x2c\xed\x75\x61\x54\x5d\x3d\xe4\x5f\xdf\x30\x99\x2e\x32\xca\xc4\xd8\xf3\xc1\xc3\x77\xcf\x91\xba\x85\x66\x8f\x0a\xbb\x01\xd2\x03\x59\x7f\x62\x6c\x90\xdf\x95\xf7\x6c\xf7\x80\xde\x1e\xa4\xb1\xde\xbe\xd6\x7c\x65\x65\x68\x4d\x3e\x2b\x78\x7d\xf8\xe1\xe3\xcb\xb7\xb0\x82\x9e\x1f\xbd\x7d\xfb\xf2\xf9\xc7\xc3\xa3\xb7\xe8\xfd\xcb\x0f\xef\x8e\xde\x7e\x78\xf9\xa1\xb2\xd5\x38\x2a\x23\xbd\x59\xfa\xad\x6f\x4e\xc3\x87\xdc\x0a\x70\x1e\x5d\x8c\xb3\xf9\x22\xc1\x17\xa4\xbc\x0c\xd1\x63\xa0\x2c\xab\x87\xa0\x0b\x95\x76\x0d\xb4\x2a\xb5\xdf\xf4\x3d\xd1\x1f\xb8\xdd\xc2\x97\x35\xc7\x52\x83\xc4\x7e\x33\x0d\x1e\xc6\x16\xf8\x4b\x8c\xce\x67\x64\x3c\x43\x73\x1e\xd5\x9f\x85\x9c\xa7\x9b\x10\x65\x68\xb1\x79\x37\xee\x3a\x5b\x87\xa6\xfd\xf1\x5c\xe1\x3a\xca\xe9\x2d\x18\x2d\xf8\xa3\x2d\x92\x49\xef\x93\x9f\x90\x4f\xe0\x39\x1c\x89\x4f\x5d\xdf\xd1\xb2\x30\x1d\x2b\x07\xdb\x73\xa0\x9c\x50\xe8\x55\x11\x23\xa1\x1a\xde\x77\xbb\xa2\x6b\x07\x8b\x13\x92\x63\xc3\x09\x80\x8d\xae\xaa\xf1\xd0\xa1\x78\x5a\xaf\x01\x57\xe1\x2b\x5d\xbb\x19\xfa\x17\xe3\x04\x97\xb8\xae\x06\x7b\x30\x36\x6e\xf4\x87\xd7\x3f\xd3\x5d\x0b\x08\x91\x13\x04\xab\x0f\x94\x3b\xcc\x52\x2b\x65\xce\x5e\x50\xc6\x9c\xcf\x92\x72\xb0\xb6\x26\x84\x41\x93\x84\xd7\x6c\xb5\x07\x3c\xc2\xa4\xc2\x9f\xe2\x79\x9a\x78\x64\x16\xd6\x0d\x39\xf4\x55\x65\xb3\xc1\xc0\x92\xd7\xfe\xc1\x7c\x3d\x2b\x97\xa5\x62\x89\xbf\x78\xf9\xe8\xf9\xab\xe3\xb7\xff\xfd\xf2\xbd\xac\x27\xc6\xe3\xd9\x32\xfd\x8c\x63\xfe\x90\x84\x3d\x12\xe5\x7f\x83\x1c\x2f\x92\x68\x8c\x7b\xc3\x7f\x5f\x9f\xfc\x3b\xfd\x77\x7e\xfa\xf4\xdf\x5f\x86\xd3\xa0\x7b\x7d\xf5\xe8\xd1\xd5\x97\x6e\x1f\x9c\xad\x7e\xf1\xc2\xff\xfb\x54\x94\x38\xe1\x65\x4e\x69\xa1\x13\x51\xea\xf4\xc4\x5f\xce\x2e\x65\x14\xaa\x28\xa3\xda\xd2\x5a\x92\x0d\x69\x65\xf8\x35\x1f\xcd\xee\x0a\x4e\x6a\x60\xc0\x5d\xb3\x80\x78\x8d\xbf\x0c\x87\x70\x07\x8a\xb9\x07\x0c\x70\xae\x01\x15\xac\x39\xa4\x4f\xf3\x9e\xd3\x2c\x73\xe5\x72\x57\x33\x16\x0c\xda\x40\xec\xc9\xab\x21\xaa\xcb\x3b\x6b\x8b\x93\xb9\xc6\x66\x3e\x43\x33\xe8\xbb\x56\xca\x30\xa9\x59\x73\x17\x9f\xea\xcc\xbe\xdd\x19\x64\x44\xc1\xe6\x46\x60\xe0\x5e\x2c\x1d\xe3\x04\x5c\x8c\x8b\x77\x9b\x46\x99\x71\x82\xa3\x5c\x58\x7f\x59\xad\xf0\x64\x6b\x41\xfb\x81\xc0\x3d\x43\x29\x2a\xf2\xed\x71\x66\x79\x7b\xaf\xd3\xff\x6a\x2d\x3b\x39\xce\x74\xf8\xeb\x00\x6d\x6d\x6e\x6e\xa2\x87\xec\x72\xc6\x73\xd7\xea\xf5\xf5\x00\x4f\xf5\x00\x3b\x02\x5f\x94\x83\x14\x98\xd3\x0b\x8b\x20\xc1\x9f\xf2\xad\x8e\x2a\x77\xc6\x2c\x12\x81\xd0\x28\xdc\xae\xd3\xe9\x30\x63\x11\x2c\xec\xb1\x69\x0a\x6b\x69\xeb\x75\x70\xee\xef\x87\xf2\xc8\x9f\xf8\x16\x1a\xc5\x71\xa1\xc7\xc3\xe5\x56\x0e\xae\x34\xc6\xd4\xc3\xc1\x1a\xdb\x70\xc5\xc1\x80\x9f\xb5\x09\x73\xe0\xcd\xb9\xde\x5c\x04\xf7\x36\xb8\xef\x61\xcc\x4a\x45\x79\x4e\xce\xb0\xce\x70\xa3\x58\xce\x9e\x68\xaf\x86\xc3\x7a\xa0\x0d\xff\xdd\x75\x16\xad\x84\x5d\xd8\x5d\xf2\xad\x16\x5d\x5d\x89\xaf\x93\xcd\x53\xb9\x65\xc2\x15\x36\xeb\x9b\x82\xe6\x09\x66\x09\x96\xa8\x4b\x74\xde\xcd\x0b\xed\xcb\xde\xd4\x49\xbc\x14\x74\x20\x1b\x16\x75\x8b\x5d\x4d\xac\x23\x7d\xa5\xb2\xa8\xd9\xdc\x2c\x85\x89\xe5\x70\xfa\x02\x8d\x3b\xdd\xdf\x63\x0d\xcd\x9c\x88\x6b\x50\x5b\x63\x1b\x3a\xc9\xf2\x1e\xc5\xcb\x67\x7c\xc9\x4e\x8a\xbe\x01\x98\x06\xbe\x3d\x3f\xd0\x60\x16\x15\x47\xe7\xe9\x3b\x88\x0f\x53\x5e\x42\xfc\xaf\xbe\x1d\xfe\xd9\x8b\x9e\xcf\xf8\xf2\xb4\xda\x12\xb4\x9b\xa5\xe8\xf0\xdd\xf3\xae\x1d\xaa\x9a\xcb\x16\x35\x75\x3a\x66\x16\x6a\x99\x3c\x17\xaa\x60\x90\x93\x98\xc3\x66\xa4\x1d\x37\x48\x81\x8a\x92\xb0\xf0\x0c\x24\xd6\x88\x5a\x37\x21\xad\x44\x78\x83\xcd\xa7\x7b\x5a\x12\x72\x00\xdd\x3d\x72\xcc\xfb\x11\x30\x2a\x30\x7b\x35\xcd\x52\xcc\x35\x4f\xbd\xf5\x4f\xb6\xd8\x7f\x9e\x93\x12\x5c\xa4\x58\xdc\x48\x03\xb1\x8e\x50\x9f\xdc\x33\x14\x67\x30\xeb\xeb\x55\xb5\x73\x05\x92\x77\xe8\x75\xef\x1b\xd6\x74\xfa\xb1\xea\xc5\x1f\x8c\x17\x2b\xfa\x26\xbb\x67\x70\xee\x15\x50\x24\xd0\xd4\x8c\x25\xe4\x39\x42\x35\x9e\x35\x45\x2f\x63\xed\xa5\xaf\x6f\x54\x35\x46\xd2\x37\x13\x1b\x24\x55\x57\x59\xa6\xb7\xd8\x47\x91\xf5\xe7\xdb\x27\x2d\xb3\x3b\xae\x4d\xb4\xce\x28\x8e\x07\x9e\x7f\x65\x4b\xb0\xc8\x56\x8f\xc5\x3a\xdd\x0d\x9b\xdd\x6e\x74\x3b\x7a\x24\xf7\xe4\x72\xa0\xdb\x74\x2b\x3e\x08\x8f\xb5\xb2\x12\x15\xcb\xc5\x22\xcb\x4b\xd0\xad\xb1\x9b\xda\x77\xcf\x91\xd4\xaa\x74\x0d\x1b\xf1\x6a\xc2\x5c\xe1\x9d\xc4\xea\x8b\xb1\x99\xca\x56\xa2\x30\xef\xb1\x1e\x68\xaa\xc1\xe8\x5e\xfa\x52\xb4\x77\xd3\x4a\x07\x37\xae\x1e\x57\x61\xb0\x3e\x7c\xbc\xb2\xdb\xbe\x3e\x0d\x76\xbe\xb9\x57\xe9\xde\xab\x74\xff\x23\x54\xba\xfc\xcd\xc5\xad\x9e\x63\x1f\x44\x79\x96\xa2\xff\x5e\xce\xa3\x33\x52\xa0\xef\x23\xfa\xf9\xb7\xcf\xec\x73\x30\xc7\x5e\x75\xef\x70\x88\x0e\x53\x52\x92\x28\x21\xbf\x62\xf4\x77\xd6\x0b\x4a\xa8\x11\x2a\xc0\x12\x4b\x18\xdc\xc0\x40\xe9\x52\x35\x1c\x49\x0f\x40\xab\x2b\x8a\x89\x38\x0c\x3c\x24\xcf\x61\x1c\xa2\xcd\xa6\x9b\x37\x66\xed\x41\x87\x6f\x3b\xcb\xf5\x9a\x99\x78\x9d\xe4\xaa\x37\x70\x22\xfa\xcf\x44\x20\x14\x5a\x52\x06\x3d\x1e\xd7\xba\xec\xb1\x4a\xa0\xa9\x7a\x26\xa2\x1a\x91\x25\x3c\xea\x7a\x3d\x0f\x69\x23\xa0\xed\x39\xbd\x1f\xae\x71\xf4\x54\x38\xd8\x65\x6d\x05\xbc\x31\xc3\x4f\x2a\xcb\xea\x57\xa9\x96\x45\x93\x8e\x31\x8f\x34\xdb\x5d\xef\x6a\x71\x78\xa2\xf8\x8c\x9e\x51\xc5\xec\xa0\xc3\x17\x90\x23\x7a\x27\x27\x6d\x63\xa3\xca\xb5\x50\xd5\xc3\x20\x12\x87\x6e\x35\x2a\x5b\xbc\x19\xe2\x23\x95\xe9\xe2\x99\x10\xfb\x9f\x1e\x98\xf8\x83\xa1\x66\x9f\x41\xd2\xf0\x42\xe0\x40\x1e\x1e\x85\x01\x91\xdf\x54\x47\x2a\xeb\x9a\x62\x41\x79\x1e\x65\x5b\x0d\xf8\xcd\x33\x04\x1a\xac\xf6\xac\x00\xaa\x2c\xd1\xba\x0c\x65\x6e\x7c\x34\x9d\x33\x07\x7a\x2a\xdb\x1e\xe0\x33\x9c\x5f\xf6\xa0\xf9\xa8\xc4\x1f\x48\x3a\x4d\xf0\x1b\x86\xf0\x3e\x0a\x91\x37\x43\xd5\xc4\xa7\x55\x76\xc4\x0f\xce\x27\xb0\xaf\x1e\x67\x73\xe1\x5d\xd0\x8d\x66\x41\x24\xd2\x18\x45\x1a\xb6\x45\x3c\x43\xcc\xcf\xfe\xfe\x3e\xa3\x1a\x1d\x88\x7b\x4e\x10\xb0\xf4\xcc\x4d\xc1\xd8\xb5\x6e\xd7\x57\x1d\x97\x61\x2d\x37\x92\xc3\x21\x0b\x56\x26\x93\xe8\x24\x51\x21\x4f\x63\x2e\x62\x3d\x56\xfb\xec\xd6\xa8\x8b\x31\xa2\x11\xf8\xfd\x6c\x60\x47\xcf\x28\x50\xb5\xe3\x6e\xde\x71\x8b\xbf\xb0\xba\x0a\xc6\x54\x79\x55\x42\xc0\x89\xfb\xa0\x3c\xe2\x8b\xa2\x27\x78\x4f\x1f\x4d\x08\x4e\x62\xcb\xf4\x80\xb7\x62\xf4\xd4\xe2\x39\x7a\x07\x2d\xc6\xc3\xba\x66\x91\xa1\x48\xb6\x3c\xeb\x0b\xb2\x70\x5f\xe8\x39\xec\x4d\xc0\x0e\x04\x6b\x13\xdf\x9c\xc5\x99\x7a\x78\x47\x56\xe4\xf5\x71\x39\x91\x8a\x81\x8f\xef\xc5\xc0\x7b\x31\xf0\xaf\x2d\x06\xaa\xf7\x79\x6c\xd1\xdc\xd5\x0b\xbd\xbb\xb9\xbb\xa7\x20\x6f\x84\xba\xb1\xd2\x58\x19\xce\x89\x3c\x1a\x86\xb0\x42\xa6\x9f\xda\x29\x92\x7b\x59\x13\xb9\xf4\xd3\xb8\xb8\x07\x9e\xa7\xf2\x95\x64\xb0\xa9\x81\x81\x1b\x7e\x3d\x4c\x9b\x32\x84\xd6\x33\xb4\x12\xcc\xb9\xb3\xaf\x88\x95\x63\x28\x5d\x41\x63\xf0\x26\x4a\xa3\x29\x56\x8e\x00\x28\xcb\x62\xa8\x30\x54\x01\xc2\xc3\x88\x02\xd7\xf6\xfb\xb9\x81\x21\xa7\xe2\x7c\xde\x60\xff\x1e\x63\xca\x61\x48\x6a\xba\xf4\xb4\xc4\xbf\x51\x54\x30\x8f\x0f\x55\xf1\x25\xa6\x18\x1c\x53\x7a\x36\x29\xd3\xb9\xbc\xed\x4b\x54\xb4\x69\xb6\x07\x24\xe6\x20\x82\xb7\x51\x19\x41\xc2\xf0\x20\xaa\x85\x28\x91\xc4\x21\xed\xf8\x84\xfb\xc2\x82\x0a\x36\x32\xa5\xc9\xb3\x31\xf3\xbf\xa9\x2e\x29\x78\xc0\x0d\xbe\xed\xca\x71\x0e\xd0\x1b\xca\xca\x09\x2e\x78\x58\x5d\xc0\x87\xe3\x78\xd2\x70\xe6\xd9\x1a\x6f\x62\x50\x57\x6f\x97\x49\xa2\xdc\x72\x04\x54\x8a\xc4\x17\x04\xae\xcd\x7c\xb8\xfb\x63\xc6\x78\x69\x23\x84\xd3\xd2\xdc\xf8\x59\xc7\xb2\x69\x38\x8f\x74\xdc\x0a\xd1\xf3\x20\x9f\x16\x8d\x88\x05\x85\x60\x81\xbe\x80\x3a\xf0\x5a\x3d\x14\x48\xb3\xd2\x8f\x49\xbd\xf6\xd6\x51\x67\xa8\x4c\xa9\x71\xa1\x26\xff\x30\xcc\x96\xf2\x68\xc2\x23\x4a\x78\x7d\x4a\x78\x70\xc6\x5d\xbb\x32\xaa\x03\x8c\xcb\xe3\xa6\x8d\x23\x06\x7a\x48\x21\x5d\x14\x19\x14\x27\x93\x3c\xb8\xd0\x6a\xa9\x45\xc5\xba\x87\xb5\x56\x90\x8f\xef\x65\xa3\xa7\xb4\x25\x40\x4a\x8f\x8b\x01\x82\x98\xc1\x75\x31\x7a\xd0\x53\xf5\x9b\x91\x36\x14\x39\xa5\xbc\x40\xfb\x6c\xf0\xa4\xef\x60\x9d\x31\x7b\x19\xcc\x53\xc7\xbc\x8b\x78\xe6\x70\xb7\xfe\xa0\x68\xba\x1f\xae\xc0\xbd\x27\x26\x8a\x0a\x27\x6a\xa3\xd0\xde\xa9\xc0\xc1\x0d\x9c\x79\x9e\x7a\x01\x64\x55\xde\x58\x24\x1c\x17\xbe\x28\x44\xe2\xf1\x94\xa0\xc3\x15\x82\x11\x45\x62\xd1\xb6\x42\x42\xbb\xb0\x42\xba\xfb\x55\xbe\x89\xd8\x5e\x91\x57\x76\xb6\xcc\x85\x09\x00\xd6\x96\x81\x0e\x08\x79\x3a\xbb\xe8\xc9\x33\x8a\x5f\x05\x22\x74\x19\xa0\x56\xaa\xd0\x64\xd4\xb9\x51\xd6\xf5\x1b\x0e\xaa\x84\x4b\x5c\x86\x4f\x53\xd4\x1a\xfd\xa2\xa3\x8b\x66\x88\xa1\x8d\x96\x24\x89\x01\x61\x7c\x50\x34\xd3\xf1\x67\x0b\xdc\xfe\xe3\xd1\x8b\xa3\xf5\xf5\x75\x90\xed\xbb\x05\x5a\x4e\x93\xcb\x01\x62\x11\x1b\xe8\x69\x60\x59\xd0\x0d\xb1\x94\xad\xa4\x9a\x0b\x59\xfa\x5b\x18\xd5\xc8\xeb\x11\xca\x38\x20\x43\x3e\xb6\x36\x3c\x2f\x65\xa3\x5f\x4e\x68\xf6\xc9\xe6\xe9\x29\x95\xb9\xf4\xcf\xab\x2b\x69\xb4\x69\x83\xb2\x1f\x5b\x50\x86\x8e\x65\xcf\x7f\x4f\x64\xd5\x0e\x90\x48\xe3\xc2\x0e\x7a\x25\xa2\xaa\xae\x50\xe5\x8d\xba\xb2\x38\x65\x21\x4f\x52\xff\x9b\x2c\xe4\xf8\xf5\xe6\xc2\xbb\x3a\x0a\xaf\xe2\xf7\x19\x59\x11\x2b\x7c\xa1\x09\x8c\x83\x3a\xb4\x65\x8a\x93\xea\x56\x4a\x5d\xce\x18\xb1\x57\xa4\x6d\x9d\xc7\x2e\xcf\x6e\x98\xc1\xf3\x76\x74\x66\x26\x2d\x22\x2d\xeb\x19\x6f\xf8\x14\xb3\xbb\x46\x35\xd5\x43\x70\x1c\x3f\xb1\xff\x68\x56\x5b\xcf\xce\x22\xac\x15\x4e\xe3\x66\x7d\x22\xe7\x90\xcb\x1c\xc3\xf5\xe8\xfb\x77\xcf\xa5\xab\x26\x66\xc7\x32\x8e\x52\x29\x69\x92\x94\x6b\x5c\xfc\x4e\xa1\x72\xd7\xc7\xe3\x60\x30\xb8\xd6\x43\xb6\xd9\x6e\xfe\x94\x1a\x53\x14\xf5\x70\xd2\x26\x1f\xf6\x95\xee\xe5\x57\x21\x42\x41\x03\xa6\x0f\x7a\x7d\xd6\xaa\x10\x2d\x63\xc5\x7b\xb5\x3a\x6f\x84\x01\x4c\xeb\xcb\xbf\x6f\xef\xb5\x3e\xf7\x5a\x9f\xbf\xb6\xd6\x87\xab\x7c\xe2\xd1\x2d\xee\xfd\x7c\x5a\x1f\xa9\xab\xd1\xd5\x3e\x8c\x3b\x49\x7d\xce\x8b\x67\x06\x23\xa1\xc3\x30\x1d\x7e\x38\x7a\x0a\x18\xa9\x95\xbc\x57\x13\x19\x6c\x4d\x09\x4c\x45\xcf\x63\xd1\xcf\xaf\xb7\xd0\x17\x64\x89\x57\x96\x20\xd4\xa3\x35\x6b\x5b\x0b\x07\x72\x94\x2e\x3d\x5f\x07\x2d\x6d\xb3\xda\xe6\xab\x23\x14\x2d\x96\xa5\x7c\xba\x96\xe2\x73\x8e\x4d\xcd\x81\x1e\x95\x3a\x42\xd4\x95\x70\x56\xe0\x8c\x10\x75\xe3\xd1\x27\x5f\xae\x90\x13\x77\x64\x9f\x64\xa3\x53\xdc\xae\x51\x09\xe7\x6d\xd4\x97\x2b\x1a\xdd\x76\x1b\x5d\x2c\xcb\x57\xf8\xa2\x79\x98\xaf\xf0\x45\xd5\x18\xcd\xac\xfa\x01\x36\xb7\xc5\x80\xaa\x86\xe6\x6f\xcb\x1a\x17\xdf\x8d\x4e\x14\x9c\x98\x88\x40\x21\x39\xe0\x43\x0f\x78\xb7\x00\xf8\xb4\x62\xeb\x7a\xf1\x6c\x4f\xee\x5a\x8c\x76\x3a\xe1\x0e\x6c\x51\x4f\xee\xb7\xa8\xfb\x2d\xea\xaf\xbd\x45\xa9\x8b\x09\x5c\xce\x6e\x74\x2b\xc1\x81\xef\xf6\x4d\x62\x45\x7c\x75\x5f\x80\x75\xdf\x15\x88\xff\x16\xa4\x61\xdb\xa4\x20\xc2\x18\xd9\x02\x5a\xf0\x64\x01\x36\xae\x6a\x6f\x9c\xa5\x13\x32\x15\x60\x5a\xec\x1b\x1d\x5a\x84\x52\x11\x60\xe7\xfc\xd1\x9a\x71\x3d\xc3\x13\x05\xcc\x8f\x70\x8a\xb7\x91\x01\x89\x02\xe4\xb0\xf8\x70\x99\x8e\xd9\x16\x63\x04\xba\x67\xa9\x02\x8c\xb2\xe2\x1c\xdb\x40\x3c\x55\xd6\xc5\xdc\x13\xe9\x10\x64\x14\xa5\x22\x9b\xf9\x3c\x74\xfa\x23\x92\xa5\x10\x02\x1e\xd3\xda\xdc\x18\x48\x8d\x37\x7f\x21\x08\x5a\xc0\xcd\xd3\x3e\x7a\xf0\x00\xf1\xdf\x03\x50\x0a\x1e\x4d\x7a\xdd\xcd\x8b\x2e\x73\x5c\xb2\xd9\x47\x4f\x51\x07\x97\x33\xba\x7b\x40\x24\xd2\x67\x97\xaf\xa2\x62\xd6\x41\xa1\x9d\xcc\xf4\xb9\x1d\x25\x25\x68\x01\x9f\x7e\xcc\xb3\xf9\xb3\xdf\xa0\xa7\x5d\xde\x25\x2d\x8e\xd0\xb3\x4b\x68\x98\x76\xfa\x20\x8d\x0f\x69\x39\x19\xbe\xcb\x0b\xc9\xc6\x21\x61\xd5\x78\x96\xe9\x38\xc1\xbf\xd1\x00\x8e\x69\x5b\x0d\x5d\xd7\x61\x2a\x3b\x2d\xe6\x47\x1b\xe7\xf3\x6c\x99\xb6\xba\x64\xba\x83\x71\x78\xdb\x66\x24\xa4\x0f\xa5\x02\x8c\x8d\xca\x99\x82\xdf\xb0\xff\xc7\xb2\x41\x6d\x32\x9c\x49\xd0\x01\x8c\x3e\xcb\xee\xbd\x2c\x67\x77\x7d\x40\xf8\xcd\x0f\x07\x10\xf2\xb7\xfa\x70\xc0\x94\x1f\x8c\x8d\x13\xec\xed\xd2\xc2\xe8\xcd\xa2\xa1\x23\x8b\x1b\xf4\x41\xbb\xe3\x66\xfc\x95\xf9\xbf\x40\xba\x23\xef\xc3\x67\x07\x6f\xad\xf8\x63\x9c\xab\x32\xc5\x0c\x7b\x40\xcb\xd5\x33\xd7\x6b\x6b\xac\x77\x03\x66\x19\x25\xdf\xd2\xbc\x2c\x67\x4a\x21\x14\xa0\xae\x1e\xad\xb9\x1b\xf0\x69\x9e\xe2\x32\xac\x50\x7b\x0a\x5f\xa5\x03\xbd\x20\x1f\x49\xc0\x55\x75\x46\xe1\xb3\x28\x31\xfc\xb5\x0f\xac\x58\xd9\x67\x51\xe2\x38\x23\x91\x69\xd7\x6b\x80\x9e\x95\x86\xc2\xfd\xfc\xdd\x64\x30\xbc\xe8\x4d\x86\xc3\x8b\xb6\x1c\x50\x9b\xd3\x28\xe5\x2f\x51\x02\x96\x9b\x8d\x67\x27\x0e\xe8\x9e\x9f\x04\xa3\x72\xf2\xe5\x21\x4a\xb3\xe6\x34\x6e\xf1\x42\x74\xa2\x44\x2a\x76\xc3\xc7\xdd\x68\xfe\xa8\x2e\xf4\x6c\x08\x3d\xd8\x39\xe3\x28\x12\x58\x8b\x16\x69\x5d\x65\x85\x7a\x35\x2c\x4f\xfa\xac\x91\x40\x15\x07\xe7\x2c\x8f\xa6\xf8\xa0\x6c\x73\x76\xe6\xa0\x95\x38\xf2\x41\xc8\x63\x6d\x0d\x96\xd8\xba\x63\x3c\xbb\xcc\xe0\x6c\xb9\x0a\x5a\xbc\x03\xe3\xce\x1d\x1b\xc6\x44\xa1\x2a\x87\x63\x65\xfe\xf6\xf3\xed\x1d\x98\x58\xf5\x4d\xf4\xcc\xd8\x91\x35\x34\x29\x34\xde\x6e\x58\xbe\xde\x06\xce\x12\x57\xf6\xaf\x74\xf1\xa2\xeb\xd5\xe8\x97\x36\x51\x4f\xbb\xb0\x03\x37\x63\x02\xc0\x1c\x4c\x48\x99\xee\x6b\x60\x42\x23\xe5\x5b\x0c\x3a\x58\xab\xa0\xec\xf9\x82\x24\xec\xf8\xd6\x48\xde\x1c\xb4\x86\xc6\x5d\x08\x81\x87\xcd\x6a\xfa\xb3\x25\xb6\x96\xf4\x68\x17\x73\xba\x55\x27\xb4\xba\x1d\xdc\xba\xe5\x44\xd5\xcd\x8d\x98\xc2\x17\x78\x4c\xe6\x51\x52\x8d\x0a\x25\x07\xb6\x44\x82\x2a\x50\x41\x94\x7f\xdc\x01\x9b\xc2\x53\xc3\x60\xab\xc3\x23\x57\x1c\xc2\x40\xc2\xae\x1d\x74\xf3\x0a\xd2\x2a\xac\x67\x1e\x1f\x3d\x67\xd4\x95\xc6\x24\x4b\x39\x83\xab\x3a\xfe\xfe\x91\x38\xcd\x4d\xf0\xf4\x1e\x8f\x31\x59\xb4\x20\x73\xb7\x4c\x1b\x02\x70\x41\x6f\x4b\x01\xbc\xc6\xd6\x03\x6c\xb9\x8a\x1b\xb9\x98\x67\x70\x36\x60\x1b\x0a\x60\x62\xd1\x1d\x09\x88\x8d\xcb\x9b\x1e\x90\xde\x47\xe7\xed\x97\xb8\x5b\xc0\x8f\x88\x5a\xb8\x36\x9c\x8d\xe2\xc1\x23\x0b\xb9\xd1\xa4\x9b\x7a\xdb\xaa\xab\x37\xef\xa7\x3d\x53\xbe\x35\xe6\x1b\x07\x99\x36\x76\x9e\x4c\xab\x7a\x6c\xe6\xdc\x8d\x8c\x5a\x81\x70\x6e\x17\x55\xd7\x51\x88\x91\xef\xed\xa8\x95\x73\x93\x8e\x52\x1e\x7a\x67\x92\xb4\x19\x4c\xbc\x6e\x4c\x1a\xa4\x7f\x68\x7e\x80\x9b\x50\x8c\x31\xc2\x5b\xad\xe6\x31\x93\xeb\x44\x08\xf0\xa6\x69\x63\xd0\x03\x11\x16\xbc\x62\x0a\xcd\x3a\x7d\x63\xad\xec\xc8\xeb\xd7\xaf\x5b\xf6\x21\xa9\xa4\x20\x59\xd3\x4a\x2d\x7f\xc0\xf9\x02\x37\xb2\x75\x89\x01\x06\x5d\x8f\x00\x07\xa6\xa6\x17\xc5\x72\x34\x27\xe5\xcf\x59\xde\x24\x5d\x28\xc0\x8a\x95\xee\xcb\xaf\xbf\x34\x6e\xd1\x2a\x87\xaa\xdc\xc2\x2a\xda\xb3\x8e\x06\xce\xc5\xb1\x52\x98\x04\x7a\x9a\x54\x10\x18\xa9\xf4\x9c\x6d\x24\xc0\x12\x36\x52\x40\x66\xb6\x0a\xf1\x83\x8b\x5b\xd2\xde\x76\x5d\x08\x25\x82\x1b\x79\x5a\xc1\xaa\x74\x29\xd0\x55\x01\x70\x99\xa3\x2a\xdb\x6a\xd4\xb4\x85\xd5\x18\x89\x4a\x74\xb7\x4f\x33\xcf\x9f\x41\xa6\xda\x97\xb5\x70\x9d\x8c\xd7\xaf\x5f\xbb\xc0\x8c\xc8\xb5\x2a\x25\xfd\x19\x63\xa3\x09\xf0\xcd\x4d\x00\x58\xc8\x32\xa9\x0c\xae\x73\x61\xac\xc8\x85\x52\xa8\x54\x4a\x9a\xc6\x95\x72\x7d\x92\x74\x14\x15\xd8\x0a\x97\x38\xc5\x8c\x1f\xf2\xe5\xc9\x61\x24\xc8\x75\x3f\x58\xa1\x8d\x39\xf1\x04\x64\x34\x5a\xe0\x10\x37\xac\x7f\x16\x15\xb3\x3c\x2a\x6b\xc7\x50\x01\xd3\x6a\x03\x58\xbd\x47\xe2\xfa\xb2\xa6\x43\x7e\x90\x66\x31\x9c\xdf\x97\x9a\xb2\xf7\xea\x3d\x9c\x46\xc5\xbb\x9c\x8c\x6b\x71\x56\x01\x73\x63\x1d\xe9\xea\xbd\xe4\x51\x79\x8a\xba\x5e\x4a\x98\x1b\xb6\x31\xd2\xee\x98\x6a\x9a\xa9\x06\xfb\x4a\x34\x24\x42\x16\xfc\x83\x19\xa3\xd4\xf5\xcd\x06\xd5\x5a\xd4\x59\x88\x71\x2b\x31\x18\xab\x8b\x7e\xed\xce\x6f\x44\x0c\x9b\xfe\x68\x5c\x66\xb9\x90\x72\x84\x69\x00\x18\xda\x06\x88\xc2\x1a\xd6\xb6\x1c\xda\xd7\xd8\x44\x98\x02\x68\x8f\x6f\x48\xe2\x7a\x24\xd2\xa2\xf4\x30\xeb\x81\x9e\xef\x5e\x2f\x40\x50\x98\x9b\x1b\x0c\x70\x39\xeb\xf5\x03\x97\x0c\x5f\x67\x53\x4d\xac\xb5\xfc\x01\x99\xfd\x53\x06\x06\xf5\x8e\xe1\x05\xd2\x7a\xbc\xc0\x60\x9a\x64\xa3\x28\x19\x50\x5c\x0c\x22\x37\x99\x47\xf2\xf2\x35\x49\xc6\xd1\xe2\xed\x4d\x9b\xa5\x85\x9d\x46\x59\x62\x5d\x93\x9a\xb5\x85\x6a\xb0\x66\x0e\xa4\x79\x46\xc5\x34\x34\xf9\x58\x7a\x59\xce\x34\xf3\x6a\xcb\xe2\xa4\x13\x6e\x3d\x09\x3a\x8e\xe5\x0b\xb7\xbc\x56\x26\x27\x9d\x70\xfb\x1b\x48\x60\x44\xd4\x09\xb7\xbf\x63\x9f\x72\xbe\x3b\xe1\x0e\x2b\x42\x46\x51\xda\x09\x77\x76\x02\xd3\x2e\x0e\x3e\x39\x96\x3a\xe1\xee\x2e\x7c\x0b\xfb\x98\x4e\xb8\xcb\xaa\xe7\x1c\xb9\x13\xee\xb2\x6e\x89\x3b\xcc\x4e\xb8\x4b\x1b\x14\xd6\x2d\x9d\x70\x77\xe7\xfa\x34\xd8\xf9\xee\xde\xd0\xee\xde\xd0\xee\xaf\x6d\x68\x57\x65\x65\x77\x6b\x63\xf0\xf6\xf6\x6f\x2d\x8c\xdb\x00\xee\x2d\x2e\xbf\xa6\xed\x38\xa4\x7e\x6d\x53\x8c\x16\xb6\xe2\xc3\xe1\x50\xb9\x5a\xf1\xb9\x6f\xe1\x71\x08\x29\x8f\x87\xea\x70\x39\x43\xd1\x82\x68\x7d\xff\x4a\x07\x89\xaa\xc0\xeb\x52\x50\x31\xa3\xb3\xdf\x54\x28\xc2\x38\xb7\x55\xbe\x4e\x2b\x55\x40\x2b\x08\x6a\xba\xd8\xe4\xec\x6a\x6f\x71\xb9\xe7\x6e\x6a\xe6\xe6\xa5\xef\x2e\xd7\xa7\xc1\xee\xe6\xfd\x6e\x71\xbf\x5b\xfc\xb5\x77\x8b\x3f\xa8\x59\xf6\xdd\x59\x50\xb7\x34\xf0\x56\x36\x8a\xef\x70\x5e\x64\x69\x94\xfc\x6e\x86\x8a\x92\xa3\xfd\x11\xec\x14\x6f\xb5\x37\x36\x74\xe1\xba\x9d\xe1\x5a\x8a\xcf\x95\x35\x5c\x9d\xfa\x56\x01\xba\x1a\xdc\x05\x9f\xd5\x4f\x5e\xa0\x5b\x5c\xbc\x2d\xd3\x24\x1b\x7f\x6e\xd7\x41\x03\xb6\xa6\x8f\x55\x70\x6d\xcc\xc7\xda\x5d\x68\x55\x5e\x6b\xdd\xf1\x3d\xa2\x1c\x52\xf3\x65\xe2\x2a\x97\x5f\xbe\xcb\xc4\xca\x21\xb5\x9f\x9f\x76\xb3\x53\x3f\x37\xab\xdc\x70\xd9\x73\x63\x75\xde\x27\xd0\xf1\x86\x55\x23\x06\xad\xb4\x50\x86\x6b\xd0\xba\xbc\xf4\xf5\xe4\xcb\x83\x06\x75\xa0\xc2\xab\x0e\x5c\x21\xd6\xb9\x72\x9d\x60\xd7\x4a\xb8\xf3\xa8\x18\x2c\xad\x82\x2d\xe7\x6d\xdd\xcb\x79\xf7\x72\xde\x5f\x5b\xce\xe3\x42\x5e\x31\xbb\x6b\xad\x40\x0b\x49\x6d\x85\x37\x76\x2d\x5e\x9f\x35\x3d\x62\x03\xa0\x0f\xb3\xd9\x57\xd7\x2c\xfc\x81\x1e\x9d\x50\xd6\xf8\x61\xf6\x9b\xe9\xee\x8b\x99\x5f\x77\xff\x2e\x2b\xca\x6a\xe5\x7d\x8d\xac\x87\xb4\xa7\xe4\x59\xd1\xb4\x4d\x53\x90\x6e\x80\xec\x0d\xba\x98\xcd\x3e\xd9\x59\x37\xd9\x95\x8d\x51\x78\xe4\x89\x14\x9f\x1f\x42\xd4\xe1\x46\x4b\x12\x0d\xd2\x95\x27\x68\x77\xfd\x00\x35\x26\xc7\xb3\xa8\x68\xd9\xb6\x06\xe9\x6f\xdb\x0f\x50\x63\xbc\x91\xe2\xf3\x9f\xf2\x6c\xb9\x68\x1e\x34\x80\x55\x8e\xd8\xce\xad\x19\x6e\x14\xc7\x1f\xb3\x36\x8d\x2a\x40\x7f\xb3\xde\xfc\xb6\xf6\x1b\x94\xa8\x0c\x7d\x97\xc0\x9b\x4a\xd4\x90\x69\x40\x42\x93\x2a\x45\x75\xa3\x56\x57\xf5\x61\xa6\xdf\xc0\x34\xdf\xa0\x18\xe2\x8d\x75\xe5\xb1\xbb\x7d\x2f\xdc\xdc\x0b\x37\x7f\x6d\xe1\x46\x29\xb1\x46\xbf\xfe\x6a\x29\xb1\x0e\x12\x7c\x81\x9e\xe1\x1c\x4f\x8b\x5f\xa3\xe2\x57\x82\xbe\x8f\x12\x7c\xf1\xb7\xbc\x9c\x14\x83\xd9\xd2\x14\x6b\x1e\x73\x07\x5c\xef\xf1\x04\xe7\x38\x1d\xe3\x10\xd1\xf6\x8b\x70\x38\x9c\x92\x72\xb6\x1c\x51\x49\x68\x88\x29\x39\xe1\xe5\x7c\x38\xcd\x1e\xc9\xdf\xff\x97\xbd\x77\x5f\x6f\xdb\x56\x16\x47\xff\x4e\x9e\x02\xed\xef\xac\x46\x8a\x69\x5b\xd4\xcd\x97\xc4\xdd\xdb\x91\xed\xd8\x2b\x17\xe7\x67\x3b\x6d\xd7\xf6\xe7\xe6\xa3\x44\xc8\x66\x23\x91\x5a\x24\x65\xcb\x6d\xbc\xdf\xe7\x3c\xc7\x79\xb1\xf3\x61\x70\x21\xae\x14\xe5\x4b\x9a\x76\xd9\x6b\xef\x54\x24\x81\xc1\x00\x18\x0c\x06\x83\xb9\xf4\x47\x49\x7f\x35\xbb\x0a\xd2\xf1\x6a\x14\xe7\x38\x8d\x83\xd1\x2a\xe9\x12\x9e\xe5\xfc\xbf\x2b\xe7\xc9\xff\x79\xdb\x6a\x3d\xb0\xce\xab\x50\x64\x1d\x13\x6c\x1e\xb5\x58\xdf\x88\x16\x8b\x9a\xa2\xe0\xfc\x2a\x49\x3f\x1f\x61\x88\xae\x56\xb6\xa1\xe9\xc5\xcd\x6d\xad\xff\xfb\xef\x9f\x4a\x4a\xdd\xc5\x96\xfc\x3a\x1e\xec\xc6\x41\x7f\x84\xe7\x61\x29\x95\xb4\x23\x68\x2f\x70\x17\xdc\xae\x82\x49\x45\xdc\x8a\x92\x0e\xdc\xac\x05\xee\x80\x5b\x98\x5c\xc5\x2c\x70\x5e\x19\x62\xbc\x98\x1d\x2b\xcb\xd7\xea\xee\x11\x2e\x1d\xe5\xa4\x02\x5a\xb4\x90\x1d\x29\xe3\xdb\x9d\x51\x4a\x71\x9e\x46\xf8\x72\x9e\xc7\x22\x2f\x66\x47\xcb\xf2\xf5\x2e\xa4\x95\x93\xdd\x6e\x0e\x51\x91\x32\x0e\x72\xd2\x3e\xdd\x79\x88\xce\x71\x05\xf7\x1b\x3b\x2e\xea\x87\x3b\x8c\x09\x0d\x38\x3c\x27\xaa\x97\x1d\x07\xf5\xc3\x9d\x47\x83\x05\x18\x2f\x47\x86\x16\xb2\xe3\x63\x7c\xe3\x28\xb5\x2b\xa1\x54\xa2\x37\x37\x0e\x0c\x3a\x5b\x96\xd4\xb2\x05\x3f\x94\x5e\x16\x8c\xa8\x78\xc9\xf9\x80\xa4\xe9\x9d\xa8\xcf\x9c\xfa\x25\x40\x84\x04\x15\x83\x64\xa9\xb7\x53\xe9\x41\x92\xc5\x1f\x54\xff\x7b\x11\x5d\x3a\x8d\x55\xc9\x9c\xc0\x77\xf1\x79\x31\xab\x82\x28\x1e\x26\x65\xb0\xe1\xbb\x04\x5b\xee\xad\xe5\xc8\x45\x84\x25\x5b\x78\x36\xab\xc2\xb8\xf5\x78\xa6\x7a\x3c\x53\xfd\xbd\xcf\x54\xec\x40\xc5\x55\x7e\x5f\x37\xae\xe8\x6d\x2c\xa6\xb8\xca\x33\x98\x44\x5c\x18\xa7\x29\x69\xf2\x8b\xb2\xab\x65\xaa\xf5\x2c\x8d\xa3\xc4\x4b\xe7\xd7\x13\x22\x1f\xb0\x98\x49\x52\x8e\xdc\xec\x2a\xca\x07\x17\x35\xf2\x5d\x0f\x87\x3d\x08\x32\x8c\x9e\x11\x8a\xcf\xf2\x67\x9b\xca\x27\x98\xac\xf4\x3c\x5b\xc9\x2e\xa2\xa1\x23\xeb\xbc\x9c\xcc\xa6\x61\x16\x60\x2c\x19\xec\xc9\x63\x7c\x45\x23\x26\x50\x6d\xf9\x0b\x0b\x1a\x13\x1c\x87\x51\x7c\xfe\xe0\x78\x7c\xa0\xed\xc8\xb7\xb4\x36\xa4\x58\xa8\x1b\x13\x1b\x0d\x9c\x51\x99\x25\xcd\x56\x75\x93\xe2\xea\x60\x8e\x72\x92\x41\xd3\x65\x04\x85\x14\x2a\xe9\x43\xa7\x71\x14\x67\x79\x30\x1a\x55\x6a\x59\x2b\x6d\xf7\x31\x73\x17\x2a\xc1\xe3\x1c\xe7\x6f\x93\xf3\x0a\x01\x30\x48\x29\xa7\x6f\x1b\x6d\x51\x2b\x52\xd2\xea\x24\x99\xeb\xff\x4a\x8a\xcc\x69\xaf\x77\x11\xc4\xe7\xb8\x42\x93\x36\xe1\x83\x82\x90\xaf\xc2\x95\xd1\x53\x04\x21\xd2\x31\xa9\x91\x64\x34\x92\xe5\x81\x85\xf9\x4d\x76\x71\xb1\x02\xac\xd1\x60\x37\xd9\x45\x05\x76\x73\x6b\x2a\xe5\x3a\xf4\x45\xe8\xe3\x9e\xe9\x94\x60\xf0\x67\xd0\x29\x69\xf7\x1c\xe7\x2c\xbd\xe4\x43\x53\x29\x6b\xed\x9b\xa2\x52\x43\x68\xa5\x7d\xc1\xf9\xc5\x26\xf9\x87\x56\xcc\x2e\x2e\x36\xc9\x3f\x54\xce\xb5\x45\x1b\x6e\xb7\x1f\xa5\xd7\x47\xe9\xf5\x6f\x2e\xbd\x16\x57\x02\xdc\xd1\xea\x9e\x12\x21\x52\x27\xb1\x23\x7c\x4e\xe6\x39\x48\xb7\xfb\x91\x23\xe8\x6e\xb6\xfa\x5a\x2d\x0a\x39\x6c\xb9\x26\x3f\x1a\x04\x13\x19\x88\x0b\xc6\x41\x6f\xfb\x83\x09\x41\xc2\x84\x79\xa3\x31\x53\x32\xb4\x85\x9e\x35\x66\x83\x6e\xb8\x11\x36\x07\x61\xbb\xbd\x11\xac\x75\xda\x83\xf6\x46\xbb\xd9\x6d\x63\x7f\xbd\xb1\x31\xe8\x34\x70\xab\x1d\x76\xdb\x9d\x6e\xb3\xff\xac\xc0\xc5\x06\x26\xf0\x03\xdf\xf7\xfb\x83\xc6\x5a\x7b\xb0\x31\x18\x06\x6b\xeb\xfe\xb0\x31\x68\xad\xe3\x6e\xab\x1f\x76\xfc\xc1\x86\xdf\x5f\x0f\x86\x8d\xc6\x33\x37\x6f\xa2\x38\x6e\x4a\x42\x71\xd0\x8f\x36\x2d\x83\xa8\xdc\x91\x12\x14\x36\xad\xfd\xa3\xec\x96\x16\x26\x68\x1b\x90\xf5\x71\xb5\xc0\x35\xbb\x4b\xa1\x2a\x1c\xb3\x7c\x16\xbf\xdf\xf4\xbd\xef\xe7\xcc\xd3\xf7\x9b\x4d\xc2\x6c\x3b\x8f\xcc\xf6\x91\xd9\xfe\xbd\x99\x6d\xc1\x6b\xb9\x9e\x4c\x63\xb6\x65\xbe\x01\xc3\x34\xf9\x1d\x8f\x83\x78\x25\xc4\x3f\x7e\xad\x4c\xb5\xfa\x5d\xea\x5d\x32\xd1\x52\x9d\xa3\xf4\x9d\xbe\x50\x82\xed\x6a\x25\x32\xbd\xc4\x6d\xd2\xca\x2e\x9e\xbc\xb6\x24\x11\x2d\x1f\x8b\x87\x4f\x45\x5b\x35\x83\xe5\x9d\x13\x58\x5a\xba\x54\x92\xc2\xd2\xe6\xbf\xad\x8d\xf0\x7f\xd9\xde\xd2\xba\x90\x4c\xf2\x1b\x49\x1e\xe9\xec\xf7\x3d\xa5\x8f\xfc\x6e\x8b\x12\x8e\xf6\xaa\x48\x99\x7f\x87\xfc\x92\x7f\xd1\x0c\xbc\x96\x21\xff\x36\x73\xf0\x6a\xc3\x4d\x4d\x21\x0a\xcc\xf2\xc4\x4e\x8a\xaa\xc9\x84\x8b\x18\xd9\x2b\xde\x0b\x27\x35\x56\x4f\x4e\x09\x75\x84\x28\x89\x78\xec\xed\x22\x59\xe5\x6b\x9c\xd7\xa4\x3b\x23\x1c\x4f\xc7\x38\x0d\xfa\x23\xbc\x89\xf2\x74\x8a\x4d\x2d\x61\x30\xc6\x59\x69\x22\x4a\x29\x5b\x25\x14\x06\x3d\x2f\x92\x32\x54\x66\x73\x52\x54\x66\x5a\x8e\xca\xcc\x91\xa4\x52\x2f\xf2\x42\x51\x4b\x88\xe6\xfd\x33\x25\x49\xae\x3d\x70\x79\xd2\xff\xcd\x83\xf2\x1e\x1d\x32\xd6\x17\x02\x3f\xc8\xae\xe3\xc1\x6b\xd8\x6f\x88\xc8\x0b\x5d\xa8\x9f\x29\x19\x3f\xb7\x59\x91\x9a\x64\xa6\xab\x55\x53\x26\x09\x40\xa8\x2c\x03\x2e\xa2\xd1\x12\xe0\xb0\x32\xb8\x08\xd2\xed\xbc\xd6\xa8\xaf\xe4\xc9\xc7\xc9\x04\xa7\xbd\x20\xc3\xb5\x3a\xff\x0c\x39\x03\x6b\x7e\xdd\xb9\xf1\xf0\x99\x75\xa7\xd5\x2a\x36\xee\x22\x47\x18\x8f\x66\xc2\x6b\x9c\x93\x0e\x99\x2b\x46\x08\x28\x4a\xfa\x48\xf1\xd6\x96\x40\x52\xd5\xe7\xf3\xbc\xad\xa2\x0a\xdd\xee\x0b\xd5\xb4\x94\x68\xb2\xac\x83\x7c\xd4\x17\xeb\x65\x61\x16\xe0\x8e\x04\x82\x0a\x8b\x28\x6b\x87\x68\x52\xcf\x05\x7b\x55\x31\xf9\xa7\x9a\xf0\xd3\x3e\xd8\x66\xca\xcf\x1b\x35\x37\xe7\x39\xce\x17\x4c\xcd\x79\x8e\x5d\xdb\xc9\xb7\x9d\x99\xd3\x42\x1c\xd5\x73\x73\xea\x16\x76\x9b\xb2\x3c\x6a\x6a\x2a\x4f\xcf\x54\x1d\x27\x4d\x27\x6c\x4d\x80\x5c\x2d\xcd\xa7\x3c\x65\x0f\x95\xec\x93\x0f\x90\x3b\xdd\x27\x39\x62\x77\x1f\x8f\xd8\x8f\x47\xec\xbf\xf7\x11\x5b\xd2\x67\x32\x0e\x31\x66\x2c\x5d\x3d\x69\xff\x13\x0f\x87\x29\xbe\x46\x3f\x47\xa3\xc1\x67\x8c\x5e\xfe\x86\x87\x43\x97\xc7\xfe\x42\xee\xfd\xef\x82\x94\x1c\xe1\x0f\x83\x78\x80\x03\x28\x6b\x73\xec\xbf\x45\x2c\x00\x56\xe5\x75\x70\x89\x7e\x4e\x92\x10\xbd\x3c\x77\x1e\xf2\xdb\xc5\x21\xff\x9f\x8c\x9b\x2a\x4e\x60\x8c\xc5\x96\xe5\x6b\xb3\x04\xab\xd1\x53\xac\xd9\xf2\xab\xd1\x84\xc2\x6a\x6b\xf4\x1d\x35\x57\xa0\xdb\xce\x41\xfe\x2c\x23\x1b\xe3\x24\x89\xb3\xa8\x3f\xa2\x04\x36\x09\xb2\x2c\x8a\xcf\xd1\x98\xdd\x5b\x91\xbd\x68\x92\x26\x97\x51\x88\xd3\x4c\xd4\x0a\x46\x59\x62\x56\x4d\x46\x23\x52\x95\x50\x1b\x37\x34\x47\x71\x12\xd2\xaf\x51\x3c\x48\xc6\x32\x64\x02\x8c\x85\xfd\xa5\xf7\x5e\x79\x34\xc6\x64\xb1\x45\x19\xf2\x51\x86\x07\x49\x0c\x59\xf8\x8f\xa3\xf8\x7c\x84\xf3\x24\x86\xe1\x24\xdd\x2b\x39\xe8\x73\x54\x95\xe3\x3e\x7f\x89\xb6\x44\x57\x24\x3d\x03\x69\x1b\x34\xc0\x37\xd2\x4b\x8e\x8b\xac\x75\x70\x1e\xfe\x88\x84\x72\x91\x26\x71\x32\xcd\x46\xd7\x34\x6d\xba\x7d\x1f\x26\x9f\x2c\xe7\x11\x14\x06\x79\xe0\x3c\x21\xab\xbd\x55\x54\x1e\x5a\x7e\x76\x02\x46\x3e\xa9\x7d\xa7\xf4\x5e\xc9\xdb\x93\xc4\x59\x42\xb6\x2e\x42\x14\x35\x4a\x1a\x2b\x07\xf1\x65\x30\x8a\xc2\x0f\xac\x7c\x4d\x96\x79\xb8\xdf\x1d\x0c\x86\x24\xe1\xab\x7b\x3c\x23\x73\x29\x05\x37\x41\x69\x85\xf6\xde\x83\x6e\x32\xbb\x0c\xe9\xfc\xc2\x4e\xe5\x5b\xea\x5c\xa9\xd9\xd0\xd9\xa1\x08\x3a\xc5\x1b\x89\xb2\x9f\x08\xba\x47\x94\x0a\xb1\x10\xd4\xa4\x6e\xe6\x17\x69\x72\x85\xd4\xee\xe9\xe5\x95\xee\xb0\x6e\xd2\x4f\x2b\x95\x4e\xfe\xc1\x42\xb3\x0f\xd2\x6c\x29\x09\xe8\xe7\x52\x21\xfd\xcc\x27\x06\x00\x6e\x50\x84\xe9\x44\x59\x4e\x1b\x3c\x2b\x94\x24\x1b\x97\x51\xc7\xfd\x10\x82\x39\xf7\x8b\x26\xf3\x27\x9d\xc2\x69\xaa\x8b\xf8\x96\xde\x58\xb3\xf5\x2b\x70\x16\xa1\xb1\xf9\x43\x66\xd4\x96\xdb\x37\x84\x5c\x96\xc8\x4c\x21\x41\x3d\x40\x97\xfb\xd8\x60\xa3\xc6\xb2\x93\x01\x29\xf0\x8a\x7c\xb7\x28\x99\x68\xbd\xfb\x20\x4c\x68\xe1\x1b\x23\x4c\xc0\x49\xa6\x4e\xce\x64\x6e\x47\x8a\xd9\x3d\xd0\xa2\x4a\x83\x5c\xcf\x06\xb3\x51\xe3\xad\xdc\x89\xf4\xb2\x79\xb4\xa7\x74\x48\x10\x1d\x9a\xb3\xfd\xe1\x5c\xec\xab\x44\xda\xe4\x67\x42\x26\xf2\x19\x14\x97\xf3\xa9\xb2\xab\xe6\x4a\x69\x49\xd4\x55\x77\x7d\xe7\x76\x3f\x6f\xe7\xce\xc9\x91\x8a\x09\x2e\x3a\xa2\xe4\xdb\x07\xf1\x69\x2e\xc7\xa6\x71\x7b\x6f\x00\xda\x41\x38\x77\xc9\x58\xbe\x0a\x53\x1b\x8e\x49\x9e\x84\x09\x1a\x8c\x70\x10\x4f\x27\x28\x06\xf8\x64\x80\xc5\xb1\xbd\x6c\xa8\x24\xec\x2d\x2b\x8f\x22\xe9\x49\x3a\x62\xd1\xb8\x3a\x96\x44\x38\x3a\xa5\xa5\xcf\x88\x90\x44\xaa\x6f\x22\x0a\x24\x0a\x37\x0d\x40\x9b\x36\x90\x9b\xc5\xcf\x1b\x9e\xee\x71\x75\x55\x1f\x7d\x85\x01\x30\x01\x4c\xdd\xcd\x19\x42\x35\xb1\xc2\xe7\x4c\x6e\x32\x11\x42\x29\x11\x41\x99\xc5\x2d\x9c\x6e\xce\x23\x72\xa4\x8b\x74\xdd\x31\xa9\x63\x99\x73\x63\x6e\x4b\x47\x5e\x80\x50\x89\x14\xea\xf2\x0e\x85\x78\x84\x73\x6c\x19\xe4\x17\xd2\xf0\x14\xf8\xb3\xd1\xa9\x31\x8d\xea\x67\x7c\x9d\xd5\x8a\xba\x75\xae\xe5\x85\x4c\xa8\xe8\x87\x1f\x90\x6b\x0c\x09\x31\xa5\x27\xf4\x7d\x4d\x29\xf4\x42\x1d\x67\x5d\x00\x2e\x19\xef\x62\xf7\x49\x31\xe1\x05\x44\xfe\xe7\xc3\x3e\xc6\x83\x8b\x20\x8e\xb2\x31\x3f\x86\x96\x33\x07\x00\x50\x3e\xbc\xb4\x0d\x79\x60\x3f\x63\x3c\x11\x41\x84\x79\x67\x57\x9f\xff\x96\x5d\x44\x31\x69\x68\x36\x48\xc6\x93\x11\x9e\x45\xf9\xf5\x66\x07\x8e\x64\xa4\x00\x21\x88\x1a\xd9\x1c\x3e\xe3\x6b\xaa\x29\x10\xa3\x29\x8d\xd7\xea\x2a\x4a\xf1\x38\xb9\xc4\x28\x18\x8d\xa0\x57\x99\x87\xf0\x6c\x80\x27\x39\x88\xfd\xec\x95\x5c\x3e\xbf\xc0\xd7\x28\xc6\x74\x44\xfa\x98\xd5\x0f\x49\x8f\xa7\xc1\x68\x74\x8d\xfa\xd7\x30\x64\x64\x78\x58\x38\x60\xa0\x99\x9f\xc9\x86\x14\xc5\xe7\xb5\xba\xb4\x0f\xd4\xbe\x53\x7a\x87\xbe\x7c\x21\xf8\x16\xf9\x6f\x09\x00\x42\x6c\x9f\x58\x1a\xdc\x65\x5f\xdf\x20\x24\x0a\xfb\x8c\xaf\xcf\x56\xc4\x4a\xd4\x2d\xa7\x4d\x8a\x24\xe5\x0d\x2b\xe6\xbf\x30\x79\xc2\x29\x93\xcc\xfb\x80\x1a\x48\xa2\x24\xae\xc2\x13\xa8\x5d\x63\x19\x4d\x32\xb3\x4d\x53\x05\xea\xa0\x42\xd4\x25\xe0\x2c\x9d\xc9\x70\xae\xf4\x9e\x00\x96\x54\x91\x1e\x1a\xac\xec\x9e\xec\x7f\xfa\x70\xf8\xf6\xed\xc1\xfb\xd7\x9f\x4e\x0e\xde\xed\x1e\x7e\x3c\x91\x8f\x47\x55\x66\xc0\x14\xaa\x14\x89\xe9\x41\x8e\x8e\xa6\x4c\x46\xf0\xda\x09\xf2\x00\x6d\xa1\xd3\xb3\x17\xea\xfb\x03\xf0\x4c\xe6\xaf\xab\x2d\x55\x01\x70\x65\x32\xcd\x2e\x6a\x3a\xdd\x33\x11\x4f\x29\x7d\x10\x66\xb4\xf0\x67\x7c\x5d\x37\xc6\xa0\x00\xb8\xc0\xe0\x55\x12\x37\x05\x64\xd6\x28\x5f\x52\xe3\x60\xa2\x30\xc9\x08\xc8\x16\x18\x0a\x90\x18\x21\x4d\x75\x98\xde\x05\x13\x49\x75\x21\xe9\xb5\x55\xa7\x72\x2a\xb8\x02\xd7\xa8\xff\xa1\x8f\xc1\xbb\x60\x72\x0a\xd5\x22\xd8\xe2\xf9\xc8\x9c\x42\xf1\x33\x3d\x4d\xb3\xe1\x62\x8f\x16\x96\x99\x13\x55\x6a\x7e\x2a\x73\xcf\x93\xc3\x9d\xc3\x4d\x4e\x64\x68\x94\x9c\xff\x97\x2e\x55\x27\x0e\xb9\xfa\xae\x92\x74\x05\x65\x41\x66\x3d\x3a\xb2\x6f\x2b\xe3\x60\x52\x73\x19\x2b\xf0\x3f\xb0\x5f\x0c\x8b\x51\x26\x63\xcf\x8e\x7a\x51\x28\xfb\xe8\x08\x8a\xf8\x8c\x51\x36\x4d\x41\x4f\xcc\x99\x55\x94\xa1\x2c\x8f\x08\x3d\x50\x4e\x8e\x43\x14\x0c\xc1\x97\x28\x4d\xa3\xcb\x60\xa4\xed\xb5\x0a\x4c\x32\x20\x10\x21\x80\x2e\x8d\x28\x3c\xd3\x51\x2c\xba\xb4\x32\x28\xec\x01\xd4\x3a\xe2\x8b\xd3\xb7\x86\xeb\x4e\xe4\x4f\x37\x08\x8f\x98\x9e\xd9\x52\x63\x18\x8c\x32\x2c\xdf\xb2\x31\x0f\xa9\xb9\x63\x2a\x32\xd5\xb2\x36\xd1\x2d\x60\x90\x79\x81\x19\x97\x16\xad\xe3\xf0\xff\xc2\x18\xcf\xef\xa0\x66\x85\x71\xac\xae\x18\x40\x0a\x85\x21\x25\x95\x76\x14\xaa\xa3\xa4\x2d\x76\xf7\x30\xa9\xb8\xb8\xf5\x0c\x48\xbe\xe4\x74\xa5\x5d\x38\xd2\xe3\x6f\xa8\x37\x5e\x5a\xfa\x05\x33\x7c\x35\x53\x48\x7f\xbf\xd9\x84\x28\x40\x4c\x19\xfe\xfd\x66\x0b\x3c\x56\xd7\xaa\xdc\x91\xb1\xd8\x69\x38\xcf\xa3\xf8\xdc\xee\x04\x0c\x8c\x49\x4b\xb9\xce\xdd\xdb\x5e\x18\x25\x8a\xb0\x9b\xc2\x3e\xc8\x15\xf2\x88\x35\xca\xfa\x4d\x50\x5e\x7f\xbc\xd6\x7b\xbc\xd6\xfb\x9b\x5f\xeb\xb1\xa8\x8c\xec\xd4\x62\x75\xb2\xbd\x43\x60\xed\x92\xe0\x8b\x96\xd8\x8b\x55\x0d\x67\xf9\x92\xf6\xd9\xe1\x60\x3b\x0c\x33\x18\x3a\xb1\xbb\x05\x31\xa8\xa5\x32\x34\xa5\xe2\x17\xf3\x8f\xf3\x88\xf0\x15\xe5\x38\x25\x58\x26\x97\x6c\x19\xf1\xdd\xfe\xe9\x53\xf9\x7c\xc0\xce\x67\x4f\x75\x25\x11\xd9\x36\x9f\xb2\x6b\x2b\xa9\x9c\xc4\xab\x68\x48\x1f\x22\x06\xf1\x7d\x28\x89\x99\xd3\x98\xc2\xd1\x98\xdc\x44\xc6\xde\xa2\x6a\x74\x09\x45\x74\xdf\xe6\x3d\xcd\x2c\x9b\x85\xcd\x1e\x87\xff\xa9\xfb\x96\xbe\x3d\xb9\x74\x97\xc2\x42\x90\xc7\x2c\x02\x94\x7f\xf8\x01\x70\xa7\x8a\xa9\x28\x3e\x07\x6e\x5c\x57\x20\xf2\xeb\x8b\x79\xe9\xc8\x28\x44\xd9\xa1\xf9\xb6\x9d\x14\xd2\xd0\x28\xc8\xa0\x99\xe3\x9c\x4c\xf6\x77\x5b\x5b\xc6\x40\xf3\x3f\xe3\xc5\xea\x2a\x4d\xae\xaa\x90\x14\x2c\xb5\x3c\x9d\x12\x99\x2d\xcd\x72\x94\x25\xd4\xce\x71\x32\x01\xd6\x0d\x67\xe7\x20\xbe\xce\xc9\x81\xdf\x43\x7d\x3c\x24\x0c\x80\x2e\x71\x7e\x85\x0a\xa3\x41\x95\x8c\xda\x5f\x34\xac\x7d\x67\xc1\xfa\x87\x1f\x90\x6d\xe4\xeb\x46\x7d\x64\x5e\x37\x10\x54\x2d\x9e\xd4\xce\xce\x26\x94\x6f\xc6\x78\x96\xa3\xde\x87\x8f\x68\x70\x3d\x18\x61\x4f\x74\x13\x86\x5d\x6c\x36\xd0\x13\xe8\x32\xb3\x59\x9a\xa4\xc9\x80\xf0\xac\x8c\x8e\x8e\xd1\x8a\x74\x0c\x16\xcb\xc4\x36\x17\x96\x8e\x30\xd2\xd0\x4b\xdd\x78\xa8\x51\xa5\x7f\x96\x61\xa5\xa4\xe0\x12\xcd\x24\x63\xb0\xa7\x02\x80\x6e\xc6\x26\xe9\x62\x6b\xa6\x1d\x94\x23\x55\x9f\x6e\x09\x75\xe3\x15\x42\xf8\x41\xe8\x15\x6c\x82\xbd\x97\x75\x48\x54\x67\x00\x9c\x85\xac\x13\x6e\x27\x79\x60\xcd\xcd\xe5\x4c\xb8\x55\x6e\x32\xaf\xc9\x7f\x48\xd6\x35\x1d\x10\x39\x5a\x52\x4e\x2d\x51\x2e\xbc\xb4\x24\x95\x13\xeb\x55\x3a\xe9\xc3\x87\x20\x0c\x85\x6d\x97\x14\x93\x55\x7c\xd7\xa7\x47\x3a\x38\x48\x2c\x96\x1b\x6f\xc1\x7b\xc9\x56\x9c\x0a\x74\x62\x24\x64\x4b\xdf\xa2\xdd\x52\x8b\xc5\x68\x58\xbc\x52\xb5\x52\x05\x0b\x02\xad\x82\x86\x7c\x25\x24\xe4\x59\x74\x4b\xb4\x06\x81\x09\x95\x73\x4d\x9a\x83\x7a\xc9\x68\x5b\xa5\x5a\x81\x90\xdb\x80\x8d\xc8\xea\x6a\x48\x4f\x22\xfb\x3e\xe6\x29\x7b\x94\x7d\xff\xee\xb2\x6f\x61\xd2\xc6\x93\xf6\xdd\x97\x8f\xee\x41\x3f\x88\x55\x69\x37\xea\x07\xc2\xf5\x16\xcf\xa8\xba\xba\xcc\x75\xf7\x78\x1c\xa4\xf9\x2e\x2b\x58\xb8\xdd\x3a\xaf\xc6\x40\xad\x04\xcd\xf2\xbe\x68\x3a\x6f\xe9\xb5\xb8\x04\x3b\xce\xd3\x28\x3e\xbf\x01\xd7\x16\xdb\x7b\x22\x2d\xf7\x83\x58\xfe\xf4\x53\x30\x9a\xe2\x1b\x74\x49\xfe\xc3\xae\x43\x08\xe4\x21\x4e\xf1\x9c\x1b\x52\x4f\x35\x2f\x80\x78\x36\x0c\x27\x55\x2c\xce\x2f\x3c\xc0\x88\x48\xeb\x1e\x6d\xc9\xdc\xc2\x40\xed\x46\x47\x19\x52\x4e\xf6\x83\xb8\x96\x27\x75\xa6\x2a\x02\x1d\x0e\xf9\xcc\x55\x3e\x35\x8b\x15\x11\xa9\xb7\x0b\x3a\xef\x67\x11\x55\xdf\x50\x88\xcc\x4f\xf7\x99\xa9\x3f\x66\x10\x77\xa2\x94\xc8\x62\x36\x87\x18\xde\xa3\x93\x84\x79\xf6\xca\xdd\x81\xea\x0c\x7a\xad\x6e\x76\x8d\xb7\x27\xe4\x18\xe8\x86\x4d\xd2\x65\xa1\xa9\x99\xa7\x34\xce\x2f\xe4\xbc\xa0\xb5\x3a\x34\xc2\xb0\x8d\xb3\x3c\xca\xa7\x54\xe0\x32\xcd\xbf\x42\x3c\x49\xb2\x28\x97\xb1\x64\x70\x05\x7a\x00\x66\x30\x8a\x70\x9c\xeb\x96\x18\x95\x1b\x36\x4c\x2c\x78\xbe\x51\x73\x04\x17\xc5\xc8\x1c\x3f\xae\x82\x2f\xbd\x4a\x16\xa4\x37\x9c\xc6\x21\xd8\x44\x0e\x70\x9a\x07\x91\x98\x7e\xc7\xf2\x11\x13\xbb\xd8\x3a\x7a\xf0\x25\x24\xf0\xba\xc5\x5a\x62\x23\x4f\x66\x53\xcb\xda\x22\xc9\xb6\xc2\x7b\x3d\x4f\x0a\x89\x96\x80\xde\xa4\x0d\x48\xb4\x39\x9a\xe2\x4d\xfa\x1f\x2e\xe6\x6a\x81\xf8\x9d\xb3\xc2\x26\xbf\x98\x94\x73\xb2\x0b\x44\x03\xc4\x39\x21\x12\xf9\x87\x6b\xe3\x69\x96\xc3\x56\x87\xc7\x38\xce\x05\xdd\xf4\xaf\x73\x9c\xb5\x9a\x75\x26\x8c\x7f\x57\xd7\x26\x92\x95\xbb\xf7\xe9\xcb\x8c\xf9\xe3\xd5\x29\xa5\xa2\x69\x1c\xfd\x7b\x8a\x51\x04\x51\xda\x87\x91\xca\x89\x2b\xcd\x35\x1f\x9d\x0a\x33\x0c\x4d\xda\xb9\x66\x00\xbb\x8e\xb4\x07\xbd\xd0\x89\x40\xe4\x0d\xe6\xa9\x82\xf3\xa4\xbe\xc2\xc7\x97\x83\xfe\xe3\xae\x44\x60\xc8\xaa\x7c\x14\xad\x41\x10\xcc\xfd\xf0\xfb\xcd\x16\x11\x5d\x79\xf2\xde\x9b\x33\xaf\x53\x29\x5d\x22\xd3\xee\x76\x2a\xe5\xdc\x79\x21\x2b\xe1\x13\x22\x5f\xb0\x74\xd5\x1e\x55\x28\x93\x81\x7d\x42\xd8\x34\x11\xf5\x93\x21\x12\xbd\xd9\xda\x42\xdf\xd3\xd8\x4d\xdf\x43\x99\x27\xab\xab\xa8\x97\x8c\xc7\x49\xfc\xcf\xe3\xa7\x4f\x9e\x18\x9d\x2f\x7e\xb1\x06\x38\x4e\xb5\xef\xc9\x30\xa4\xf8\xfb\xba\x87\xa4\x57\x38\x1e\x2c\xf7\x83\x0c\x77\xdb\xda\x87\x71\xd8\xd1\x8b\x5e\x4e\x3e\x87\x43\xed\xe5\x20\x9a\x5c\xe0\x74\x99\x42\xae\xbf\x78\xfa\xe4\xe6\xe9\x13\x3c\xca\x30\x92\x3a\x43\x15\xe6\xb4\x2f\x7c\x18\xbe\x47\x3f\xfc\xc0\x3e\xac\x04\xe3\x50\xf4\x6d\xfb\xdd\xce\xd3\x27\x4f\xe8\x87\xda\x29\xc7\xd9\x43\x2a\xaa\xf0\x4c\x30\xa4\x1f\x28\x62\xf0\x5b\xc6\xe7\x4c\x8c\xb2\x8c\x18\x6b\x88\x46\xc3\x40\xb5\x7e\x9a\x5c\x65\x38\xad\x3f\x7d\xf2\x44\x8c\x58\x92\xe4\x2b\xbd\xf4\x7a\x92\x27\xff\x3c\xa6\x55\x6f\x58\xd6\xf1\x62\x16\xc5\x77\xf4\xc7\xd3\xa7\x4f\x6a\xea\x71\xec\x09\xa2\x1a\x91\xe3\x8b\x24\xcd\x07\xd3\x3c\xa3\x6f\xc8\xb2\xe9\xa1\x2d\xc4\xeb\xbe\x90\x5e\x7f\x1a\x45\x7d\xf2\x69\x65\x14\xf5\xa5\xf7\xa0\x0c\xeb\x41\xa7\xc8\x57\x52\x6a\x45\x7a\xa7\x40\x08\x46\xe7\x09\x80\x20\x3f\x5e\x3c\x15\x58\xbc\x4d\x92\xcf\xd3\x09\xca\x83\xfe\x08\x4b\x98\x1c\xbf\x3a\xfc\x85\x9d\xf9\xc4\xbb\x83\xf7\x3f\x7d\xb2\xbd\x3f\xfe\xf8\xea\xd3\xbb\x83\x5f\x3e\x35\x5c\x1f\x7c\xd7\x87\xa6\xeb\x43\xcb\xda\xb6\xab\x1d\xf9\xa3\xd1\x96\xfc\xd1\x68\x4f\xfe\xc8\xdb\x14\x43\xd3\x4b\xc6\x13\x72\x50\x1c\x99\x43\x64\x9b\x52\xad\x56\x98\x4c\xfb\x44\xea\x27\xb5\x8a\x02\xc0\x62\x65\x2c\x90\x6c\xa9\x10\x41\xe0\x41\x14\xa1\x97\xa8\xd9\xe9\xbe\x40\xd1\xd2\x92\x02\x5e\xc8\x88\xe8\x25\xf2\x9b\xeb\xc6\x37\xf2\x17\x9e\x46\x67\x68\x8b\xc0\x78\x89\xfc\x17\xea\x77\x7a\x95\x5a\x52\xab\x46\xab\xd5\xd1\xaf\xa8\x31\xf3\xfd\xbe\x5e\xbf\x78\xbc\x79\xaa\xf4\xfa\xe7\x60\xf4\x19\xbd\xde\xab\x35\x7f\x5d\xaf\xab\xbd\x9d\xd1\x60\x8a\xea\xbb\x48\x7b\xb9\xd0\x08\x48\x83\x9c\xf5\x93\x99\xfa\x11\x0c\x0d\x48\x9b\xb3\x08\xfd\x8a\x6a\xb3\xa2\x43\xec\x77\x53\xfa\xdd\x92\x7e\xb7\xeb\x5a\x67\x01\x4a\x2d\x9b\xa1\x1f\x7f\xfc\x11\xad\x43\xc9\x6c\x86\x7e\x40\x8d\xd9\x70\x48\x07\xa8\xdb\xd2\xaa\x90\xd5\x71\x3a\x23\x03\x99\xcd\xb4\x4f\x7c\xf1\x9c\x66\xf0\x7d\xf6\xe2\xa9\xb3\x53\xe3\xe9\x28\x8f\x26\xa3\x68\x00\x5a\x02\xb3\x7b\x33\x42\xc6\xe1\xe9\xec\xec\x85\xe5\x5b\x9b\x7e\x6b\x5a\x3f\xae\xd3\x8f\xed\xb3\x92\xd6\xb3\x69\x1f\x81\x7c\xe3\xa1\x71\x34\x43\x83\x64\x34\x1d\xc7\x99\x42\xfd\x32\x4c\x22\x29\xd4\x42\xe8\xd5\x73\x42\x33\x0d\x9f\x8f\x14\x7b\x6c\xf8\x8d\x86\x3e\xb4\x62\x25\xd3\xc1\xaa\xe5\x30\x31\xed\x3a\xfa\x42\x7e\xd3\xf1\x76\x54\xf1\xe5\x2a\x7e\x57\xaa\xe2\x77\x5d\x75\x9a\x72\x9d\xf5\x3a\x2a\xea\x34\x8d\x59\x17\xdc\x80\xd6\xc9\x4b\x46\x2a\x8a\x2f\xe5\xd1\x22\x8f\x95\x47\x6c\xb6\x2e\x8d\x0f\x23\xcf\x36\x7b\xd5\xe0\x2f\x9a\xca\x90\x96\x8e\xa8\xc2\x1f\x19\x8d\x55\x19\x56\x85\x75\x2a\xf5\xe6\x8c\xad\xc2\x56\x95\x8a\x73\x06\x58\x61\xb9\xac\x62\xd9\x28\xc3\x65\x01\xe8\x81\x71\x6a\x72\xc2\xef\x66\x56\x26\xc8\x18\xc0\xd6\x02\x1c\x10\xaa\x34\xd1\xaf\x28\x3c\x25\xff\x9b\xad\xa3\x5f\xd1\xac\x79\x76\xa6\x2f\x24\x28\x1b\xa1\x5f\xb7\xa0\xe0\x2c\x32\x0a\x28\x4c\x12\x7e\xde\xc0\x99\x56\xec\x2b\x1f\x52\x3c\xa0\x9d\x0b\xd1\xd1\x20\x89\xd9\x06\x53\xec\x4a\x47\xbd\xc3\xf7\x64\x8f\x68\xcc\x1a\x0d\x0f\x35\x66\x0d\x1f\xfe\x6d\xc2\xbf\x6d\xf8\x77\xdd\x03\x5a\x20\xff\x36\xe1\xdf\x36\xfc\xbb\x0e\xff\xfa\x7d\xf2\x6f\xab\x5b\x6c\x66\xcf\x9f\x33\xa4\x9e\xa3\xed\xdd\x63\x1a\xba\x1d\x51\x71\x08\x11\x81\x20\x8d\xf2\x8b\xf1\x0a\x2f\xb3\x5a\xa0\x42\x4a\x6f\x31\xf1\x61\x85\x3e\x48\x12\xc6\x0a\x9e\xe5\x34\x7a\x80\xe8\xf2\xa7\x30\x39\xc2\x19\xce\x37\x91\x63\x8b\x64\x83\x70\xfc\x39\x9a\x30\xcb\xdf\x64\x88\xe2\xa3\x04\x4e\x63\x17\x41\x86\xfa\x18\xc7\xe0\x1d\xc0\xee\xb7\x82\x38\x04\x13\xbe\x30\x0a\x51\x9c\xe4\xcc\x0c\xd3\x24\x05\x9a\xf7\x85\x43\xe2\xe6\xa2\x9f\x3e\xe3\xeb\x0f\x69\x94\xa4\x47\xd4\x02\x78\x6b\xab\x78\x6f\x25\x1d\x6e\x16\xa6\xcd\xa9\xd9\x01\x55\x7c\xe3\x7f\xdc\xe0\x70\xcb\xde\x7c\xf1\xd6\xc2\x9f\x3f\xe3\xeb\x9f\x93\x14\x8c\x18\x3f\xe3\xeb\x95\x2b\xf2\xdb\x5e\xec\x38\xfa\x1d\xb3\x52\x59\x74\xfe\x8a\x30\x20\xb4\x8a\xda\x65\xcb\x48\xf8\x01\xa4\x30\x40\x26\x58\x3e\x72\x1c\xc7\xe2\x99\x37\xb8\x84\xba\x95\x5a\x20\xfd\xcf\x06\x17\x98\x1c\x3f\x10\x11\xa1\x2d\x7d\xc8\x8e\x92\x2b\x02\xbb\xc6\x9b\x59\x22\xbb\xf4\xf3\xd2\x3e\xc8\x70\xed\xc3\xc2\x1b\x95\xc6\x59\x7a\x77\xaa\x2f\xd5\xc2\x44\x94\xa0\x43\x45\x0f\xfa\xf3\x25\xc3\x90\x3d\x5b\xa4\x10\xc4\xc8\x4e\x94\xa7\x83\x64\x2d\x47\xfe\x24\x54\x4e\xa1\xce\x19\x1d\x59\x98\x71\xf6\xc6\xc2\x6a\xdc\x0c\x0b\x49\xfb\x89\x01\x1c\xa2\xe9\xe8\x43\x29\xa3\xfd\x1d\x43\xfc\x1f\x02\x71\x27\xe6\x6c\x16\x8e\x92\x1c\x11\x92\x74\x17\xca\xe5\x3d\x40\xdd\x02\x4a\x21\x1f\x4f\xfb\x55\x20\x83\xf8\xc4\x61\x9e\x49\x7b\x1b\x7c\x28\x76\x2a\x26\xa3\x9d\x49\xbb\x98\x5c\x62\x5d\x29\x00\x98\x32\xc8\xec\xf5\x1c\x6c\xdf\x45\x33\x60\xdb\x65\xd8\xfe\xba\x05\x4c\xfc\x94\x0d\xf2\x6a\x41\x1d\x5f\x50\x83\xa1\x6e\x99\x6c\x54\x4c\x38\x90\x16\x5b\x77\x3f\xa2\x2e\xe1\x67\xda\x84\xa1\xad\x2d\xd4\x9e\x37\x69\xdf\xdc\xd0\xda\xfb\xec\x18\x71\xd7\x9a\x31\x68\x9d\x0d\xc9\x19\xfa\x95\xc8\x12\xe6\x22\x9a\xcb\xcd\x65\x99\xae\x9c\xcd\x44\xf1\xe5\x1b\x0b\xa7\x31\x5e\xbb\x99\x0d\x29\x5a\xf0\x1b\xf1\x54\xb0\x1c\xfe\xca\xc1\x75\x64\x86\xc5\xf8\xe8\xb2\xa8\x63\x23\x5e\x38\x32\xf2\x66\xfe\x51\x42\x34\x4e\x76\x72\xbf\x9c\xa9\x6d\x05\x37\x0f\xf1\x97\xa8\x0d\x8e\x2c\xf4\xa1\x8c\xf6\xd5\xb9\x38\xe5\x10\x98\xa4\xb9\x60\x47\x4a\x80\xa9\x42\xb7\xba\x86\x08\x29\xaa\xc2\xb5\x63\x29\x9d\xa1\x5f\xdd\x8b\xd3\xf1\xa7\x0a\xdf\xf6\x15\xa8\x23\xd0\x3a\x55\x97\xa2\x7d\x0e\x9c\x92\xac\x27\x4d\x0f\x8e\x07\xe9\xf5\x84\x5a\xc6\xca\x72\xde\x3b\x0f\x25\xc3\x61\x86\x73\x63\x66\xe8\x1a\x09\x93\x9e\xa8\x57\x14\xf6\xcc\xbd\xda\x2b\x4e\x88\xc5\x4f\xbf\xf8\xd9\x2c\x7e\xb6\x3c\x60\x31\xf2\x29\x43\xc1\x35\xc4\x8b\xe2\x4a\xb8\xe6\x55\x30\x41\xcd\x38\x04\xd9\xb3\x9d\x5f\x38\x84\x18\x42\xdf\xef\x4e\x29\x18\x22\xbf\xe8\x43\xaa\x7c\x53\xcb\xb6\x4a\xca\xb6\xac\x47\xa2\x2a\x43\xa8\xd2\xaa\xa7\x12\xa8\xfa\xe8\xab\x8f\x4d\xf5\xb1\xe5\x09\x85\x85\xb1\x79\xaf\xae\xa2\x03\x72\xf2\xfd\x26\xc6\xc8\x3e\xe9\xca\x30\x59\x67\xdd\x43\x77\x23\x37\x1b\xd1\xb0\x03\x41\x65\xc9\xda\x32\xb0\xaf\x31\x8b\x15\x0a\x17\x92\x54\x54\x27\x98\x5a\x74\x5c\x0d\x69\xb0\xce\xe0\xf5\xaf\x0a\xb3\x6d\xd8\x34\x40\x99\xaf\x4f\x87\x56\xcb\x98\x1f\xa8\xd5\x54\x6b\x35\xf5\x5a\x56\x6d\x53\xd6\xd2\xa7\x53\xab\xd5\xb2\xa9\xa1\xde\x68\x67\x07\xfb\xd1\x5f\xde\x02\x6d\x27\x86\x23\xcb\x19\x47\xec\xbf\x74\x54\xb7\x90\xff\x82\xfd\x7c\xc9\x67\x88\xbd\x70\xec\xbb\x30\xc7\xd1\x30\x07\x4a\xf7\x1c\x8a\xb2\xd2\x89\xe3\xa8\xe7\x64\xf2\x24\x75\x4d\x43\x48\x5e\xbf\x4a\x8a\xae\x5a\xe6\x1b\x72\xd7\xaf\x92\x52\xab\x96\x35\x75\xa9\xeb\x57\x49\x7f\x95\xb5\xa4\xd7\xc6\x36\xbc\xb4\x64\xdb\x00\x00\x39\x5f\x45\xce\x77\x20\xd7\x9c\x83\x5c\xab\x14\xb9\xc6\x2d\x91\x6b\xaa\xc8\x35\x1d\xc8\xb5\xe6\x20\xd7\x28\x45\xce\xbf\x25\x72\x2d\x15\xb9\x96\x03\xb9\xc6\x1c\xe4\xfc\x52\xe4\x9a\x73\x91\xb3\x92\xee\xc7\x09\xd8\x10\x65\x79\x90\x63\xb3\x00\xb0\x93\xbc\x61\xe9\x18\xb0\x8c\x5c\xd7\xa3\xc1\x17\x32\x17\x79\xd3\xf6\x85\x0c\x44\xae\x6b\xc7\xad\x4a\x14\xeb\x7a\x9a\xc3\xfb\x60\xf9\xd4\xe8\xc9\x43\x5a\x3b\xfa\xa9\xc5\xb2\x7c\xf4\x63\x8b\xb9\x82\x94\x73\x4b\xb1\x84\xea\xd5\x28\x41\xac\x1f\x8e\x9d\xef\xc6\xce\x5c\x3f\x06\x76\xc6\x12\x52\xb1\x6b\xdc\x06\xbb\xa6\x84\x5d\xd3\x8d\x9d\xb9\x80\x0c\xec\x8c\x35\xa4\x62\xe7\xdf\x06\xbb\x96\x84\x5d\xcb\x8d\x9d\xb9\x82\x0c\xec\x8c\x45\xa4\x62\xd7\x9c\x8f\x9d\x49\xad\x98\x07\xb6\xb6\xcb\x25\x74\x1b\xb6\xac\x23\x5d\xc8\x31\x96\x93\xba\xb9\x5a\x56\x95\x21\xfa\xb4\x5c\xb2\x0f\x3b\x0a\x6f\xa2\x66\xa7\xbb\xda\x6a\x32\x0d\x74\xdd\xa6\x0a\xe6\x12\x8b\x10\x90\x32\xe6\x38\xcc\x54\xc3\xcf\x32\x96\x1a\x0a\x41\xb6\xef\x61\x30\xc0\x42\x47\x2c\x80\xfc\x37\x9e\x05\xe3\x89\x38\x29\x17\x1f\xf8\x9c\x52\x58\x39\x9e\xe5\xd2\xed\xf6\xca\xf6\xee\xf1\x0a\x3b\x47\xd4\xc6\xdc\x22\xfd\x33\xbe\xf6\xd0\x60\x78\x2e\xa4\xf9\x02\xca\x64\x14\x10\x24\x66\x39\xd2\xa1\x30\x09\xbf\x56\xb4\x63\x03\xc4\x74\xda\x3d\x8b\x12\xfb\x13\x8d\x9a\xba\x8f\x47\x13\x9c\xd6\xb6\x77\xe9\xb5\x3e\xd5\xd9\x3f\x7d\xc2\x6c\x56\xe4\x26\x5f\x3c\x7d\x0a\x11\x70\xc1\x80\x44\xb1\x2a\xd8\xec\x34\x3d\x6e\x97\xb0\xd9\x01\xdb\x11\xc9\x32\x61\xb3\xd3\xf6\x0a\x93\x84\xcd\x0e\xb8\x30\x8e\xc3\xce\xf7\x9b\x5d\xff\xe6\xcc\xeb\x34\xef\x64\x2d\xf2\x35\xcd\x44\x1e\xcc\x98\xe3\x2b\x9a\x65\xd0\x95\xf0\x1c\x31\x03\x0a\xd2\x3c\x1a\x24\xe3\x49\x12\x43\xc8\x75\xf2\x6d\xf5\xe9\x13\x31\xef\xa3\xa8\xbf\xc2\x8a\x7e\xf9\x22\x1b\x00\x08\xa7\xcf\x7b\x36\xee\x08\x32\x5c\x58\x75\x04\x19\x96\xbe\xfd\x9c\xa4\x21\xb8\xa5\x8b\x02\xe2\x8d\x0c\x61\x3a\x04\x7b\x31\xa0\xf5\x6d\x7e\xcb\x53\xc0\xb4\x7e\x56\x30\xc3\xe0\x59\xd5\x23\x0b\x55\x7a\xff\x31\x1f\xae\x03\x14\x1c\x0f\x56\xc8\x83\x86\x75\xb7\x2d\xbe\xd2\xc7\x32\x43\x14\xf1\x65\xf7\x72\xf2\x66\x67\xaf\xb8\x6c\xa2\xcf\xd6\x1b\xac\x7e\x46\xcd\xf3\xc8\xb2\xe2\xb7\x58\x39\x1e\x4f\x46\x41\x6e\x63\x50\x22\xc8\xf4\x1f\x31\x0b\xc8\xc3\x35\xa8\xe0\x54\x20\x78\x1d\xe8\xfd\xa2\xdf\xf1\x0a\x0f\x30\xb9\x89\xda\xa8\xe6\x37\xd7\x51\x3f\xca\xb3\x7a\x19\xc0\xe8\xd2\x02\xef\xe0\xa7\xdb\x82\xfb\xb4\xfb\xbe\xf7\xe9\x97\xbd\xc3\xa3\x77\x9f\xde\x1d\xee\xec\xa2\x6d\x08\x6d\x90\x07\x71\x8e\x52\x3c\x49\x71\x86\xe3\x3c\x8a\xcf\xb9\x22\x86\x90\xe1\x38\x09\x8b\xbe\x5b\x61\xee\xec\x56\x82\xc9\xd8\xa9\x01\x53\xba\x14\xd4\x4c\x8e\xc4\xa3\x9d\xa2\x2c\x97\x84\xc5\x6c\x52\x74\x7b\xe0\xf6\x3d\x4d\xc1\xe0\x41\xe4\xf8\x90\x8b\x28\xc5\xa5\xde\x09\xba\x27\x73\x80\x4e\x2e\x30\x19\xf5\x3c\x41\x53\xe6\x26\x40\x58\x00\x22\x85\x01\xb4\x02\x72\xb5\x78\x18\x0c\xcf\x37\x81\x74\x39\xae\x75\x79\x47\x35\xb0\x85\xed\x22\xa3\xb0\x19\xf9\x45\xb1\x6b\x32\x6c\xe8\x53\x7b\x4c\x09\x77\x42\x7a\x04\xf9\xcf\xf8\x7a\xc5\x5a\x96\x7b\x86\x0e\x86\xe7\xa8\x76\x08\xad\x04\xa3\x3a\xd4\x19\xd8\x06\xaf\xe2\x18\xa8\x6d\xf1\x38\xa2\x74\x42\x6f\x08\x89\xf0\xde\x11\x42\x19\x94\xf5\x89\x9c\x2b\xa2\x81\xfb\xbb\x2a\x25\x98\x05\x90\x22\x2d\xc8\x7b\x3c\xbf\x7a\x5e\xa1\xdb\xf4\x2e\x1d\xe6\x24\xad\xb1\xcb\x33\x18\x42\x0f\xfd\x81\xa2\xcb\x4d\x14\x5d\x16\xbc\xf1\x46\x31\x3d\x50\xe6\x5b\x85\xb4\xa9\x84\x85\x62\x92\x83\xae\x01\x90\x13\x87\xd0\xfa\xec\xc6\x59\x5d\xab\x16\xd9\x43\x97\xd0\x2a\xd2\x93\x63\x21\x3e\xd2\xd3\xfd\xd2\xd3\x0e\xbe\x2f\x7a\x12\x90\xee\x46\x4f\x2a\x9f\xbe\x05\x3d\x1d\xc4\x51\x1e\x05\xa3\xe8\x77\x9c\xa1\x00\xc5\xf8\x6a\x74\xcd\x30\x0c\xd9\x70\xcc\xa7\x25\xbe\x6b\xcc\x86\x49\x3a\x7e\x97\x84\x18\xed\x52\x5f\x35\x08\xd3\x5c\x70\xba\x24\x95\xe9\x14\xac\xab\xc1\xcd\x8f\x53\xad\xd8\x64\xec\x64\xf8\xcd\x91\xec\xbd\x91\x55\xcd\xfc\x60\xe3\x14\xb7\x24\xb8\x28\x8e\x14\x0b\x1b\x31\x4d\x12\xb9\x58\x54\xd4\xdb\x93\x09\xa1\x05\x18\x2d\x9e\x98\x3a\xb3\x5c\x33\x90\x21\xde\x12\x3f\xf9\xa6\x48\x69\xd0\x3c\x15\xe7\x44\x72\xa6\x86\xf5\x49\x3a\xa6\xd3\x1e\xd8\x74\x37\x94\xbe\x0b\x92\xda\x2a\xc8\xeb\x85\xad\x24\xb5\xa3\x01\x5b\x19\xeb\x59\x3c\xa2\x84\x4e\x3d\x00\x6c\xfd\x00\xfb\xa2\x5a\xe5\x85\x03\x36\x3a\x2a\x1f\x86\x58\x0e\x99\x68\x09\xb4\x67\x77\x24\x1f\xb6\x04\x4d\xdc\x94\x19\x4e\xab\x18\x51\x51\xa3\xa2\x30\xc8\x03\xd4\x07\xd9\x4b\x2d\xe1\x90\xc7\x00\x34\xcd\x74\xc1\xbd\x9d\x75\xc0\x1f\x70\x0a\x73\x39\x48\xe2\x41\x8a\x73\xbc\xcc\x86\x63\x94\x9c\x2b\x4c\x59\xba\x97\x3a\x5a\x6c\xac\x21\x9e\x06\x60\x4e\xdd\x5b\x18\x4f\xc1\xa1\xc4\x52\x70\xb8\xc0\xa6\xf7\x25\x63\xae\x30\x04\x28\x53\x76\x12\xde\xc0\xdb\x60\x0d\x48\xe0\x2b\xec\x5c\x12\x7f\x12\xb0\x68\xd0\x2c\x16\x8c\x20\x8a\xcf\xef\x81\x9b\x14\x9d\xdf\xe2\xe4\xc1\xe0\xd7\x9e\x91\x36\x9f\xa9\x64\x52\xa5\xde\x15\xc7\xdc\x49\x61\xac\xe4\xa6\x16\xe5\x95\x0e\x9d\x83\x7b\xe0\x38\xb4\xcd\x7e\x00\x5f\xe4\xea\x36\x9a\xa2\xed\xa1\xe0\x32\x88\x46\x41\x7f\x84\xa9\x19\x62\xe6\xde\x16\x3f\xf1\xce\x54\xa6\xaa\xbd\x28\x66\x1b\x5f\xe9\x3e\xc5\xe0\xaa\xfb\xcc\xfb\x24\x67\xde\xd1\x34\x68\x1a\x85\x54\xec\x1a\x28\xca\x10\x1e\x0e\xf1\x20\x8f\x2e\xf1\xe8\x1a\x05\x28\xc4\x59\x9e\x4e\xe1\xd9\x43\x29\x0e\xc2\xe5\x24\x1e\xe0\x4a\xfb\x4c\x55\xea\x05\x34\x1e\x8a\x86\x29\xf0\x87\xa6\x64\x3e\x92\xb5\xea\x44\x2c\xaa\x2c\x4a\xfd\xa2\xe2\x7c\xf2\xe7\x45\xab\xd3\xff\x5e\x31\x17\x53\x28\xa4\x96\x88\x86\xa5\x00\x50\xe9\x6a\x51\x8a\x5a\x2e\x4a\x16\x60\xc8\x10\x0f\x89\xa0\xca\x16\x1c\x0e\x59\xbc\x4c\xce\xa9\xf7\xa4\x09\xb1\x2e\x3e\xb3\xf6\x5c\x65\xb3\xdf\x5c\x5f\x6d\x35\xe5\x4f\x54\x25\x62\xfb\xa2\xc9\x41\x9b\xc8\x57\xbe\xaa\xf2\xef\x26\x6a\x56\x39\x3b\x65\x56\x55\x76\x30\x5f\x91\x8d\x9c\x6b\x93\x9f\x5a\xd8\x48\x9f\x5c\x60\x49\x28\x60\x89\xb6\x02\x74\x01\x5a\x63\x22\x64\x56\x58\x8a\x5c\x84\xdd\x8e\x39\x3e\x10\x60\x80\x2f\x6b\x22\x34\xb1\x75\x6d\xe9\xd0\x57\x38\x2c\x31\x6b\x6f\x53\xe5\xa9\xe9\xc8\x0d\xd9\xd6\xb9\xca\x94\x7a\x9b\x4e\xbf\x29\xf2\x27\x3e\x65\x78\x84\x07\x39\x6d\xf8\x38\x4f\x83\x1c\x9f\x5f\xd7\x5c\xe6\xda\x92\xf6\x19\xc4\xc5\x2d\xf4\x8c\xb2\xd2\x67\x4e\xf3\x30\x36\x1b\x1f\x82\x2c\x23\x6c\xe2\x55\x90\xe1\x50\xf1\x98\x93\xff\xca\x8d\xc3\x18\xa8\x63\x9c\xc2\x81\x8b\xec\x6a\x6e\x48\xe5\x8b\x5c\xcf\xed\xc7\xee\x33\x4a\x6c\xd4\x5d\x48\x31\x72\x92\x19\x9b\x79\xc3\x52\x66\x37\x5a\x04\x01\xb3\xcf\x83\xb8\xb8\xa1\x28\x7a\xc8\x7d\x81\xa3\x8f\x81\xe7\xb0\xf4\x64\x64\xbf\x69\xf4\x5f\xbb\xcf\xb9\x13\xda\xea\x4d\x91\x87\x4a\x6f\x8c\x74\xcc\x2d\x13\xaa\xb3\x6d\x99\x4b\xd6\xea\x4c\xc3\x6b\xbf\x7a\x53\x75\xd8\x59\x9e\xe2\x60\x7c\x2b\x55\x36\xc8\x50\x4c\xf9\x2c\xdb\xe0\xb7\x9a\xcb\xfd\x88\x1a\x6c\xab\x27\x1a\x2a\x9d\x40\x18\x6b\x49\x33\xed\xa3\x5a\xab\xa9\x2a\xa6\x25\x85\xef\x31\xe0\xa7\xa9\x7d\xf5\x97\x25\x1e\x21\x7b\x96\xbd\xd6\xb6\xc3\x72\x11\x71\x12\xa4\x70\xdc\xb2\x09\x88\xe6\xf6\x06\xc7\x9b\xc2\xba\x8a\x0b\x8d\xdf\x7d\xf7\x6c\x38\x9a\x66\x17\xcf\xaa\x6d\x73\x14\x8a\x6b\xa3\x13\xc3\xbc\x89\xfc\xb2\x79\x85\x73\x2d\x64\x35\x9d\xc8\xb7\xa5\xb2\xf2\xfc\xd3\x98\x9e\x7d\x7b\x2b\xec\xc7\x1f\x37\xf3\x29\x44\xf1\xd8\x81\x7a\x06\x95\x48\x6d\x48\xb7\x9b\xec\xa0\x6d\x38\x07\xb3\xf7\xb2\xd2\xbb\x4c\x41\x2f\xab\x28\xc7\x3c\x39\x57\x21\x5f\x2f\xbc\x9b\x6e\xab\x3d\xb2\x2a\x04\xf5\xcc\x32\x85\x82\x1f\xa8\xfa\x2b\xec\x87\x7c\xa6\xf8\x76\x07\x7a\xd8\xde\xab\x9e\xa1\x8a\xe6\x1c\x25\xba\xa4\x5e\x3b\xb7\xd1\x3c\x17\x30\x4a\x75\x85\xa2\x2e\x57\x34\x49\xf5\x6e\xa5\x71\x16\xd3\x59\x1c\x90\xfe\x33\xa7\xb3\xd0\x04\x2f\x38\x9d\x56\xc5\x6f\xc5\xe9\x14\x75\xef\x30\x9d\x65\x0a\xdf\x6a\x57\x07\x5f\x75\x3a\xef\x3c\x5d\x25\x4b\x60\xce\x7c\xe9\x7a\xd3\x92\x49\xa2\x9b\x89\xd0\xf3\x0e\x6c\x62\x1d\xb3\xba\xbe\x44\x5b\x28\xba\x94\x67\xab\x6c\x8b\x60\x3b\x26\x8d\x2b\xdd\xbb\x08\xa2\x18\x52\x9e\xb8\xee\x5a\x5f\x81\xdd\xc0\x27\xde\x79\xb4\xe5\x0e\x3e\xa0\xab\xd8\x94\x1d\x84\xd4\x35\x88\x41\x1a\x9a\xa2\x31\x6d\x97\x10\x77\xa2\x2f\xca\x38\xca\xab\x1e\xdf\x0e\xb4\x93\x90\xd4\x84\x32\x77\xa4\x57\xaf\x7a\x96\xbd\xc7\x04\x4f\x9b\xf8\x20\xc2\x7f\xe6\x5c\x8d\x41\xa9\x34\xc8\x99\x51\xf7\x8a\x5e\xc7\x80\xa1\xd1\x2c\x95\x8e\x84\x56\x84\x09\x4b\x09\x97\x91\x90\xca\x09\x91\xf5\x86\x84\xd9\x65\x11\x20\xec\xe7\xd5\x05\x66\x91\xf7\x29\x7e\x10\xc8\x33\xab\x80\x9c\xb9\x30\xec\x05\xc9\x1f\x4c\x25\x13\x75\xa8\x37\x00\xa4\xc7\x83\x2e\x08\xd7\x06\x5d\x96\x95\x27\x03\x15\x2a\x40\xc3\x4c\x5e\x85\xe2\xb4\x85\xb6\x3a\xc0\x22\xfd\x86\x44\x5e\x48\x0e\xc3\xd9\x42\x88\x15\x9a\x1c\xf1\xca\x61\xce\xfa\xcb\xe1\x11\x9c\x97\x19\xd1\x99\x65\x66\x49\x0a\xfd\x2a\x14\xdd\x1e\x52\xfa\xe5\x15\xcd\xda\x84\x7e\x86\x87\xec\xeb\x52\xd3\x47\xd7\x8a\xd9\x11\x1e\x63\x90\xc2\x61\x77\xa5\x24\xc0\xae\xa2\xe0\xb4\x0f\x0e\xed\xf0\xda\xac\xce\x25\x58\x7c\xc9\xc3\xce\x53\x66\x4a\xf3\xc9\x73\xbc\x85\x29\xa0\xb3\x03\xb2\xe7\xce\xdc\x75\x1b\xe2\x0a\xeb\x56\xec\x53\x8f\xeb\xf6\x71\xdd\xa2\xdb\xaf\xdb\xbb\xac\x0e\xb0\x10\xbe\x88\xb2\x85\xd7\x86\x15\x13\x46\xd1\xc0\x45\x7e\x39\x3c\x72\x72\x00\xd9\x83\xcc\xe0\x00\x77\x65\x3b\x56\xcc\x4e\x8a\xa1\xe9\xe3\x41\x32\x66\x4b\x87\xb0\x85\x28\x99\x66\xd5\x99\x87\x18\xac\xaa\xec\x41\x90\x12\xef\x46\xcd\x89\xfb\x42\x1e\x50\x20\x22\x71\x69\xc9\xe6\xe1\x7f\x91\x24\x19\x46\xe3\x68\x46\x64\x21\x4b\xff\xc0\x13\xd4\x14\xd2\x90\x4c\x88\x4c\x0a\x73\x91\x5d\x72\x09\xd2\x29\x39\xe9\x64\xd3\x7e\x86\xff\x3d\xc5\x71\x6e\x55\x31\x20\x55\xb4\x93\xb2\x7a\xa8\xa3\xe8\x54\x0d\xca\x28\x69\xb3\x32\x5f\xd5\x4f\x76\x36\x1b\x56\xb6\x18\x49\xc5\x6a\xb3\x46\x4a\x22\x7f\x30\x81\x85\xf5\x78\x74\x86\x7e\xdd\xa2\xf5\x4e\xa3\xd2\xd0\x25\xc5\x6f\x6e\x02\xfd\xaa\xc7\xca\x2b\x01\x4d\x24\xd1\xf6\x43\x10\x86\x64\x02\xe7\x28\x40\x26\x90\xe5\xaa\xb7\x42\xff\x6b\x57\x7f\x7c\x78\xd3\x3b\x46\xff\xa7\xb3\xba\x86\x26\x0c\x68\xc6\x74\x79\x36\x98\x1f\x3e\x0f\xb2\x35\x90\x93\x27\x41\xb8\xc2\x9f\x4a\x64\xe3\x0f\x01\xbf\x7e\x9e\x66\x3c\x74\xbe\x08\x84\xc2\xcc\x95\x21\x6e\xb2\xc0\x63\x21\xfb\x2b\x80\x2c\xdf\x3e\x13\xb4\xac\x95\xec\x7a\x3c\x16\x02\x4a\xba\x8f\x04\x40\x99\x08\x66\x49\x06\x05\xc2\x59\x3e\xf0\xb1\x59\x1c\xbe\xc4\xb8\x92\x5f\xc5\xf5\x9a\xa7\xc5\xcd\x52\x2e\x98\x83\x50\xbf\x5c\xbb\x35\x03\x11\xd5\x68\xac\x93\x2d\x69\xbc\x5c\x31\x43\xa6\x71\x2e\x68\x07\xfc\x8a\x4c\xa8\x31\x23\x58\x03\x28\x7d\xb1\x4c\x53\x4e\x8b\x08\x2b\xff\xd0\x0a\xd8\x9a\xa5\xf7\x42\xbc\x5d\x33\xf4\x02\xcd\xf4\x06\x5f\x09\xbd\x40\x04\x14\x05\x8b\xc2\xd7\xc5\x78\xcf\x1c\x5c\x8c\xf7\xe0\xd6\xa2\xbc\x9d\x8b\x59\x29\x52\x59\x79\xf8\x82\x82\xfd\xa8\x6d\xa2\x08\x2d\xb9\xdc\xf2\x65\xe8\x34\xcc\xbd\xf4\xa6\x44\x7a\xd5\xb0\x43\x5b\x85\xed\x3b\x3f\xfc\xcb\xa0\x3d\x15\x25\x9b\x19\xc2\x76\x18\xda\x07\x01\xe6\x7a\x90\xc4\x83\x20\xe7\x30\x2b\x6b\x60\x3e\xc6\x13\xc1\x50\x60\xc9\x5e\x04\x21\x0d\x64\xc4\x16\xea\xd7\xe1\x32\xd3\x58\xe7\x33\x5f\x85\x23\x40\xb3\x15\xae\xdc\xa1\x9c\xce\x12\x6c\x7c\xe0\x35\xce\x95\xc4\xc5\xd2\x22\x86\x18\xb0\x68\x14\x64\x39\x3c\xcf\x5f\xd3\x85\x78\x7d\x5a\x53\x97\xf3\x32\xf2\xeb\xd4\xc5\xec\x8c\x39\x83\xd9\x3c\x89\xa9\xe0\xe0\xa6\x98\x02\xdc\x96\xbe\x06\xa5\xcd\x94\x6e\x9b\x0b\xea\xf9\xff\x8c\x8b\x20\x9b\x8b\x82\xfd\x66\xc1\x76\xab\x50\x76\x0f\x74\x7f\x46\xff\xef\x92\x10\xdf\x50\xf5\xe0\x89\x38\xad\xd1\x4b\x11\x38\x49\x48\xdd\xe9\xbd\xea\xb9\xa0\xb0\xb9\xba\x11\xf4\x45\x60\xe9\xc2\x86\x09\x11\x48\xde\x41\xe0\xe0\x47\xc0\x06\x40\x32\x9c\xd4\x08\x9c\x60\x0a\x98\x79\xda\xa9\x8e\xb6\x6d\x34\x71\xa3\x78\x23\x2c\x60\x18\x48\x27\x5a\xfd\xd8\x93\xac\x0f\xcb\x6d\x00\x4b\x02\x9c\xa9\xf6\xa1\x16\x3f\x4e\x90\x9b\xc9\x08\x28\x6a\x51\xa4\x2a\x76\xc9\xf7\x31\xd8\x7e\x3a\xf0\x2f\x26\xd6\x3c\x0c\x18\xb6\xa4\x5c\xd2\x56\x8d\x4b\x9c\x27\x06\x02\x15\xb6\x44\xd0\x68\xc0\xa9\x5c\xbb\x9b\xb1\x4b\xfb\xab\xcf\xcb\x9b\x57\xad\x57\xea\xe8\xf9\xea\xc2\x18\x08\x55\x8b\xe3\x2c\xf3\x06\xe3\x09\x0a\x72\x34\xc2\x84\x0b\x26\x31\x5f\x01\x2c\xcb\x07\xb5\x04\x85\xfd\x1a\x18\xae\xc9\xb7\x90\x38\xdf\x8c\xa3\x98\x1a\x89\xb2\x43\xbc\x11\x2e\x51\x7d\x64\x95\xe8\xf4\x49\xf8\x53\x42\x1a\x83\xfd\x31\x3d\xf2\x46\x97\xe8\x87\x1f\xac\xfa\x78\x3d\x50\xc7\x87\x5b\xe9\x32\x0a\x4c\x54\x65\x8a\xf3\x7c\xae\x37\x5b\xf5\x4a\xda\x2d\x92\x16\x22\x89\x30\x94\x66\xaf\x2c\x04\xcd\x9b\xbb\x5f\x42\x5e\x5d\x25\x07\x19\x9a\xee\xcb\x25\x72\x81\xbc\xce\x4c\xbf\x40\x02\x87\xdf\x73\x75\x10\xfc\x2a\x9e\xda\x08\xba\x4e\xc9\xb7\xba\x8c\x7f\xb8\x65\xf5\xb0\x78\x5b\xdb\x03\xc9\x6f\xce\x0c\x50\xf9\xc8\xd6\xde\x3c\xcb\xbf\x3b\x5a\x2a\x80\xe9\x1d\x93\x3d\xec\x66\x28\x68\x90\x8c\x46\x98\xd2\x7f\x32\xe4\xa2\x01\x88\x9a\x18\x72\xe9\x95\x89\x1e\x92\x28\x2a\x39\x79\x93\x6d\x34\x0d\xae\xa4\x57\x56\xbf\x44\xbb\xeb\x07\x75\x40\x17\x42\x4a\x95\xda\xc5\xc5\x23\x64\x78\x60\x5c\x90\xd6\x27\xeb\xd3\x30\xc7\x75\x01\xca\x82\x11\xc5\x1e\x7e\x00\x30\x50\x49\x06\x34\xfc\x28\x4e\xa3\x4b\x2a\xab\x70\x8e\x61\x05\xc8\xaf\x52\x0b\x39\x5f\xb2\x1c\x34\x63\xad\x56\x93\x6b\x6e\xd3\xb3\x72\xf9\x66\x70\x81\xc7\xb7\x83\x6b\x17\x38\x99\xca\x1c\x2c\xa6\x87\x12\x3c\x2b\x08\x9a\x93\xf1\xa6\xc8\xd9\x48\x4f\x31\x54\xc4\xe2\x6f\x75\x31\x6c\x90\xc4\x97\x38\xcd\x15\x19\x96\x66\xbb\xe3\xc6\x94\x60\xf1\x49\xad\xff\xdc\x6e\xab\x1f\x68\x15\xd5\x79\x55\xbc\xac\x68\x0f\x33\xdf\xc5\x4a\x45\x6d\xfe\xb1\x4e\x78\x37\xc9\xf8\x68\x76\xa2\x41\x2c\x92\x58\x4d\x92\x2c\x8b\xfa\x23\xec\x5e\xb1\x96\xa6\x16\x73\x6e\x2a\x06\xca\xb4\x07\xa5\xdf\xf8\x09\xfc\x0f\x03\x0a\x12\xea\x73\xb2\x82\x37\xa5\xdf\x85\xc3\x93\xb5\xd2\x67\x7c\xbd\xa9\xfa\x45\x59\x8b\x69\x9e\x52\xf6\x42\x64\x19\x6f\xc2\xbf\x73\x0a\x8a\x55\xb9\x69\xba\x73\xd9\x6b\x30\x11\x5e\xb7\x4c\xb0\x17\x16\x72\xbd\x7a\x74\x7e\xd3\x3b\x5e\xb3\x57\x90\x58\x78\xdb\x5e\x42\x2c\x1c\x09\x28\x7d\xb7\x72\x38\xc1\xf1\xf1\xf1\x5b\xa3\x5a\x75\x67\x32\x79\xfa\xed\x82\xd7\x38\x9a\x1d\xc4\x6a\xb9\xca\xa6\x47\x74\x15\x67\x8b\x2d\x63\xe4\x5c\x37\x26\x2b\xd1\x7c\x03\x1d\xdc\x84\x1c\xea\xdc\xc0\xb9\x81\x2d\xf7\xca\x80\x5d\x01\x7e\x47\xc3\x48\x5f\xe3\x25\x70\x20\x09\x58\x46\x33\x80\x41\xf6\x38\x5c\x78\x51\x16\x18\xc7\x09\x7d\xa3\x31\x40\x96\xb3\x1f\x97\x71\x8f\xaa\x4b\x9a\x22\x2f\xae\xe9\xd8\xda\x5e\x42\xcf\x9e\xd9\x7d\x2b\xac\xe5\x57\xf2\x84\xe6\x1b\x72\xb9\x72\xcc\xa9\xe5\x20\x55\x27\x61\xf2\x8a\x32\x71\x8a\xb1\x71\x59\x55\x15\x25\xd0\x97\x2f\x94\x5c\x8b\x3a\x2b\x7c\x12\xaf\xf9\xb1\xd7\xd0\xd1\x58\xe5\x24\x4a\x65\xf3\xee\x35\x68\x3b\x70\xb5\x21\x7e\xda\x6f\x37\x58\xcf\x6d\xc4\x69\x03\xcd\x8a\x8b\x54\xc6\xb0\x7b\xa9\x83\x58\x7e\xdd\x21\x56\x5d\xe0\x5e\x72\x31\x6f\x66\x79\x90\x8c\x27\x41\x0e\xdb\x4b\xd5\x65\x28\x6f\x0b\xda\x26\x26\x89\x3f\x55\xf7\x44\xdb\xf2\xbb\x0d\x72\xf7\x65\x38\x98\xd0\xb6\x8f\x39\x79\x3b\x08\x59\xa2\x2e\x17\x6f\x54\xe8\x5b\x14\xaf\xcc\x7d\xe7\xa8\x65\xe4\x48\x4b\xca\x12\x2c\xbe\xd8\x02\x35\x12\x71\x57\xab\x40\xde\xd9\x8e\xb1\xd0\x5f\xf3\x10\x4b\x8a\x3b\x55\x2d\x57\x52\xb4\x1a\x43\x7b\x7f\xda\x98\x75\x5a\x5d\xbf\x3b\x58\x83\xc4\x06\xdd\x4e\xb7\xdd\x19\x76\x86\x67\x75\xae\x8a\x07\xd0\xfc\xa1\xe8\x87\xe3\x1c\x59\x01\x05\xe7\x58\x38\x0e\x5f\xa2\x6e\xc1\xc8\x68\x58\x9b\xc5\xf7\xbc\xb2\x35\x26\xfb\x2b\x2d\x2a\x3c\xf2\x75\x52\xd0\xe9\xad\x97\x8c\x1a\xb3\x81\x2f\xe8\x5b\xac\xe1\xfb\x0d\xe0\x60\x0a\xa3\xda\xd2\x9b\x04\x69\x86\x6b\xca\x42\x2d\xb9\x98\x4c\x33\x45\xf1\x53\x54\xb3\x7a\x25\x90\xe2\x88\xc6\xf0\x9a\xb3\xe8\x28\x61\x18\xc8\x94\xa9\x57\xcb\x20\xf2\xcb\x38\xe9\x30\xcc\x92\x42\x18\xe0\x4e\x70\x96\x53\xdb\x86\x60\x64\x59\xa0\x1a\xcc\xd3\xc6\x19\xda\xda\x42\xc5\xda\x43\x3f\xfc\xa0\xb7\x7b\xea\xb3\x32\x7c\x4d\xba\x54\x50\xbb\x33\x7a\x81\x61\xb6\x8c\x54\x0e\x63\x2c\x7e\xad\x45\x66\xca\xd3\xf4\x50\xbb\x5e\x62\x5d\x97\x5c\xb2\x23\x3a\x5c\x05\x15\x30\xcc\xf2\x06\xfc\x09\x34\xd0\xd0\x6f\xad\x8d\xe2\xca\xad\x8e\xdf\xad\xc6\x28\xac\x47\x23\xc7\x31\xc8\x93\x4e\x27\xaa\x68\x5e\x7a\x57\xc4\x17\xe1\x55\x1a\x4c\x26\x20\x47\x06\x39\x6b\x5e\x56\x99\xa0\x80\xec\xf4\x99\xe4\x95\x56\xba\x7a\x15\x57\x1f\xc3\x95\xad\x70\xf8\xb1\x7d\xaa\xea\x40\x72\xeb\xcb\x1e\x21\xf4\x70\x19\xbf\x4c\xaa\xe7\x3a\x02\xb9\xb7\xac\xb3\xd4\x21\x34\x0e\x29\xd5\x88\x03\x46\x71\xb1\x63\x39\x38\x95\x85\x88\xd2\xbd\x17\x01\xa1\x4d\x43\x54\x93\x26\xb6\x34\xa8\x14\xbb\x76\x20\xf3\xc6\xbc\xe9\xee\xe2\xa1\x5a\x28\x9f\x2c\x47\x9d\x12\xef\x73\xd6\x34\xb5\x41\x61\xbf\x0b\xbf\xf3\xbf\x48\x0c\x17\xfb\x16\xb6\xfd\xe7\x6e\x60\x64\x59\xda\x35\x2a\xe6\xb2\x12\xfe\x95\xa6\x36\x42\x71\xb5\x74\x9c\xc2\x1e\xae\xc1\x22\x48\x8d\xae\x4e\xf8\xaa\x8d\x7b\x62\xb5\x39\xa4\x81\x12\x65\x87\xc5\x39\xd6\xed\xc5\x7a\xbb\x10\x3a\x0b\x45\xcf\xd9\xb5\xd9\xaf\x4b\xd1\x0d\x92\xc2\xf9\xc4\x16\x00\xcd\xea\xb3\x6a\x88\x25\x85\x67\x86\x08\x90\xc0\x3a\x7b\x1b\xc9\xa4\x07\xfd\x2b\x60\xc2\x15\xb0\x01\x85\xd9\x1b\x11\x8e\x2b\x1c\x73\x5d\xfb\x51\xf5\xed\xb4\x6c\xd3\x56\xf6\x57\xb3\x20\x57\x2d\x5a\x3e\x11\xb2\x12\x7d\x5b\x89\x2e\x2d\x45\x24\x1d\x21\xa3\x17\xb3\x0c\xd5\x0a\x16\x80\xe0\x42\xd4\x2c\x26\xf4\x81\x45\x49\xf6\xca\x52\x58\xd2\x05\xea\x16\xd6\x96\xd2\x92\x5e\x90\x90\xde\xd0\x72\x5c\xbb\xa9\x7c\x6c\x61\xf7\xd0\x99\x98\x38\xa1\xf8\x92\xaf\x65\xd0\x83\x6d\x4f\x32\x01\x88\x1d\x4a\xbb\x68\x92\x1e\x21\xb5\xf7\x5f\x71\x9f\xd2\x02\xb4\x88\x48\xc7\x5f\x61\x6f\x2a\xa2\x2a\xcf\x67\xd3\xdc\x7b\xde\xc2\xa6\x39\xd9\xb1\x30\x0a\x92\x47\xfd\xad\x59\xf6\x7d\xa3\xa8\xef\x4b\xf7\xb8\xa5\x38\x63\x17\x38\x22\x0c\x7c\x85\x5d\x85\x69\x1c\x24\xd5\x82\xbc\x98\x34\xc0\xf2\x4e\xc1\x6e\xbf\xe1\xfc\x2a\x23\x5f\x70\x13\x5b\x73\x8c\x53\x98\x1b\x86\x3c\x79\xca\x26\xa6\x44\x5d\xa4\xc3\x52\xec\x4d\x12\x93\x51\x14\x3e\xd6\x6d\x42\x34\xb1\xb0\x36\xc6\xca\xd6\xf4\xb1\x52\xef\x5f\x40\xc7\x14\x64\xd9\x74\x8c\x43\xf5\x3e\x31\x18\xa5\x38\x08\xaf\xa5\xfd\x4e\x39\x90\x4d\x63\x9a\xb6\xb2\x42\x44\xb3\xc5\xd8\x9e\x9d\x7f\x2d\x74\x68\x22\x8c\x0b\x4c\xd4\xd3\x0c\x2f\xcc\xeb\xdd\xfa\xa2\x69\xbc\x28\xac\x3f\x51\xe2\x36\x48\x9e\xaa\x90\x0e\x39\x15\x20\x41\xfc\x76\x1e\xf0\xc9\xd0\x29\xc9\xab\x87\x55\xb6\xa5\xf2\x66\xb1\x6b\xe4\x45\x38\x27\x84\x0d\xb7\x09\xa1\xec\xc9\x5c\xaa\xfa\xc5\x06\x2a\xd5\x8e\x32\x68\x25\x4a\x51\x43\x33\x61\xbd\x21\x79\x63\x37\x91\x98\x77\x65\xf2\x39\x1c\xc2\x7d\x09\xfd\x6f\xf9\x65\xc9\x3c\x2b\x0c\xf3\xc2\xe4\x0d\x85\x4e\x5a\xa9\x76\x4f\xb2\x43\xc0\xc3\x9d\x3e\x69\x8c\xac\xe5\x83\x9f\xb8\xc2\x60\xc2\xe2\x05\x55\x57\xc7\xf2\x1a\xcc\xf2\x82\x3d\x80\x9c\x42\x9a\x01\xc0\xe5\x5e\x21\x45\xa0\x72\x4c\x6d\x2b\xa2\x98\x59\xf2\x32\x3b\x00\x66\x32\x73\x8e\x63\x30\xe6\x2d\x87\x26\xa2\x94\x3b\x80\xd1\xd0\xd9\xe5\xb0\x4c\x9d\x01\xa8\xb0\x24\x21\x69\x1b\x75\xdb\x60\x72\x0c\x1f\xb8\xfd\xec\xc1\x10\x25\xe3\x88\xc8\x08\x1e\x0a\xe8\xa7\xab\x68\x34\x42\x7d\x2c\x1a\x0c\x51\x1a\xc4\x61\x32\x1e\x5d\xdf\xd3\xe1\x9e\x5a\x4d\xb0\x61\xf2\xd0\xc1\x4f\x1e\x4c\x29\x69\xfc\x2b\x70\x21\x3a\xc9\xa1\xc9\x82\x24\x6a\x5c\xc1\x33\x3c\x98\xe6\xb8\xf6\x8c\x47\xa3\x7a\xe6\xb1\xc4\x1d\x1e\x33\xdf\x72\x88\x45\xf7\x04\xdd\x43\xcf\xc8\x70\x90\xff\x7f\xe6\x3e\x33\x53\x30\x32\x77\xe3\xd4\xec\x71\x12\xf5\x18\x75\x51\xc5\xa6\xdd\xa8\x9f\x4e\x33\x9b\x65\x87\xa2\xfa\x3b\xe7\x55\x92\xa1\x44\xa6\x70\x6a\xdd\xf6\xaa\x91\xd6\xdc\xe2\x56\x47\x97\xb6\xb4\xae\x4d\x69\x85\xc6\x9b\xa5\x89\x07\x0a\x05\xae\x88\x71\x57\xa4\x41\x66\x0b\xe9\xa6\xbe\xc2\x12\x79\x4b\xe3\x01\xf8\x5b\x03\xd6\x12\xda\xcc\xcb\x31\x00\xbb\x69\x43\x4d\x2e\x92\x41\x33\x05\x39\x4f\x26\xcb\xc7\x1c\x3d\x37\xf5\xd9\x4a\x6a\xe8\x22\x85\xb3\xdd\x59\xea\x88\x89\x52\x0b\x1e\xc6\x8b\x23\xb5\x90\xa2\x6f\xa7\xd5\xb6\x69\x06\x14\x15\x77\xc8\xf8\x32\x67\x79\x1a\x4b\xf6\x04\x2c\x87\xf8\x75\x7b\x7d\xb8\x25\x4a\x9c\x50\x88\xdb\xbf\xd9\x34\x5c\x0f\xa8\x1f\x7f\xb3\xb3\x77\x83\xc8\xf6\xc9\x2d\x28\x6d\xbb\x70\x21\xe5\x71\x66\x5b\xbe\xc5\x2d\xa4\x15\xb7\x74\xd8\xed\xfc\xf0\x39\x1c\x6e\x4a\xdb\xb3\x44\x21\x0b\xaa\xc7\x99\x4b\xd5\x22\xfb\xf2\xb7\xa1\x2f\x2f\x95\x0e\xbe\x01\x75\xc4\x5f\x44\x6d\x6e\x59\x7c\x95\x34\xc9\xcf\xf8\x50\xbb\xc2\xca\x3e\x7c\xc3\x1e\xfa\xe3\x81\x35\xd8\xc5\x76\xf4\x95\x14\x0e\xda\xee\x9a\xe4\x2e\xe5\xae\x4d\x76\x21\xe0\x89\xd8\xc2\xc5\x15\x09\x7b\x3a\xbc\x42\xc6\x60\xcf\x74\xdb\x73\x79\x77\x52\x31\x96\xf6\xcd\xe8\xd2\x0a\x6c\xb1\x0a\x06\x2b\xd6\x90\x04\x4e\xc5\xbc\xa2\x2f\x71\x5f\x67\xc8\x01\x20\x8c\xf9\x51\xdb\x97\xf4\xf8\x06\x1a\xef\xa2\x19\x4d\x06\x02\x15\xac\x43\x2a\x9d\xad\xa9\x61\xa6\x02\xdd\xa5\x37\xb1\x9e\xf8\xee\xa0\x0f\xfe\x13\xf8\xf1\x3d\x2b\x88\xbf\x75\xc6\xfc\x2d\xea\x89\x6d\xcc\x70\x51\x45\xf1\x9d\x18\xe3\xbd\xa3\x68\x2a\x8a\xef\x8b\x71\x57\xd4\x13\x7f\x75\xde\xfd\xd5\x95\xc5\x5f\x7f\xab\xf0\x14\xdb\x1e\xc7\x09\xed\xfe\xf6\x8e\x4a\xfa\x70\xf7\xfd\x85\x6d\xeb\x90\xc7\xb7\xe2\xee\x51\xa6\x20\x2f\x54\x79\x22\xd3\xa5\x9c\xd2\x92\xe5\xaf\xbc\x39\xf3\x3a\xad\x6f\x35\x29\xe5\xbd\xe7\xa0\x5c\x34\xf7\xa4\x92\x73\xd2\x40\xcc\x4c\x3f\xa9\xa5\x9d\xe4\x15\x1d\x89\x27\x41\x3f\x5a\x00\x17\x3f\xd5\xe4\x93\xef\x82\xfc\xc2\x43\x96\x14\x94\xc5\xf1\xfa\x6d\x32\x08\x46\x68\x92\x8c\xae\x87\xd1\x08\x25\x43\x44\x37\x2d\x76\x8a\xb7\x1c\x79\x59\x6c\xfb\x2d\xb5\xa0\xd6\xb0\xc2\x98\xc4\xeb\x3d\xf2\xfe\xe6\x85\x19\x3b\x48\xb2\xb5\xec\xff\x66\x30\x35\xb0\x11\x9c\xf6\xc9\x0c\xea\x44\xbc\xb7\x32\x49\x93\x3c\x21\x9f\xd0\x16\x39\x7d\xe8\x05\x58\x3d\xb4\x85\x62\x7c\x45\x10\x28\x87\x10\x4f\x47\x23\xc7\x42\x11\x18\x14\xcb\x44\x8a\x77\x64\x8b\xe4\xc9\xe7\xa4\x5c\xc9\xed\x54\x6c\xbf\x8d\xfa\x69\x90\x5e\xcf\xd3\x91\x4b\xf9\x41\x9d\xa0\x20\x5b\x28\xd3\x7a\x12\xe1\x82\x77\x39\x18\xa1\x28\xbe\xc0\x69\xa4\x04\x70\x55\x22\x3a\xe8\x79\x46\xcd\x08\xa3\xe6\x74\x56\x08\xfb\xc7\x63\x0c\x83\x7b\x9c\xf0\x33\xb8\x08\x72\x8e\x10\x0b\xe5\x41\xc5\x20\xe3\x54\x89\x50\x59\x1c\x40\x2e\x77\x25\x97\x38\x4d\xa3\x10\x67\xe8\x03\x55\x88\x44\x38\xa3\x0c\x7c\x72\x8d\xa2\x98\x65\x33\x2e\x10\xa8\xd0\x82\x9e\xab\xe1\x64\x51\x00\x86\xcc\xe5\x28\xb7\x48\xd4\x40\x32\x51\xef\xae\x4f\x28\x09\x2b\xd2\x4d\x89\x49\xa2\xec\x2f\x16\xe1\x51\xb8\x89\x9e\x41\xa6\xac\x67\xba\xe1\x88\xbd\x4d\xf2\x37\xc6\xf9\x45\x12\x96\xfa\xc8\x4b\xa5\xf5\x18\xf9\x36\xc7\x33\x84\xcc\x70\x86\x14\x7d\xc5\x20\x9b\xcf\xab\x33\x88\xe1\x24\xb8\x8a\xcd\x2f\x12\x23\x21\xc2\x42\x91\x56\xcf\x65\x4e\xbc\x3d\x3d\x1f\xe3\xd8\x62\x3a\x4c\x76\x94\x72\x2c\x50\xc1\x7c\xd8\xb9\xab\x28\x6f\x4d\xff\x60\x45\x80\x99\x49\x71\xd7\xaf\x48\x38\x96\xa6\x76\x9c\xbe\xe3\x4d\x5e\x04\xd9\xe1\x55\xcc\xc8\xfe\xba\xf6\x8c\xd4\x7c\x56\x17\x3e\x4f\xe4\x11\x36\x41\x5e\x9e\xbc\x98\xdb\x0f\x5a\xab\x74\xba\x2d\xb5\xfe\x9f\x6c\x3a\x21\xa2\x56\x1c\xe5\x2b\x01\x11\x4e\xd9\xd6\x17\xa4\xe7\x53\x32\xba\xd6\xf1\x40\x96\x0c\x0a\x25\xe3\x54\x78\xdc\xa6\xcf\x32\x54\x70\xf4\x88\x2a\x85\xf9\xa4\xd3\x55\x6a\x42\x90\x3b\xa8\xec\x07\x8e\x6d\x07\x71\xc5\xf8\x10\xa7\x38\x1e\x90\x06\x60\x9c\x27\xfa\x7a\x35\x86\x81\xc9\xc5\x36\x80\xce\x7d\x06\xd9\x52\x63\xd8\x98\xea\x2e\xac\x94\x4c\x66\x9a\x54\xe5\x3d\x8d\xe9\x38\xc0\x04\xd2\x55\x6b\x86\x40\xdd\xe6\xf3\x51\x64\xb0\xa9\xd5\xc5\x35\x1c\x11\xa5\x21\xa4\x1c\x00\xa9\xd5\xff\xca\xbc\x92\x47\x2c\x47\x5b\x8c\x6d\xf2\x3b\x8b\xb9\xbc\x88\x96\x2b\xe7\x78\x66\x23\xb0\xe4\x8a\x38\xd9\xe6\xca\xe5\x11\xd4\xa5\x35\xc2\xdf\xa9\xeb\xc4\x49\x35\xbc\xf8\x6d\xc8\xa6\xcc\x5d\xdd\x31\x57\xe8\x90\x31\x33\x96\x24\x00\x48\x0a\x4c\xe8\xc3\x10\x65\xc9\x18\xd3\xd4\x53\xe8\xea\x02\xc7\xe8\x3a\x99\xa6\xc2\xcc\x3e\x20\xe2\x2c\x05\x7e\xcf\xb1\x73\xef\xba\x0b\xea\x8e\xce\x65\x7b\x19\xa2\x0c\x60\x65\xc5\x1c\x19\x31\xf4\xb7\xdc\xee\xe6\xa2\x51\x69\x4e\x7b\xc9\x84\x08\x3b\x93\x42\xee\x61\xf2\xce\x1d\xc4\x29\x09\x18\x68\x98\x14\x99\x6a\x0c\x9a\xc8\x7b\x9e\x52\xb6\x3a\xe9\xfe\x59\x55\x7e\xb9\xe5\xb8\x43\x23\xca\x25\xb6\xe8\x9f\x75\x8d\x8b\x88\x87\xfc\xb2\xed\x7d\x30\x06\xa3\x89\x39\xf5\x10\xdb\xaa\x8b\x62\xfa\x66\x2d\x03\xac\x97\x6e\xb1\x64\x3a\x4f\xe5\xe2\x67\x68\x4b\x6a\x5f\xfd\xb4\x40\xea\x22\xc7\x26\xbb\x8b\xae\x92\xf8\x59\x4e\xe5\x67\xee\xee\x28\x05\x2f\x1c\x25\xc9\x04\x05\xfd\xe4\xd2\xb2\x0d\x96\x77\xf9\x19\x87\xf6\xcc\xdd\x61\xe0\xa2\xa2\x55\xb9\x9f\xe2\x6d\x85\xbc\x5a\x95\x16\x8f\x38\x9c\x40\x4f\xc1\xfe\x65\x91\x75\x63\xdb\xf8\x06\xa3\x24\xc6\x0f\xc0\xf1\x00\x2e\xda\x2a\xf6\x10\x78\x51\x61\x27\x23\xc5\xe6\x6e\x64\x72\x2e\x12\x55\x38\xe2\xfc\xd4\x6a\x4f\x66\x3f\x23\x5b\x6f\xf7\x63\x14\x80\xe7\xad\x16\x8b\xb0\x34\xb2\x90\x11\xe7\xbd\x1c\x84\x2d\x3c\x8d\x30\x7e\x50\xc3\x21\x66\xd1\x79\x1c\x0d\xa3\x41\x10\xe7\x2c\xa0\x64\x44\x7b\x0f\x20\x69\x3b\xb6\x63\xf2\xcf\x92\x07\x31\x3d\x2b\xcb\x6f\xee\x21\x6c\x8c\xd9\xbc\x4e\x16\x8e\x30\xf8\xb2\xe9\xd5\x9c\xb1\x46\x56\xb3\x30\x31\x52\xda\x0d\xc6\xdc\x41\xc3\xf7\x96\xea\x45\xf6\xcf\x56\x36\x76\xc3\x16\xc6\xa1\xfd\xaf\x0e\xe0\xb4\x31\x6b\x34\x1a\x7e\xa3\xd9\x68\x79\xa8\x31\x6b\xb4\x1b\x9d\x46\xb7\xb1\x76\xf6\x60\x80\x3d\xd4\xad\x1c\x7a\x85\x85\xaf\xe3\x33\x62\xac\xd8\x2b\xe6\x10\x0c\xcb\x95\x3f\xd0\xff\x7e\xf9\x02\x31\x7b\x35\x51\x63\x88\x6a\x62\x7a\xbf\xdb\xb2\x28\x0a\xe5\x3f\x80\x2a\x19\x0d\xf1\x9f\x95\x8d\x49\x75\x00\x94\x3c\x46\x38\x3e\xcf\x2f\xa8\xe9\x91\x93\x8b\x54\x8f\x19\x53\x2c\x94\xc5\x22\xc5\xec\xc6\x83\x24\x24\xf4\x8e\xe9\x0f\x9d\xdc\xe1\x75\x79\xec\x4f\x41\x00\x38\x1e\xac\xec\xe3\x99\xbb\xcd\x79\x01\x64\x2a\xad\xf6\x85\x83\xbb\x14\xc4\x5a\x21\xb2\x8b\x25\xae\xc1\xbc\xb0\x2e\x96\x2a\xca\x90\x7c\xcc\x87\xeb\x0b\x45\x73\x61\x53\xe1\x8c\xe5\xc2\xa7\xea\xcb\x17\xb4\x8f\x67\xa5\xe1\x5b\xe6\x10\xd0\x20\xc8\x71\xcc\xf6\x7c\x95\x82\x1c\xcc\xdf\x4d\x48\xd2\x3d\x6c\x31\xe0\x27\x8c\x1b\x4a\x94\x09\x69\x7e\x17\xbd\xd7\xad\x8a\x4b\x15\xda\x10\xd8\xf9\x3c\x7e\x86\x78\xd3\x74\xa7\x34\x83\x92\x3a\x53\xa2\x81\x9d\x17\x0b\x47\x42\x06\xf6\x67\x83\x61\x59\x7c\x15\xf3\x8b\x40\x84\x3a\x28\x48\xcc\x5d\x3a\xca\x8e\x0b\x1e\xa3\xf0\x1c\x07\xf0\x63\x95\x25\x51\xf8\x45\x1d\xa3\x53\xbd\x51\x30\x9e\x20\x3c\x83\x48\x92\xfd\x48\xef\x1c\xbd\x57\x25\x65\xcc\xdb\x06\x7a\x9f\x3a\xb0\x05\x49\x51\x10\xff\x87\x23\x50\x3a\xd4\x27\x22\x69\x8c\x61\xab\x45\x41\x8e\x02\x94\x47\x63\x8b\xc4\x6d\x0b\xc9\x2e\x77\xd7\x9d\x14\x42\x1e\x1c\x52\x14\x6d\x11\xf4\xd8\x2c\x9c\x46\x3c\x2a\x36\xf9\x4f\xad\xd9\x46\xcb\xa8\x16\x51\x8c\x9f\xa3\xf5\x7a\x5d\x44\xcb\x76\x4a\xf1\x14\x8e\xda\xe3\x25\x14\x89\x70\xdb\x5f\xb6\x8a\xa6\x5f\xbe\xe4\x6d\x58\xca\x8b\x46\x2b\x08\xfe\xce\x6d\x49\x1e\x53\xba\xb8\xee\x34\xa6\xee\x28\xf7\x55\xbb\xbf\x85\xcc\xc1\xae\x92\x31\xd8\xa4\x42\xb1\xd9\x2e\x6d\xa9\x68\xda\x72\xac\x04\x51\x1c\xf4\xf5\x93\x87\x74\x00\xa8\xca\x4e\x69\x0c\x0e\x22\x04\x2a\x82\x61\x94\xdf\x55\x14\x2c\x16\xa7\x58\x5d\x0e\x26\x45\x3e\x57\x0d\xdd\x6b\x61\x4d\xa6\x1c\x65\x8b\x8b\xe4\x64\x32\x76\x86\x61\x11\xd5\x4e\x05\x0c\x1e\x67\x7e\x0b\x96\x0e\xfd\x03\xd2\x6f\x35\x09\xe9\x67\x0a\x5f\xb0\x10\xbc\x22\x4a\x6d\xa1\x77\x41\x7e\xb1\x32\xc0\xd1\xa8\xa8\xb9\x8a\x16\x88\x48\x64\x3f\xff\x56\xda\x79\x1c\xe6\x48\xc6\xf1\xf7\xb6\x76\x9f\xec\xb8\x2b\xd3\x82\x71\xde\x55\x69\x61\xde\x39\x57\x06\x0b\x27\x35\x8a\xab\x1c\xfd\xdc\x3c\x39\xaf\x98\x34\xc2\xcc\xef\x1b\x4e\x93\x3a\x52\x6f\xf1\x29\x90\xc4\x86\x61\x34\x1a\xf1\xb0\xb3\xcc\x4d\x02\xce\x5b\xf3\x85\x12\x7e\x98\x8b\x6d\x87\x5e\x19\x94\xd3\xc5\xa7\xd2\x2c\x33\x48\x95\x08\xe5\xbe\x8c\xcf\x2a\x1c\xc1\x98\x2b\x88\xef\x3e\x69\xd1\x12\x32\x99\xc4\xf6\x23\x96\xcc\x1e\xcc\x03\x15\xf9\x9a\xaa\x37\xe4\xe3\x4f\x57\xee\x28\xf3\x9f\xae\xd0\x16\xf9\xd7\x91\x40\x6d\xfc\xe9\x77\xb2\xcd\xcc\x5a\x41\x88\xbb\xeb\x7d\x3d\xfc\xba\x28\x16\x64\x9f\x91\xcc\x39\x4a\xee\x09\x2a\xdc\xdd\xd1\x56\x6b\x8d\xd9\x46\xa3\xbb\x81\x9e\x93\x2e\xfc\x0e\x7b\xfa\xde\xde\xde\x5e\x1d\x2d\xd1\x17\x3f\xfe\x88\x1a\x33\xbf\x01\xdb\x3d\x41\xc0\xb1\xdd\xd3\x2e\xd6\x1a\xb3\x76\xb7\xd3\xa0\xc0\xae\x74\x60\x57\x55\x81\xc1\xf0\xe2\x6c\x0a\x9e\x3e\x35\x40\xe3\xe5\x4b\x5a\x13\x2d\x21\x18\xe9\xd2\xfa\xac\xee\xea\x16\xd4\x61\x7f\xe5\x65\x97\xb6\x50\x63\xa5\xe3\x2c\x03\x63\xca\x8a\x3e\xa7\xf6\x36\x9c\xda\xea\xe8\x47\xb4\xd2\x41\xff\x85\x7c\xb4\x89\x96\xfd\x2a\x22\x8a\xc1\x39\x54\x71\xc3\x43\xe9\x20\x18\x5c\x60\x96\x5d\x67\xbe\xc0\x41\x6a\x7e\x22\xf4\x98\xd6\x6a\xb4\x2a\x39\x2a\x29\x48\x92\xdd\x44\x1a\x0c\xfb\x15\x13\xad\xba\x85\x3e\xa5\x35\x5a\x1e\x08\x72\xad\xbf\x66\xe9\xd3\x55\x91\xc3\xa7\x26\xca\x17\xf0\xd1\x17\xd4\xa8\x18\xd6\x3c\xc6\x57\x92\xb3\x13\xdc\x3a\x32\x05\x48\xcc\xd3\xf7\x3c\xd1\x46\xd2\xee\x7c\xca\x8e\xf6\xf3\x0c\x69\x70\x3c\x00\x43\x1a\xfa\x5f\xbb\x21\xcd\x3e\x9e\x99\x9a\x00\x1b\x38\x52\x70\x8b\x02\x5d\xa1\xbf\xab\xc5\xdf\xd4\xd5\x17\x17\x78\x56\x59\x85\x51\xe1\xe4\xb9\x60\x54\xcd\x4a\xad\xdf\x17\x23\xbf\xc0\x33\x33\x84\x26\x1b\x3f\xe9\x68\x3f\x3f\x91\x90\x35\x70\xe6\x6d\x8f\xa9\x57\x95\x4f\x9e\xd9\xa2\xc7\x48\x3a\xeb\x26\xa0\x0b\x3c\xeb\x5d\x04\x69\xe5\x3c\x5b\xd9\xdc\x03\x1d\xe4\x48\x8b\xe8\x41\xee\xea\x8e\x87\x38\x8e\x1d\x5b\xe3\x00\x96\x00\x69\xd7\x0b\xb5\x8f\xdf\xad\xdb\xf8\x9d\xad\x2a\x69\xa7\x31\x2c\xaf\xeb\x60\x10\x02\xdc\x6f\x49\x14\xd7\x9e\x3d\xbb\x45\xc4\x4d\x89\xc2\xe9\x7a\x5b\x44\xd3\xc3\x57\x0a\x25\xdc\xea\x0b\xc6\x21\x3c\xfd\xf9\x52\x13\x5f\x6c\xd4\x66\x5b\xac\xc7\xea\x91\x32\x69\x95\xc5\x12\xa5\xd0\x3a\x6f\xf9\xd1\x85\x3e\xb2\xa3\xcc\x22\xab\xe6\x6a\x91\xd4\x74\x72\xa3\x6c\x0b\x6d\x96\xe4\xc7\xa4\xab\xa5\x05\x9a\x09\xe8\xf4\x41\x9c\xb3\xce\xae\x64\xd3\x7e\x96\xa7\xb5\xc8\x43\xcd\xba\x07\x49\xf8\x0a\x95\x05\x59\x51\xeb\x75\x9b\x03\xee\xc2\x7b\x9e\x32\x4c\xab\xa8\x59\xd5\x7d\xf6\x6d\x90\x47\xb1\x5f\x6d\xd3\x62\x65\xf9\xbe\x25\x1e\x6f\xb7\x75\xb1\xea\x7f\xde\xee\x55\x15\x81\xfb\x5a\x53\x23\x68\xcf\xbe\x87\x51\x5c\xfe\xa3\xb6\x31\x3a\x1c\xdf\xf0\x4e\x26\x21\x48\x77\x24\x3a\x75\x2b\xc3\x34\x19\x93\xb7\xbd\x24\xc4\xb0\x49\x55\xdd\x90\x64\x80\x77\xd8\x93\x14\xba\xbd\xfd\xb6\x24\xc8\x71\xa1\xc5\xf0\x4d\x6f\x4e\x6c\x15\xd1\xfd\x49\x5e\x6e\xd5\xb7\x28\x51\x6b\xb1\x5d\x4a\x54\x13\x1b\x95\x78\xf3\xd0\x7b\x95\xd6\xf4\xbc\x5c\xce\x91\xa4\x45\x2f\x7a\xbb\x32\x60\x04\xbd\x9d\xd7\x22\xbe\x26\xf4\xad\xca\xae\x5b\x5c\x78\xab\xd2\x10\xae\xba\x53\x7d\x3c\xd9\x5b\x5e\xaf\xb6\x51\x7d\xcc\x87\xeb\x62\x9b\x62\x0f\xb7\xdb\xa4\x68\xa3\x7f\xde\x1e\x55\xb1\xfd\xfb\x5a\x59\xd3\x7c\xb8\x6e\xdf\xa0\xc8\x28\x3e\xe4\xf6\x94\xa7\xd7\x25\x06\x46\x21\x26\x47\xf4\x8f\x47\x07\x3d\xee\xe9\x54\xc3\xd9\x20\x98\xe0\x5a\xc9\xc6\x69\xb2\x65\x34\x08\xf2\xc1\x05\xaa\x99\xe9\xa3\x01\x85\x8b\x34\xb9\x02\xba\x85\x8c\x2b\xb5\x67\xef\x82\xd1\x30\x49\xc7\x38\x64\xd3\x10\x06\x79\x60\xa6\xa0\x5b\x9c\x81\xcb\x93\x7a\x7b\xfe\xcd\xe6\x6a\x11\x32\xf9\xa6\x99\x37\x50\x18\x65\xdd\x05\x19\x56\x67\xdc\xac\x8e\xcb\x18\x40\xd9\x1a\xa6\x31\xa3\x1e\x6a\x21\xa0\xd0\x15\x87\x53\xaf\x1c\x80\x46\xa4\xe0\x85\x5c\x98\x38\x64\xd9\xcc\x24\x2f\x74\x67\x26\x5e\xc9\x4e\xf6\x5a\x4a\x89\x36\x9e\x66\x39\xea\x63\x14\x91\x11\x1d\xe3\x38\xa7\x79\xd6\x02\xb8\x5e\x4f\x71\x2e\x3c\x16\x2a\xe5\xf6\xd5\xf2\x74\xaa\xca\x7d\x9a\xe3\x90\xba\x56\x15\x09\xe2\x3f\xe3\x49\x8e\xa6\xf1\x84\x27\x0d\x54\xb3\x83\x4a\x36\x2d\x0d\x0b\xf7\x7d\xc5\xc6\x01\x32\x0d\x6e\x8b\x51\x10\x5e\x62\xae\xcf\x15\xcd\xe0\x20\xbb\x2b\xb3\xe6\xd1\x46\xfa\x19\x4b\xa2\xcd\x92\x98\xe6\x09\x8a\xf2\x8c\x7b\xc5\x20\x42\xc1\x77\xbd\x63\xea\x5b\x91\xa7\x09\x71\xdd\x97\x4c\x95\xb2\xee\x32\xf3\x3e\x04\x56\xca\x36\x9b\x01\xc8\xc0\xc9\x3c\x15\xb5\x9d\x55\x67\x4a\xb4\x7c\xbc\x13\xe4\x01\x17\xd6\x1b\x55\x25\xcd\xed\x30\xcc\xa0\x0d\x9e\x17\xdc\x31\xd2\x8c\x16\xaa\x6f\x8a\x22\xc8\x82\x91\x79\x9c\x19\xbb\x20\xba\xe6\x99\x13\x00\xe5\x97\xd4\xa7\x24\x90\x2c\x28\xa9\x3d\x31\x70\xbc\x87\x99\xcc\x4f\x14\x9d\xda\x33\x93\xdf\x57\xaa\x37\x7f\x6f\x64\x25\xab\x24\x33\x37\xdd\xeb\x8b\x74\x74\x72\x40\x51\x69\x80\x58\x30\x51\x15\x94\xec\xe3\x0c\x64\x34\x27\x4e\x24\xa3\x35\x89\x29\x03\x86\xf3\x23\xa5\x6d\x43\xd7\x5c\xe4\xcb\x4d\x89\x6c\xc0\x0c\xa2\x5d\xda\x52\x93\xa4\x57\xa5\x60\x9e\xeb\x34\x43\xc1\x65\x10\x8d\x20\x62\x17\xe5\x0b\xc0\xec\xdc\x54\x73\x22\x39\xab\x44\xf1\x65\xf2\x19\x67\x7a\x92\xe1\x1a\x4b\x0e\xec\xa1\xab\x8b\x68\x70\x61\x65\xd5\xfd\xeb\x12\x56\x6d\xb6\xca\x17\x4a\x3f\x49\x46\x38\x88\x6f\x50\x98\xec\x8d\xa6\xd9\x05\xfa\xf9\x02\xe7\x34\x9e\x09\xcf\x45\x0b\xee\x5a\x93\x20\x05\x46\xc1\x5e\x15\x5c\x5b\xb0\xeb\x5b\x84\x03\x11\x9c\x1e\x46\xfc\xee\xdb\xbc\x00\xb8\x43\x09\xc9\xb5\x66\x78\xaa\x5c\x57\x5c\x8e\x05\xc1\xd8\x33\x05\xab\xb1\x56\x69\x51\x65\xf1\xd1\x01\x5f\x50\x67\xc2\x96\x48\x41\xdc\x16\x6d\x09\x79\xcd\x8d\xd3\x60\x64\x5d\x6a\x15\xf2\x51\x32\x34\x73\xd1\x3d\x2f\x5e\xc8\x0a\x5b\x5a\x4a\xe6\xb2\xc2\x1c\x7a\x51\xdb\x1e\xd1\xaf\x97\x4c\xe3\x9c\xd3\x97\x85\x99\x10\xa0\x31\x4d\x24\x7c\x04\x71\x8b\xb7\x54\xfc\x57\xb5\x26\x5f\x98\xbc\xc8\x35\xe4\x0c\x83\xa3\x64\x1a\x87\x68\x3a\xa1\x0e\x85\x83\xd1\x34\xc4\x1a\xdd\x9b\xd5\x34\x8c\x0a\x23\x17\xf9\x43\xf5\xd8\xb6\x02\x8b\x30\xb9\x8a\x65\x3c\x92\x78\x74\x8d\x86\x53\xb1\x28\x2d\x91\xf4\x57\x57\xd1\x08\x67\xd4\xa9\xd2\x2e\x6b\x01\xdf\x48\xf1\x38\x88\x62\x55\xb8\xaa\xd6\xaf\x71\x30\xab\x29\xfd\x82\x8b\x53\xb4\x6c\xcb\xcc\xee\xcd\xbf\x52\x15\x73\x4e\x35\x0f\xae\x29\x07\x4a\xe6\x78\x28\xad\x3f\x47\x12\x01\xba\xe8\x09\x68\xc3\x49\x4e\xe4\xab\xda\xc7\x28\xae\xc9\x4d\x3e\x47\x6d\x4f\xa1\x33\x9b\xf9\x24\xcf\xe0\x6d\x23\x12\x42\x77\x12\xc0\x72\xb7\x2d\xca\xe7\xa9\x9a\x85\xfd\x7e\x29\x8f\x80\x78\xbb\x24\xad\x27\xa7\xd1\x04\xc1\x0c\xa7\xe4\x34\x29\x36\x86\xe5\xe2\x80\x00\xce\x90\xf6\x8a\x8c\xbb\xa8\x7b\x90\xe0\x2a\xb6\x5c\xf5\xae\x39\x46\x4a\x0a\xac\x82\xe1\xc3\x94\x9b\x45\x15\xee\x2b\xb3\x30\x3d\x19\x96\x3c\xa2\x16\x34\x14\x4e\x86\x96\xb7\xe4\x99\x9e\x4f\x95\x3c\xb6\x68\x19\xb6\x6e\x85\x93\x8a\xbf\x27\x37\x7d\x57\x63\xb7\xca\x59\x28\x4b\x9d\xbc\xee\x68\xe5\xe6\xd8\x0d\xff\x24\x93\xb7\x4f\xc6\x86\x58\x60\x62\x9d\xb1\x52\x8b\x37\x95\x87\x89\x93\xa6\x23\x13\x3d\x3f\x83\x5f\x04\x19\x64\xc8\x75\x9e\xb8\xe7\xa6\x22\x2f\xd8\xb5\xec\x03\x45\x27\x9d\x41\xa7\x61\xd7\x70\x86\x92\x58\x3a\x0a\xfb\x5d\x54\xeb\xf8\x4d\xb0\x64\xad\x5b\x8e\xc5\xfb\xb4\x32\x3f\x06\x8b\x47\xfb\x79\xf8\x5e\xa2\xbe\x96\x65\x20\x2b\x0d\x98\x5a\xe6\x6a\x46\x07\x61\x81\x9c\xe4\xb7\x8d\x6e\x47\x1a\x42\x34\x44\xf2\xbc\x20\x77\x95\x6d\x48\xc4\x1c\x28\xa1\xdb\x8e\xf7\xb7\x9b\x9d\xae\xdd\x49\xac\x2c\xd5\xf5\xad\x23\xac\xf1\xd8\x6a\xd5\xc3\xac\x1d\x63\x11\xde\xc3\xad\x21\x30\xd5\x10\x73\x2c\xb1\x0b\x4d\x0a\x5f\x38\xf7\xaf\x32\x61\xf4\x72\x1f\x2a\x12\x40\x58\x56\xf1\xa8\x25\x1c\x2b\x09\x40\x2b\xcc\xcb\x94\x1a\xf4\xbd\x99\x0d\x87\x65\x63\xe6\x1b\xf2\xd1\x62\x63\xfd\x71\x12\x02\xcb\x90\x07\x9b\xa6\xe5\xaf\x9e\xb1\xcf\x19\x41\x98\x02\xd7\xe3\x08\x57\x76\x21\xa2\xac\x88\xf9\x0f\xcd\x5d\xde\x0b\xcc\xf9\x14\xf0\xaa\x3d\x63\x48\xd9\x74\x29\x6a\xc9\xf9\xaa\x13\x5a\x50\x26\x14\x65\x0c\x1c\xeb\xd1\xa1\x91\x60\x0a\x1b\x15\x82\x85\x3c\xd8\xf8\x12\x21\x9d\xe0\x6b\x03\x25\x9d\x63\x4d\xf1\xf7\xde\x7c\x27\xf6\x58\x92\x9b\x4c\xe0\xe2\x64\x90\xe8\x7d\x02\x28\x07\x39\xcd\x17\xcf\x6a\x16\x31\x43\x51\x94\x21\x3c\x1c\xe2\x41\x1e\x5d\xe2\xd1\x35\x0a\x50\x88\xb3\x3c\x9d\xc2\xb3\x07\x72\xfa\x72\x12\x0f\x70\xa5\x28\xa3\x15\x29\x54\x49\xf4\x00\x28\x15\x01\xb9\xa1\xc4\xe2\x9a\x0b\x32\x08\xf7\xb4\x33\xa0\x2d\x4e\x8e\x22\x99\x90\x43\x2d\xe1\x28\x5d\x46\xe8\x25\xd5\xe6\x53\x3d\x2f\xba\x10\xdd\xef\x59\xc6\xd7\x3c\x10\x95\x83\x41\xf3\xd6\xca\x3c\x01\x7e\x01\xce\x2a\x8d\x10\x67\xb2\x7b\xd2\x3c\x58\x17\x0f\x29\xef\x5a\x3c\x52\xf2\xbb\x8e\xdf\x5c\x6d\x35\xab\x89\xf9\x19\xd3\xf8\x28\xf1\xef\x03\x36\x69\xcf\x44\xe0\xa4\x28\xce\x71\x3a\x94\xac\x85\x91\x73\x55\x70\xfe\xca\xba\xce\xa9\x96\x6e\xb7\x2c\x3e\x62\x80\x2e\xf0\x68\x82\x53\x22\xfe\x54\x58\x04\x7b\x0c\x37\xe6\x1b\xac\xa3\xfc\x15\xee\xf1\xa8\xcc\xa4\x3b\x55\xd0\xae\xae\x7c\xa2\xbd\xda\x87\x2e\xd5\x6c\xc2\x96\x5b\x3f\x27\x57\x55\x8c\x07\x01\xb4\xeb\x7e\xcf\x58\x17\xf6\x00\xb8\x48\x3d\x2f\xb2\x95\x08\x87\x45\x35\x8b\x58\x91\xe1\x52\xa5\xf0\xc5\x8f\x8d\x56\x7a\x22\x2c\x79\xff\xdd\x76\xef\xfe\xe9\x89\x88\xd0\x3c\x28\x05\x69\x81\xd1\xd5\x5f\x82\xa6\xf6\xc7\xc1\xa0\x12\x5d\x8d\x83\xc1\x5d\x68\x4b\x54\xbf\x13\x7d\x7d\xc6\x76\x15\x92\x44\x5f\xbd\x4f\x80\x16\x99\x07\x4a\x64\xb4\x11\x5a\x77\x31\x62\x2b\x3d\xfe\x0a\x4d\xd2\x1c\x1f\x06\x82\x0d\x38\x31\xb0\x1f\x85\x17\x03\xcf\xd4\x02\x21\x7d\xdf\x05\xf9\x05\x0d\xeb\xfb\x84\xbf\x67\xc3\xfc\xa2\x88\xf4\x7b\x73\xe6\x75\xda\xdf\x6a\x78\x5f\x86\x4c\x8d\x87\x23\xae\xdf\x7b\xbc\x5f\x0e\x79\xd1\xb8\xbf\x02\x43\x39\xfe\xaf\x2b\xe8\xaf\xf8\x0e\xc1\x7f\x6d\x01\x74\xcd\x2b\x0a\x1e\x35\xb6\x98\x32\x89\x00\xa4\x68\xb0\xd2\xfb\x92\xf0\x34\x4a\x6d\xc9\x05\xc6\x15\x46\xb6\xdb\xae\x66\xa2\xc5\xca\x72\x23\x2d\xf1\x78\x3b\x33\x2d\x56\xfd\xcf\xb3\xd3\xaa\x8a\xc0\x7d\x71\xca\x3e\xb4\x67\x37\xd5\xa2\xb8\xfc\x0d\x6c\x89\x8d\xf2\xe3\x60\x22\x84\xc3\x71\x30\x59\x3c\xf6\x82\xc5\x45\xdc\x04\xe1\xb2\xca\xa4\x63\x7e\x5b\x83\x65\xb4\xb4\x85\x5a\x6e\x9b\xe5\xeb\x1c\xfb\x16\xa3\x65\xfa\xe7\x32\x5d\xa6\x7f\x4e\x03\x66\x0e\xb8\x59\x00\xae\x45\x68\x09\xf9\x75\x8b\x4d\x34\xff\x52\xc5\x32\x9a\x03\x6e\x69\x80\x9b\x4e\xc0\x4d\x2b\x60\x3b\xe4\x3c\x8d\x26\x23\xb8\x7a\xa9\xd1\x61\x79\xf9\x12\xfc\x26\xbe\xd0\xe7\x26\x79\x5e\x27\x8f\x80\x82\x0d\x8a\x98\x8a\xdf\xe8\x54\xd4\x7e\x43\x2f\x49\xeb\x3f\xfc\x80\x00\x9b\xdf\xd0\x73\xd4\x58\x59\xeb\x48\x33\x54\x7f\x81\x7e\x2b\x09\x77\x21\xcd\x3d\xb5\x05\x1f\x07\x13\xb0\x99\xdd\xce\x6b\x35\x8e\x30\x74\xba\x8b\x9e\xa3\x5a\x0b\x2d\xa3\xdf\xea\xac\xa7\xad\xa1\xd5\xdb\xc9\x88\xcf\x60\x2a\x2e\xc2\x90\xa7\xfb\x36\xa9\x91\x7d\x20\x28\xa1\x2d\x24\xa1\xd3\x35\x9c\x49\x20\xb6\x5e\x51\xdc\x6e\x1c\x7c\x11\x8d\x30\xaa\xc9\xfd\x64\xe1\x02\x5c\xb1\x46\xac\xc3\x22\x37\xb3\x78\x9f\x19\x67\x95\xa1\xde\xc1\x4e\x5e\xe1\xc9\xb7\xb7\xb3\x14\xac\x76\x21\x46\xff\x4d\x9b\x5a\xb2\x1d\x82\xda\xf5\xc8\x5b\x49\x75\x73\x4b\x51\x6b\xc1\xcd\x41\xd4\x13\x86\xf2\xe2\x8d\x30\x94\x9f\xcf\xf7\x8d\x12\x29\xbe\xc4\x69\x86\xdf\x49\x05\x8b\x57\xb6\xb8\x66\xdf\x15\x9f\x9d\xd4\x5d\x0a\xd4\xb6\x05\xf0\x3f\x9d\xff\x10\xf6\x43\x56\x28\xeb\x60\x29\xa7\x51\x1b\x3e\xe5\x0b\x9b\xd9\xe6\xff\x56\x3f\x43\x5b\xe8\xb7\x6a\xb1\x3a\x2d\x2c\xe5\xe0\x3c\x4e\x52\xfc\xd5\xb8\x8a\x04\xf2\x20\x0e\xc1\xcf\xb9\x98\xee\x88\xbc\x39\x1c\xce\xe3\x19\x52\x3b\x14\xc6\x77\x5b\x5b\x68\xd9\x9f\xc3\x93\x64\x0a\x93\x6b\xdf\x8a\x11\x5b\x45\x82\x54\xa4\xbd\xcc\xf0\xdb\x24\x99\x14\x4b\xc2\xd3\x71\xf0\xa4\x19\x55\x44\x0e\xed\xc6\x33\x98\x6c\xa2\x67\xdb\xaf\x7a\x3b\xbb\x7b\xaf\xf7\x0f\xfe\xf9\xe6\xed\xbb\xf7\x87\x1f\xfe\xef\xd1\xf1\xc9\xc7\x9f\x7e\xfe\xe5\x5f\xff\x13\xf4\x07\x21\x1e\x9e\x5f\x44\xbf\x7d\x1e\x8d\xe3\x64\xf2\xef\x34\xcb\xa7\x97\x57\xb3\xeb\xdf\x1b\x7e\xb3\xd5\xee\x74\xd7\xd6\x37\x96\x56\xb7\x58\x84\x5b\x71\xb4\x13\x8b\x76\x61\x54\x8b\x21\x76\x78\xa5\x14\x96\x1b\x8a\x85\xa9\x4d\x14\xd2\xda\xb1\xb9\xa9\x90\x99\x8e\x1c\xfb\x0d\x73\xec\xca\x88\x90\x24\x2d\x8f\x82\x9a\x64\x07\x16\xb4\x8c\xfc\xfa\x19\x78\xaf\x14\x02\x53\xd3\x24\x2e\x0e\xb4\x59\x05\x68\xfd\x8c\x6f\xf0\xb2\x18\x66\x81\x4a\x05\xa2\x58\x89\xdc\xf3\x85\x08\x33\x80\xfe\x17\xda\xa2\xec\x5b\x13\x97\x07\xef\x41\x6c\x88\x97\x96\x94\x0f\x82\x6c\xc5\x0f\x46\x91\x46\x6c\x49\x6b\x58\x84\x9b\x22\x77\x8f\x7e\xc8\x97\xf6\x88\x17\xce\xcc\x3e\x9d\xc7\xa3\xff\xe3\xd1\x5f\x1c\xfd\x3f\x9e\xec\x2d\xfb\x5d\xf4\x6a\xb7\xb2\x83\x96\xdf\x7d\xb5\x2b\xfb\x68\xf9\x5d\xf5\x09\xbe\xde\xde\x69\x8b\x22\xf3\xe7\x3a\x6e\x55\xc4\xe1\x1e\x9d\xb7\xfc\xae\xd3\x7b\xcb\xef\xfe\x0d\x34\x02\xd5\x0f\xeb\x30\x18\x77\x39\xab\xdb\xfd\xfd\xc1\x32\x2a\x09\xf1\x87\x24\x8a\x73\x97\x93\xb1\xdf\x75\x38\x19\x5b\x0f\xd3\x05\xa6\x6e\x2f\x63\xd1\x64\x55\x57\x63\x09\xe8\x1d\x4e\x50\x3a\x11\xdf\xc9\x59\x0d\x68\x73\xd1\xb5\xf1\x4d\x1f\xa3\xe8\xaa\x12\x2e\x6b\x7c\xf1\x2d\xe4\xb3\x06\x95\x16\xf3\x35\xe6\xb5\x84\x7c\xcb\x5f\x3c\xb4\xa7\xb1\xda\x70\x35\x47\x63\x1f\x64\x1f\x81\xa1\xea\x66\x4c\x44\xa0\x62\xb1\x34\xc9\x62\xd1\x82\xb0\xb9\x29\xdc\x25\xe5\x68\xa3\xf3\xbc\x7a\x28\x0c\x46\x96\x6f\x2b\xec\x61\xd2\x3e\xf5\xf6\xce\xfb\xd4\xdb\x6f\x60\x9f\xaa\x82\xc3\x7d\xef\x53\xd6\xe5\xf4\x76\xf7\x71\x9b\x12\x7f\xf7\xb6\x4d\x65\x57\xc1\x64\x37\x0e\xa3\x20\xae\x2d\xba\x63\xd9\x8e\xe4\xdf\xfe\x96\xf5\xf6\x61\xb6\xac\x2a\xcb\xe4\xdb\xdf\xb2\xde\xee\x6a\x9b\xd6\xe3\x8e\x65\xec\x58\xd2\x8a\x59\x68\xf3\xfa\xaa\xbb\x97\x98\x17\x09\x5b\x02\x48\xe9\x23\x8f\x86\x0f\x5f\xd8\xdd\x09\x5d\xdc\x8d\x06\xf9\x7f\xb8\x58\xa1\x1f\x49\xf7\xd9\x57\xfa\xad\x58\xfe\xf3\xd4\x05\x40\x58\x6e\x6d\x41\xf7\x4e\xda\x02\x96\xa3\xf6\x6b\x2a\x0d\x3c\x24\xbd\xca\x2e\x02\x5f\x7b\x75\x31\x0e\x06\x0f\xa8\x5a\xf0\x10\x6f\x16\x7e\x41\x6b\x7f\x07\x75\x83\x91\x2f\xf6\x16\xaa\x08\xc5\x88\x45\xfa\xf2\x6e\xa7\x03\x35\xc1\xe4\xe6\xdd\x4e\xc7\x26\xe3\x81\x89\xf3\x67\x7c\x4d\xb3\x60\x53\x3b\x58\xd1\x57\x70\xfe\x0d\xe2\x9c\x27\xf1\x4e\xd2\x31\xb5\xd1\xde\xfd\xe9\xc3\x27\xd8\x74\x4f\x92\x37\xb8\x10\x06\xd1\xd5\xd5\xd5\x4a\x32\xc1\x71\x96\x8d\x56\x92\xf4\x7c\x35\x4c\x06\xd9\x2a\x24\xe1\x4e\x56\xb5\x3a\x17\xf9\x78\x64\x51\x84\xec\x5e\x4e\xde\xec\xec\x15\x68\x8b\xe7\x8a\xc1\x10\xe6\xfb\x80\x68\x7b\x9c\xe1\xfd\xc2\x52\x9e\xc3\x1e\x45\x06\x26\x23\x0f\x51\xcc\xdd\x5e\xa4\x70\xcf\x85\xab\x4b\x1b\xd5\xfc\xe6\xba\xe2\xe9\x62\xc0\x77\x18\xa9\xc9\x61\x31\xf4\x04\x29\xef\x76\x3a\xf3\xb0\x8d\x72\x66\x8b\xac\x07\xa9\x96\x3e\xe4\x09\x9a\x50\xab\x53\xd9\x3b\xc7\xb1\xc3\x19\x7e\x31\xda\xee\xc0\x86\x67\x13\xf9\xcd\x75\x30\x21\x55\xbe\xd2\xce\x01\xe6\xda\x97\x02\x1f\xa5\xed\x9b\x5b\xbb\xdd\x38\x88\xf6\xa1\xfd\x70\xb0\xd4\xe8\x3d\x98\x59\x7f\x0e\x87\x86\xf7\x0d\xa5\xf9\x39\x29\x9a\xe6\x57\xfc\xa3\x98\xab\x75\x2d\x9f\xdf\x6d\xc1\x78\xea\x34\x36\x1a\x0d\x1d\xf0\x82\xde\x41\x73\xfd\x7e\xaa\xc9\xbb\x3b\x90\xc2\x9f\xd0\x08\xa1\x0a\x48\x84\x1d\x40\x06\x56\xb2\x68\x6f\x63\xa5\xcf\xeb\xd2\x58\x00\x36\x40\x25\x95\xb3\x60\x94\xa3\x6d\xf8\xcf\xe2\x62\x31\x50\x17\x25\xef\xfb\x20\x2f\x4c\x36\x8f\xcf\xe1\x70\x85\xba\x45\xe0\x1a\xef\x8c\x07\xf8\x95\xe4\xad\x81\xe2\x4a\x7e\x47\xb5\xe6\x42\x02\xaf\x3a\xc5\x16\xf1\x96\xac\x74\xc6\x3d\xcc\xda\xc2\x4b\x8d\x90\x07\x33\x51\x2e\x56\x87\x15\x96\xcb\x2d\x0c\x42\x0b\xd0\x21\x7e\x03\x63\x63\x4b\x89\xb6\xc8\x19\xb9\x00\x26\x7c\x82\xc5\x1b\xe7\x71\x99\xef\x31\xb4\x47\xec\xc9\x52\x4e\x62\xe2\xb4\x68\xf1\xc2\x82\xe5\x6b\xb6\x31\x11\xf0\xea\x47\x66\xcc\xa2\xe1\xca\x0d\x5a\x5e\x72\x7c\xac\x47\x01\x22\xc6\x81\xe7\x80\xf3\x82\x59\x75\x59\xa2\x65\xe7\x5f\x2b\x23\x39\x18\x43\xe1\x04\xc2\xa0\x70\x62\x93\x8c\x82\x0d\x7a\x55\x9b\x17\xfe\x74\x66\x09\x42\x13\x62\xe0\xcc\xcf\xca\x41\xc9\xa7\x07\x25\x69\xa0\x4b\xd3\xfe\x68\xd8\x0b\x64\x9d\xa3\x60\xc3\xd8\x32\x54\xe6\x3b\x89\xac\x58\xcc\x18\x6b\x1b\xda\x28\x4b\xb5\x24\x1d\x0d\xa7\x3f\x4b\xb4\x0b\x11\x60\x8e\xd7\xab\x6a\x73\x5d\x89\x07\xcb\x7e\xc7\xb7\xe2\xbd\x0b\xf2\xdd\x7b\xf4\xbe\xb5\xf8\x95\x49\xbd\xa9\xce\xcd\xa5\x4a\x8a\x76\x43\x7a\xaf\x72\xf7\xe2\x03\x52\xb8\xba\xd8\xb4\xe9\x7e\xed\xe2\xec\x8b\x55\xf3\x90\x43\x6c\xb8\x0b\x98\x52\xb1\x41\xa8\x90\x0b\x59\xdf\xb5\xe7\x98\x2e\x2c\x6c\xd8\x55\x89\x05\x1c\x57\xca\xf7\xbb\x9b\x17\x25\xc7\x77\x0a\xcd\x7e\x76\xf7\xf8\xe1\x73\xb3\xb3\xee\xf1\x23\xe9\xe6\xda\x1a\x39\xd3\xaf\xfd\xa5\xcf\xf4\x83\x68\x72\x81\xd3\xe5\x07\x36\x11\x80\xd3\xbb\xdc\xd4\x9f\x73\x88\x37\x33\x77\xde\xcb\x69\xbe\x07\x1d\xfb\x40\x38\x4e\x26\x0e\xed\xf2\x4b\xb7\x09\x81\x78\xaf\x65\xc2\x50\x6a\x90\x33\x5c\x90\x43\x25\xfa\x93\x33\x62\x56\x71\x0f\x5e\xe6\x2c\xaa\x02\x2d\xb2\x40\x3a\x0d\x72\xba\xa1\x73\x93\xe3\x59\x4e\x4e\x91\x01\x7b\x46\x13\xda\x27\xe6\x9b\xc5\x53\x6d\x04\x21\x1e\x44\xe3\x60\x34\xba\x66\x69\x40\xc3\xca\x37\x37\xf2\xa8\xdc\xb0\x56\xd8\xc0\x9d\x08\x34\xd4\x66\x17\x4f\xc6\x71\x1b\xfc\x1e\x34\x3d\x47\x31\x25\xd2\xad\x8e\xdc\xf9\xc5\x2e\x76\x94\x9a\x0e\x47\x2d\xb9\xcc\x4a\x31\xbb\x45\x02\x89\x7d\x3c\xbb\x65\x26\x08\xcb\xf0\x4a\xe4\x23\xdf\x37\x2c\x38\x9d\xda\xcd\x43\x14\x4f\xa6\xf9\x5d\xe6\x94\x93\x87\x4a\x74\xb7\xa0\xb3\xfb\x22\x8e\x81\xc6\x28\x2c\xf4\x71\xeb\xa4\x12\x30\x5a\xf6\x10\x36\xc5\xe4\x6c\xa1\xa2\x0d\x5a\xe1\x85\x95\x7a\x7a\x0a\xf5\x70\x8d\x40\x01\x68\x53\x06\x7a\x63\xd7\xcd\xbb\x77\xda\xa2\xbb\xda\x6e\x2b\x6d\x10\x9b\x9d\xa6\xa7\x29\xcf\xd7\x1f\x4d\xed\xfe\xee\xba\x6f\xd7\xee\x68\x44\x32\x2f\xd3\x84\x9b\x87\x14\x70\x00\x16\x1a\x57\x6b\x22\x2a\x52\x62\x4b\x76\x54\xbd\x9f\x84\xf4\xe0\xf2\x3a\x97\xe3\x55\x56\x12\x57\x54\x45\x11\x59\x1d\x9c\x97\xf1\x20\xc5\xf9\x3d\x29\x95\x88\xfc\xbb\x6f\x0f\x1c\x04\xbd\x64\x6c\xc2\xe6\x89\x4c\x1d\x7d\xab\x6a\x0c\x65\xe7\x60\x47\x80\x60\xab\xce\x48\xe8\x8b\xa8\x8f\x82\x78\xd4\x3d\xdc\x4b\xbc\xdd\xee\x33\xbe\x2c\x1c\x98\xe6\x84\x97\xa5\x87\x2a\x29\xba\xac\x3e\x4e\x76\x43\xfc\x12\xc5\x14\xed\xe8\x2b\x29\x2e\x26\xeb\x7a\x59\x64\x4c\xad\x12\xd7\x17\xe8\xb0\xec\x51\x32\xb7\x47\xa3\xe4\x0a\x05\x69\x3f\xca\xd3\x20\xbd\x46\x4c\xbd\xf4\x19\x5f\x5b\xe2\x0e\x7e\x96\x35\x12\x3f\x5a\x1b\x2e\x19\x28\x5d\xdd\x52\x6d\xb4\xe6\x38\x43\x12\x94\x4a\xdc\x20\x21\xfe\x1b\xe8\x36\x92\x14\x45\x71\x8c\x53\x88\x3e\x9b\x4c\x73\x10\x20\xf4\x28\x7c\x10\x33\x91\xea\x18\x29\x19\xb2\x07\xda\x8a\x11\x90\x8e\x6b\xfc\xe4\x1a\x91\xa5\xc6\x22\x24\x90\x48\x5a\xc9\xa4\x4c\x1f\x19\x49\x05\x23\xa9\xa0\xd1\xd8\x2f\x87\x47\x30\x9f\xf4\x1a\x70\x12\x84\x68\x90\xc4\x59\x1e\xc4\x7a\xf3\xd6\x24\x52\xea\x1c\xbb\x15\x6b\x02\xef\xd3\xe8\x0c\xfd\xba\x85\x1a\xb3\xce\x80\xfe\xcf\xe6\x0e\x63\x14\x6e\x75\xe9\xff\xca\x35\x63\x89\xa6\x13\x8b\xb4\x67\x1b\x45\xfe\x09\x71\xc8\x60\x07\x7a\x88\x28\x64\x82\x89\xdf\x4b\x24\xb2\x92\x7c\x65\x36\x66\x6c\x19\x48\xe8\xb4\x8d\x8f\x3b\xf4\xa4\xaa\xbe\xb8\x58\x30\xb7\x8b\x40\x06\xc3\xfc\xcd\xc4\x1f\x7b\xb7\xdd\x63\xd1\xc7\x00\xaf\x08\x96\x58\x69\x24\x94\x05\xa7\xbc\x4a\x20\x32\xa3\xf4\xfd\x07\x23\x93\x49\x82\xb7\x32\x37\xf8\xd8\x43\x45\x0f\x83\xa1\xfe\x4f\x8f\x1e\x36\x47\x4c\x5d\x44\x44\x24\x3c\xb4\xa0\xa1\xb9\x11\xc4\xdc\x35\xe6\x46\x11\x73\x57\x7d\xa0\x48\x62\x77\xe7\x76\x3d\xaa\x9e\x86\xf1\xb6\xec\xc7\x44\xba\xd8\xb7\x07\x47\x2b\x0d\x38\x56\xca\x31\xe5\xb1\xd2\x80\x16\x12\x0a\x97\x34\xf8\x25\x93\x40\xa5\xee\x0c\x39\x36\x0e\x06\xf6\x4b\x22\x71\xf0\x77\x18\xc1\x6d\xfc\xa5\x15\xe6\xb3\x6e\x7b\xd9\xf2\x7a\x14\xf5\x97\x09\x2a\x21\xd8\xb6\x66\xda\x57\x1c\x0f\x96\xc1\xa6\xd1\xf2\x9e\xba\x59\x6a\x1f\xc6\x61\x67\xbe\xf1\x5d\x76\x11\x34\x3b\x3a\x48\xf2\xb2\xa9\x83\xcb\x2e\x82\x8e\xdf\x34\x5f\xb6\xd6\x2d\x25\x5b\xda\xab\x34\x9a\xe0\x71\xe8\x77\x1b\x56\xdb\x3f\xe5\xd5\xa4\xff\x39\x1c\xea\xed\xe0\xcb\xc9\xe7\x70\x58\x76\xef\xa0\x76\x3d\x09\xf1\xf2\x60\xd8\xb7\xbe\xce\x53\xc7\xeb\xe5\xf3\x51\x10\x8e\x83\xd8\xf6\x39\xb1\x03\xc3\x03\xfd\xf5\x24\x08\x97\x83\x38\x8b\x66\x1b\x4d\x7d\x10\xc8\xa7\x28\x4b\xfc\x86\xdf\xd4\x47\x9c\x7d\xda\x58\xdb\x58\xd3\x67\x88\x7c\xfa\x1d\xa7\x09\x73\xbd\xb6\x7c\x8d\x1d\xdf\xa8\x8e\x6c\xf9\x02\xcf\xb4\x0f\x01\xd6\x89\x8b\xc6\xdd\x08\x8d\xf7\xe9\x40\x9f\xdc\x34\xe8\xf7\xa3\xdc\xfa\x72\x79\x84\xcf\x83\xc1\xf5\x43\xdf\x01\x89\xd5\x03\x4f\xfa\xa2\x81\x97\xc5\x5a\x11\x8f\x6c\x89\xc0\x33\x59\x19\x9a\x59\x28\x5b\x07\xe2\x77\xb3\x2d\x7e\x13\xaa\xe7\xbf\x09\xb1\x8b\xdf\xf4\x57\x41\xda\x85\x7d\x29\xfc\x62\x84\x4c\x31\xa0\xf4\x6b\xdc\x61\x51\x74\x38\xb5\x4a\x4f\x79\xaa\x3e\x09\xda\x2c\xde\x26\x4a\x0d\x42\x89\xb4\x59\x99\x00\xc5\x1b\x41\x77\xf2\x1b\x4a\x6e\xe2\x8d\x4c\x65\xe2\x65\xac\xbe\x92\x68\x0a\x9e\x09\x29\xc1\x8f\x82\x82\xe8\xa8\x0c\xd8\x40\x31\x7a\x91\x7e\x73\x32\x59\x54\x11\xa9\x28\x20\x65\x5e\xbb\xb8\x62\xd2\x1d\x8a\x8d\x75\x69\xb3\xe3\x7b\xe5\xda\x64\x4f\xa5\xab\xcd\x4e\xdb\x53\x08\x6f\xb3\xd3\xf1\x8a\x89\xdf\xec\x74\x3d\x75\xf4\x36\x3b\x6b\xfa\x8d\xb0\x4e\xca\x9b\xdd\x86\xc7\xa8\x75\xb3\x0b\xf8\x08\x4a\xd9\xec\x36\x3d\x99\x56\x36\xbb\x6d\xcf\x46\x2d\x9b\xdd\x96\x27\x53\xc8\x66\xb7\xe3\xc9\xf4\xb3\xd9\x05\xbc\x14\x9a\xd9\xec\xae\x79\x3a\xd5\x6c\x76\xd7\x3d\x9d\x6e\x36\xbb\x1b\x9e\x41\x24\x9b\x6b\x0d\xcf\x42\x4e\x9b\x6b\x80\x3f\x5b\x12\x9b\x6b\x80\x3d\x23\x8d\xcd\xb5\xb6\x67\x10\xc7\xe6\x1a\x20\x4e\xc8\x68\x73\x0d\x70\x2e\xd6\xd9\xe6\x5a\x57\xbe\x40\xf7\x8a\x25\xbb\xb9\xc6\xaf\xd6\xc9\x62\xde\x5c\xdb\xf0\xf8\x52\xdd\x5c\x6f\x78\xc5\x12\xde\x5c\xf7\xbd\x62\x71\x6f\xae\x03\x3a\x05\x05\x6f\xae\x43\xe3\x82\xd1\x6c\xae\xb7\x6f\xce\xbc\x6e\xe3\xf1\xf2\xe0\xcf\xbf\x3c\xe8\x5d\xe0\xc1\x67\xd2\x29\x58\x29\xd4\x0d\x88\xa6\x39\xcb\xa6\x13\x32\x30\x98\xc5\xa7\x96\xfa\x0d\x72\x3c\x0d\x69\x8e\xbe\xdb\x42\xcf\x38\xe4\x67\x16\x8b\x10\xe1\xa4\x71\x8f\xd7\x15\xa5\xe6\xf8\xa2\x9d\x23\x3c\xc4\x29\x86\x83\x5e\x1a\x9d\xc3\x99\x2c\x8a\xa3\xbc\x00\x93\x4d\x27\x38\x05\xd5\xf5\x96\x96\x9e\x43\x82\xb2\x3d\x3d\x1f\xe3\x38\xd7\x0a\xa0\x3c\x41\x17\x41\x1c\x8e\xb0\x32\x6e\x32\xec\xbe\x15\xb2\x62\x53\x03\x55\x4d\x77\x40\x49\xf7\x4d\x63\xc9\x53\x13\xa8\x28\xce\xd7\x25\x0d\xfd\x50\xae\x2f\x14\x13\xea\xec\x98\xc7\xfc\xa2\x06\x55\xc2\x7f\x24\x50\xe1\x85\x8c\x8d\x72\x88\xb0\x22\x96\xd0\xf4\x5f\x00\xe9\x32\xc2\x57\x2e\x14\x9d\xcd\x4b\x08\x1f\x70\x14\xd0\x97\x2f\x6a\x79\x4e\x70\x80\x25\xe8\x8c\x79\xf5\xef\xc8\x9a\x13\xb6\x23\xb0\xe8\xec\xc0\x8d\xaa\x75\xa3\x15\x27\x56\x7e\xd7\x8e\x96\xbb\xa5\xc5\x6a\x1c\xc4\x79\xab\xb9\x68\x13\x8b\xd5\xd8\x1b\x25\xc1\x6d\xaa\x74\xdb\xf0\xbe\x28\x7f\x4b\x52\x5a\xa1\x14\xec\x21\xf9\xd5\x75\x8e\x0f\x21\x39\x90\xf1\xda\x96\x77\x59\xa1\xbf\x7d\xba\xe8\x8a\xb6\xaa\xac\x88\xa2\xf4\x62\x2a\x84\x02\xda\x2b\x81\x1b\xda\xb2\xe3\x6c\xd1\x2c\xec\xce\x58\xf6\xd5\xeb\xdc\x66\xfc\xbc\x90\xbb\xa0\x0d\x95\x45\xf2\x69\x17\xf5\x4f\xa3\xb3\x5b\x25\xcf\x2e\xcc\xb9\xa3\xdf\x31\x55\xd5\x16\x8e\xa3\x6a\x51\xc1\x58\x8b\xd4\x16\x1e\x62\x6e\x84\xb6\x8e\x28\xf3\x6d\xcd\x7a\x46\x46\x93\xbc\x26\xf0\x50\x4c\xa4\x3e\x99\x99\x9b\xed\x06\x93\xc9\xe8\x9a\x35\x1c\xa4\xe7\x53\xc2\xc2\xb3\x32\x7f\x45\xc6\xaf\x57\x26\x69\x92\x27\x04\x47\x99\x73\x97\x19\x4e\xe8\xbb\x8f\x5d\xc1\xd2\xf5\x1f\x65\x9d\x3f\x47\xd6\x81\x80\xd1\x7f\x42\x5c\x22\x6b\x4e\xa5\x0a\x26\x12\xb0\xc5\xd2\x7b\x3c\x94\x17\xba\x75\x52\xe5\x84\x31\x0b\xa9\x24\x55\x5d\x6a\x37\x7f\x36\x49\xcf\xc5\x57\xba\x6d\x3b\x17\x39\x21\x6c\x62\x8b\x0e\xdf\x4a\xd0\xcf\xe8\x8f\x2c\x8a\x59\x30\x56\xc2\x32\x1a\x33\xbf\xc1\xfe\xea\xe8\x8b\x9a\xc6\x97\x2d\xaf\x5a\xdd\x6a\xa1\xfe\x6e\xa7\xa3\x59\x53\xd8\x0c\x40\x74\xaf\x49\xb4\xc5\x46\xd5\x62\x00\xc2\xd3\xde\x94\xde\x8e\x15\x9a\x60\x7b\xae\xe2\x53\x93\x93\x36\x66\xdd\xb5\x76\xa7\xd9\x6a\xf8\x1e\x6a\xcc\xf0\x70\x10\x06\xfd\xf5\x0d\x4b\x5e\xc5\xc6\x6c\x63\xbd\x1f\x84\x83\x21\xf6\x60\x60\x5a\xcd\x4e\x7b\xad\xab\x96\x3b\x73\xde\x88\x69\x69\xf4\xe4\x5e\xbc\x13\x99\xf4\x6c\x7b\xd7\x55\x30\x41\x18\xdc\xab\xe7\xef\x21\x7e\xd7\xbd\x63\xb8\xaf\xaf\xf9\x6c\x50\x24\x3e\x11\x78\x3c\xbd\x20\x8a\x1c\x11\x78\xdf\x7d\x92\x4a\xbf\x3b\xe5\x0f\x67\x36\x97\x10\xe9\x33\x21\x38\xb3\x00\xf9\xab\xd5\x6a\x12\x4c\xea\x29\x8e\xbe\x20\xf9\x25\xec\x75\xed\xba\xe6\x23\x8e\xbe\x54\x04\xd8\x6c\xd7\x2d\x00\x21\x94\xb1\xe2\x92\x6e\x82\xbb\x9b\x71\xc8\xbe\x72\x43\x61\xbf\xee\x57\x86\xb4\x81\xa4\x31\x45\x4b\xa8\xa1\x8b\x0f\x4a\x69\x5f\x2b\xed\x97\x96\x6e\x6a\xa5\x9b\xa5\xa5\x5b\x5a\xe9\x56\x69\xe9\xb6\x56\xba\x5d\x5a\xba\xa3\x95\xee\x94\x96\xee\x6a\xa5\xbb\xa5\xa5\xd7\xb4\xd2\x6b\xa5\xa5\xd7\xb5\xd2\xeb\xa5\xa5\x37\xb4\xd2\x1b\xe5\xb3\xd3\xd0\x66\x67\xce\x64\xfa\x5a\xf1\xf2\xd9\xf4\x9b\x5a\xf1\xf2\xe9\xf4\x5b\x5a\xf1\xf2\xf9\xf4\xdb\x5a\xf1\xf2\x09\xf5\x3b\x5a\xf1\x8e\xc1\x0d\x56\x57\x09\x43\xfe\x1c\xc5\xe7\xa4\x6a\x14\x8c\xfa\x36\xb1\x39\x20\xdb\xc0\xa9\x75\xa0\xfa\xf0\xc9\x3a\x28\x03\xf8\x64\x1d\x80\x10\x3e\xb5\x6c\xe8\xf4\x8a\x3b\x68\xf5\x1b\x41\x62\x6f\xaf\x16\x78\xa8\xef\xa1\x81\x87\x42\x4f\x5a\xa0\x1e\x42\x6b\x1e\xd9\x42\x1b\x67\x3a\x6f\x08\x69\xbd\xd0\x43\xa2\x6a\x31\x42\x1e\x42\x7e\xd3\x43\x27\xa7\xbe\x51\x6f\x40\xeb\xd1\x96\x68\xd5\x62\xd1\x92\x7a\x6b\xa4\x5e\xd3\xa8\xd7\xa7\xf5\x04\x92\x81\x54\xaf\xe5\x21\xd4\x84\xf6\x5a\x46\xbd\xb2\xfe\xb5\x45\xff\xda\x0b\xf5\xaf\x23\xfa\xd7\x59\xa8\x7f\x5d\xd1\xbf\xee\x42\xfd\x5b\x13\xfd\x5b\x5b\xa8\x7f\xeb\xa2\x7f\xeb\x0b\xf5\x6f\x43\xf4\x6f\x63\xa1\xfe\xf9\x0d\x8f\xf5\xcf\x37\x09\xa6\xac\x83\xbe\xef\xb1\x0e\xfa\x26\xc5\x94\xf5\x90\x60\x49\x7b\xe8\x9b\x24\x53\x4a\xa2\x2d\x8f\x93\xa8\x49\x33\xa5\x7d\x6c\x8b\x3e\x9a\x44\x53\xda\xc7\x8e\xe8\x23\x50\x8d\xd9\xc9\xd7\xaf\x1d\x9d\xf4\x10\xea\xd0\x4e\x9a\x74\x13\xd2\x8a\xd6\x4e\x12\x7a\xdb\xa0\x15\x4d\xc2\x19\xd0\x8a\xf6\x4e\xfa\x1e\x22\x1d\x3d\x39\xf5\x4d\xca\xe9\xd3\x8a\xd6\x4e\x12\x8e\xd1\x6c\x40\x45\x93\x74\xca\xfa\xd8\x11\x7d\x6c\xda\x79\x8d\xab\x8f\x84\xe6\x68\x1f\x9b\x76\x66\xe3\xec\x63\x87\xf7\xb1\x69\xe7\x36\xae\x3e\xb6\x45\x1f\x9b\x76\x76\xe3\xea\xe3\x46\xd1\x47\x3b\xbf\x71\xf6\xb1\x2d\xfa\x68\x67\x38\xae\x3e\x12\xc6\xc8\xfa\x68\xe7\x38\xae\x3e\xae\x17\x7d\xb4\xb3\x1c\x27\xad\xb6\x3c\xde\x47\x3b\xcf\x71\xf5\xb1\x29\x68\xb5\x69\x67\x3a\xae\x3e\xae\x89\x3e\xb6\xec\x4c\xc7\xd5\x47\xb2\xfc\x69\x1f\x5b\xbe\x7d\x41\xee\xef\xbb\x89\xb5\x0d\xb8\xb6\xec\x5c\x67\x7f\xdf\xde\x49\x32\xac\x64\x6d\x9d\x9c\xb6\xec\x5c\x67\x7f\xbf\x64\x41\x76\xa1\xa2\x9d\xeb\xec\xef\x3b\x3a\xd9\xf6\x50\xb3\x05\x15\x4d\xd2\x29\xeb\xa3\x5f\xf4\xd1\xce\x74\x5c\x7d\x6c\x17\x7d\xb4\x33\x1d\x57\x1f\x61\x22\x69\x1f\xed\x4c\xc7\xd9\xc7\x86\xe8\xa3\x9d\xe9\x38\xfb\xd8\xf2\x58\x1f\xdb\x76\xa6\xe3\xea\x63\x43\xf4\xb1\x6d\x67\x3a\xae\x3e\xb6\x44\x1f\xdb\x76\xa6\xe3\xea\x23\x61\xe5\xb4\x8f\x6d\x3b\xd3\x71\xf5\x71\x43\xcc\x63\xdb\xce\x74\x5c\x7d\x24\xcb\x83\xf5\xd1\xce\x74\x9c\xb4\xda\xe1\xb4\xda\xb6\x33\x1d\x57\x1f\x9b\x45\x1f\xd7\xec\x0b\xf2\xe0\xc0\x2d\xa8\x76\x69\x27\xed\x5c\xe7\xe0\xc0\xde\x49\xa0\x39\xe0\x01\x6d\x3b\xd7\x39\x38\x28\x11\x03\x3a\x20\x02\xda\xb9\xce\xc1\x81\xbd\x93\x84\x77\x34\x61\x58\x3b\x76\x51\xc7\xd5\x47\x32\x1f\xb4\x8f\x1d\x3b\xd3\x71\xf5\xb1\x25\xfa\xd8\xb1\x33\x1d\x67\x1f\x1b\xa2\x8f\x76\xa6\xe3\xea\xa3\x5f\xf4\xd1\xce\x74\x5c\x7d\x5c\x17\xf3\xd8\xb1\x33\x1d\x57\x1f\x81\xe6\x68\x1f\xed\x4c\xc7\xd5\x47\x10\xc9\x69\x1f\xed\x4c\xc7\xd9\xc7\x96\xc7\xfb\x68\x67\x3a\xae\x3e\xb6\x45\x1f\xbb\x76\xa6\xe3\xec\xa3\xcf\xfb\xd8\xb5\x33\x1d\x57\x1f\x9b\xa2\x8f\x5d\x3b\xd3\x71\xf5\x71\x43\xcc\x63\xb7\x65\x2e\x48\xb8\x46\xc9\x71\x3a\xc6\x61\x14\xe4\xcc\xa9\x0c\xdc\x15\xd4\x72\xe4\x88\x8b\xb6\x50\x0d\xfe\xbb\x84\x02\x5d\xc3\x4a\xcb\xf8\xac\x8c\x4f\xca\xf4\xed\x65\x9a\xac\x4c\x93\x94\x19\xd8\xcb\xb4\x58\x99\x16\x29\x13\x1a\xda\x5c\x4d\x55\xb9\x67\xb1\xd4\x5d\x30\xa0\x2d\x64\x4a\x17\xd9\x74\x83\x3c\xb0\x1d\xcc\x83\x3c\x10\xa1\x7c\x82\x3c\x70\x2b\xc7\xe2\x57\x51\x9e\x9d\x24\x79\x30\x12\x30\xe3\x9d\x20\x0f\xa8\x07\xc9\x73\xb4\x6e\x81\x0e\x75\xde\xe2\x61\xce\xa1\x0b\x8f\x13\x28\x6f\x74\xc6\x99\xf2\x4a\xa0\x79\x5a\x80\xfc\xf1\xc7\x1f\x51\x07\x2e\xde\x1a\xb3\xf5\x46\x71\xdf\x56\x94\xf8\x07\x6a\x35\x0d\xe2\x50\xfb\xb2\x8f\xb6\x10\xa8\xdd\x87\xa3\x24\x49\x6b\x52\x27\x57\x15\xdd\xbb\xab\x73\x50\xf6\x2d\xda\x92\x9e\xf4\x85\x23\x50\xaf\xd5\x6a\x05\x6e\x4b\xa8\xdb\xa6\xf9\xd2\x36\x20\x98\x68\xbb\x4e\x15\x36\x76\xfd\x2c\xaf\xca\x70\x2e\x94\xb3\xf2\xdb\xea\xda\x59\x13\x1c\x53\xcd\xea\xe0\xe6\xe9\x66\x0d\x2e\xb1\x48\x67\xdb\x55\x3a\xfb\xd6\xda\xd9\xb7\xb7\xed\xec\x5b\x6b\x67\xdf\x56\xed\xac\xd9\x5b\xd9\x89\xaa\x26\xba\xcf\x83\x4d\x41\x4e\x3d\xbb\xff\x20\x18\xbc\x53\x37\x06\xf0\x51\xb4\x79\x52\x95\xe6\x95\x9f\xe3\x0d\xa9\xe8\xbc\x2d\xe4\xbb\xcf\x0c\xe3\x9d\xde\x6f\x0b\xdd\x7b\x38\xae\xb8\x50\xd9\xf5\xbf\xc0\x04\xae\x30\xf6\x4f\xed\x77\x17\xfb\xec\x96\xac\x56\xdb\x57\xae\x25\xf6\x17\xbe\x8f\xa0\xb4\xb0\xaf\xdc\x45\xec\x3b\x2f\x21\xe6\xdf\x38\x1c\xb1\xdc\xc0\x30\x87\x2c\x02\x4f\x08\x63\xaa\x16\xad\x90\xac\x1c\xdc\x10\x4a\x59\x3d\x28\x58\xc1\x29\x53\xdc\xd0\xc1\x63\x71\xfd\x6f\x6c\xbc\xf0\xf9\x93\x41\x0b\x2e\xef\x4a\x1e\x41\x83\x7c\xb5\x7b\x38\xd0\x5f\x02\x49\x4d\xf5\x35\xf3\x50\xe6\x21\xf5\x0a\x0d\xf8\x24\xda\x42\x01\x5a\x42\xb5\x5a\x1f\xfd\x40\x37\xc7\xda\xff\x92\x9f\x61\x9d\xb0\x81\x19\x5a\x42\xb9\xd4\x9e\x08\x58\x1c\x93\x69\xca\xe8\x4a\xa5\x71\xca\x5b\x4d\xb4\x8c\xb2\x3a\x54\xeb\x6b\x46\x6f\x02\x2b\xed\xfc\x5f\x0d\x2b\xd8\x8e\x6b\x03\xf4\x03\xfa\xdf\x87\xc1\x4a\x3b\x04\xcd\xc5\xaa\x8f\x7e\x45\x03\xf4\x2b\x41\xec\xfe\x91\xd1\x04\xc0\xb9\xc8\x10\x44\x6a\x7d\xf4\xe5\x9e\x07\x47\xbe\xad\x3e\x76\xa5\x49\x9f\x9b\x78\xbf\x4a\x90\x35\xee\x27\xa6\xb9\x28\xc2\x6a\x30\xc1\x38\x9c\xc5\x1c\xa5\x6f\x1b\xd6\x8c\xad\x4b\x61\xe4\xf2\x6e\xa7\x63\xf1\xfd\x2a\x2f\x6f\x3a\x7c\x15\xf1\xc5\x94\xcb\x7c\x35\x23\xff\xbb\x9d\x8e\xd5\x64\xc0\x39\x09\x73\x72\xd5\xdf\xd7\x14\xdc\x2a\xb4\xc3\xfc\x89\x93\xbd\xfc\xee\x63\xe2\xa8\x53\x99\x98\x88\xfd\x71\x30\x20\x93\xa1\x64\x86\x37\xe7\x83\x15\x33\xe7\xa4\xc8\x66\x4f\xe7\xa5\x34\x03\x3b\x8b\x6c\xed\xb0\x80\x6a\xfe\xa5\x5d\xcc\xfe\xfe\x31\xd9\xe8\x62\x7b\xce\xe2\x0c\xa1\x3d\x8c\xc3\x7e\x30\xf8\xcc\xe2\x6a\x8e\x93\x10\x96\x14\xa1\x19\x31\xdf\xf0\xb2\xb7\xf7\x8a\x88\x40\x16\xf1\x00\xcc\x9c\xe0\xab\x62\x2d\x07\x16\x2e\xb4\x95\x77\x04\x00\x33\xe6\x11\xab\xbe\xb7\xf7\x6a\x65\x37\xa6\xb1\xca\xc1\x80\x6a\xef\x95\xc5\xe0\x67\xe2\x30\x97\x61\x66\x86\x25\x26\x33\x6e\xd1\x94\x85\xa0\xe2\x02\x09\x7d\xb4\xdd\x33\x4b\xa1\x3c\x68\x21\x39\x94\x87\x5a\x9e\xc7\x28\x7f\x83\xaf\xb3\x3c\xc5\xc1\x78\x3b\x0e\x59\xef\x2c\xd6\x91\x09\x33\x8b\x15\xe0\x3c\xd6\x80\x4d\xc8\x3e\xc2\x63\x0c\x41\xc6\xc1\x18\x93\xce\x13\x8b\x95\x09\xfe\xf3\x31\x9e\xe5\xf4\xb5\x5d\x7c\xc7\x97\xaf\x58\xcc\x54\x68\x7d\x25\x1b\x45\x03\x5c\xe3\x28\x88\x9b\x7a\x81\x8b\xcd\x7e\x52\x99\xb5\x1d\xfc\x77\x99\xb5\x3b\x8c\x2e\x18\x0e\x5f\x44\xd9\xc2\x63\xfb\xd5\xe8\xe6\xa4\xe8\x50\x1f\x0f\x92\x31\xf3\xba\x27\x04\x11\x25\xd3\xac\x1a\xc9\x88\x2e\x56\x12\xc7\x4b\x7a\x53\x9b\xdb\x05\xcd\x37\xc2\x3c\xb0\xc1\x79\xef\xb2\x08\xd6\x72\xf9\x42\x35\x1a\x97\xc3\x31\xd3\xe6\x8b\xcf\x90\xd9\xf5\xd2\x7a\xa4\x11\xa5\xd1\x16\x8a\x2e\xd9\x14\x36\x1c\x2b\x31\xb9\xc4\xe8\xe0\x27\x38\x7f\x66\xd3\x7e\x86\xff\x3d\xc5\x71\x5e\x72\x7a\x06\x7c\x85\x03\xc3\x5c\x03\x68\x1d\x1f\x6d\x42\xcc\x49\x20\x7f\x8c\xca\x31\x1d\x68\x28\x58\x13\x40\x3c\xa4\x76\x65\x75\x15\xb1\x19\x29\xde\x59\xb3\xe5\x96\x47\x8d\xa1\xa6\xe7\x85\x85\x20\x44\x82\x11\x8d\xc2\x39\xda\xa0\x17\x86\x05\x17\x27\xf6\x5e\x95\x19\x5c\xf3\x4d\x67\x91\x38\x75\xdd\xd6\xa3\xf0\xf1\xad\x0b\x1f\xe8\xbf\x27\x29\xce\x70\x7a\x89\xa9\x18\x92\x4c\x89\x28\x2f\x89\x1f\xa0\xc6\x08\xf2\xa8\x3f\x62\x1c\x18\xed\xa4\xe8\x55\x1a\x05\x31\x7a\x4d\xdd\x33\xd1\x30\x1a\x61\x1c\x0f\x56\x06\x00\x82\x87\x7c\x86\x08\xd8\x1a\xfd\x9c\x1c\x41\x91\x7f\x06\x31\xda\x4f\xa7\xfd\x6b\xf4\xdb\x05\xf9\xcf\xca\x15\xee\xff\xf7\xf9\x38\x88\x46\x2b\x83\x64\x6c\x97\x77\x4e\x8e\x78\x73\x25\x62\x8f\x5c\xa8\xb2\xf4\xf3\xa4\xc8\xf7\x12\x0f\xc8\x41\x81\xa6\x4c\x7a\xfa\xe4\x09\x19\x74\x20\x3d\x91\x0e\x09\x94\x44\x54\x29\x54\x87\x59\xa7\xbf\xfe\x40\xab\xab\xc9\x25\x4e\x87\xa3\xe4\x8a\xd4\x81\x8d\xcf\xe7\xe9\x40\x49\x3d\xbf\x5b\xff\x81\x94\x7d\x21\x3e\x37\xe5\xcf\xeb\xfa\xd7\x16\xdb\xc3\x58\x63\x80\x27\xa0\x42\xc0\x8a\x76\x57\x57\x11\x6f\x16\xf5\x7d\x52\x04\x50\x86\xa6\x1b\x2f\x44\x95\x66\x51\x45\x94\x79\x02\x08\xd0\x42\xb4\x54\x4b\x2d\xc5\x8a\x3d\x01\x54\x58\xb9\x1b\xf8\x97\x10\xa4\x5c\x62\x69\xa9\xdf\x92\xbe\xc3\x3f\xbc\x0c\x2d\xb2\xb4\xd4\x6f\xbe\x78\xea\x2e\xb0\xb4\xd4\xf7\xd9\x77\xf2\x2f\x74\x9c\x37\x0a\x0f\x4b\x5b\xd0\xf3\x97\x2f\x59\x3e\x48\xf9\x75\x93\xaa\x00\x95\xb7\x0c\x21\xb3\x25\x51\xad\x31\x6b\xf8\x4c\xeb\x57\x14\x65\x5c\x8f\x14\x22\x2f\x6f\x74\xea\x60\xcb\xa3\x36\xa0\xff\x55\x69\x84\xbd\xa4\x37\x48\x9c\x94\x8a\x97\x75\x46\x30\xd2\x14\xac\xae\x22\xb2\x4b\xc0\x4d\x0c\x8a\xa4\x85\x44\x17\x8f\xb1\xd2\x9e\x65\x08\xe0\x65\x28\x89\x47\xd7\x74\x39\xee\xfc\x7c\x78\xb4\x83\x7e\x43\x2f\xd1\x3a\xc0\xe4\x0d\xfa\x36\x2c\xe8\x5d\x9c\xda\x59\xf6\x8d\xf7\x97\xaf\x25\xe5\x2c\x20\xd6\xd5\x8a\xe3\xf5\x9f\x28\x73\x2e\x2a\x72\x1a\xc5\x35\x19\xc6\x6c\x95\xf1\x44\xd1\x2c\x1f\x30\x03\xf5\x32\x89\x07\xb9\xa5\x1e\x10\x1a\xec\x8d\x94\xcb\x40\xe8\x16\x72\x10\x9a\x2f\x0b\x71\xe9\x80\x10\xb6\x49\xf3\x94\x15\x3d\xd1\x45\x23\xf6\x59\xc2\x55\x55\x3d\x2f\x22\x14\x21\x87\x60\x84\x6e\x27\x1c\xa1\x05\x05\x24\xa4\xca\x73\xe6\xa1\xab\xa0\x7b\xf9\xec\x25\x96\xc6\x0b\x4d\xb2\x12\xc5\x25\x01\xcb\x29\x62\x49\x85\x17\x90\xb4\xda\x8f\x92\xd6\xb7\x2e\x69\x39\xe4\x2b\x87\x7a\xe7\xe4\xa8\x5c\xce\x59\x54\xbd\x63\x61\xe9\x3a\x2f\x7f\x64\xe2\x7f\x3f\x26\x5e\x7a\x9a\x7d\x00\x96\x7d\x10\x0f\x52\x0c\x91\x1b\x18\x70\x0d\x24\x93\x43\x8a\xc9\x5d\x46\xd4\x98\xc6\xf1\x05\x6e\xcb\xbf\xa0\xc6\x5f\x6a\x73\xa8\xba\x2b\xcc\x3f\x6f\x93\x32\x0b\xec\x02\x9d\xc7\x5d\xe0\x2f\xb1\x0b\xec\x8e\xf0\x20\x4f\x93\x38\x1a\xa0\x5e\x12\xe2\x7e\x92\xcc\x57\xf8\xef\xf6\xca\x14\xfe\xf4\xeb\x42\x3b\xc2\x6e\x4f\x55\xf8\x93\xe7\xfb\xda\x01\x64\xd6\xae\x32\x10\xb5\x5e\x99\x16\x93\xe0\xa3\x2c\xa4\x87\xc2\x2f\xc4\xb7\xc2\x8f\xa7\x5e\xea\xcd\xd7\x9b\x41\x99\x05\xd6\xf1\x5f\x3b\x39\xf2\x7f\xce\x3a\x3e\x9c\xe6\x93\x69\x5e\xfd\xd2\xee\xb0\xf4\xd2\xee\x70\xf1\x4b\x3b\x5d\xaa\x3b\xd4\x2e\xf1\x0e\xff\xdc\xeb\xa0\x07\x97\xea\x4c\xdd\xbc\x78\x73\xbf\x92\x5d\x49\x43\xdf\x8a\x74\xf7\x77\x3a\x61\x1f\x6a\xd7\x9a\x2e\x21\xea\xb0\xc2\xa5\xc5\xe1\x82\x97\x16\x8f\x59\xec\xfe\x1a\xcc\x77\xfb\xfd\xf1\x01\xfa\x65\x65\xa3\xd9\xe2\x06\xe2\x28\xcb\xc9\xf2\x3e\xbf\x36\xb8\xef\x24\x08\x57\xb6\xe3\x2c\xfa\x85\x94\x16\xb9\xe0\x26\x41\x28\xb3\xbf\x30\xc8\x03\xe9\x22\xd4\x75\x01\x9a\xa9\x37\xa0\xa4\xd6\x71\x61\xf0\xab\x18\x00\xbf\x50\x8b\xf6\xf5\xb4\x22\x7d\x57\x42\x11\x20\x8a\x69\x9c\x8b\x9e\x69\xc1\xac\xc0\x16\xef\x03\xfd\x66\x00\xa3\x2f\x96\x55\xcc\xfe\xa1\x7d\x37\x5a\xa3\x31\x6d\x46\x41\x46\x23\x67\xa1\x49\x92\x45\xaa\x07\x3e\x69\x94\x7c\x27\xf5\x3f\x24\xbc\xb3\xa2\x85\x25\x0d\xa3\x65\xe4\x6b\x8d\x7c\x08\xc2\xe2\x19\x06\x4a\x64\x1b\x51\x5f\x53\x56\x22\xb7\x55\x84\xd4\x52\x1b\x29\x42\x6a\xc9\xa5\x6d\xc1\xb5\x54\xcb\xec\x25\x0d\x10\xb7\x43\xe4\x16\xb8\xd3\xd8\x42\x1c\x3a\x45\xbc\xc6\xb9\x94\x70\x5e\x99\x2a\xaa\xc0\x17\xa3\x59\x3e\x73\x52\x9f\x6b\x2a\x9a\xcb\xe4\xf8\xcb\xfa\x5e\x5c\x04\x49\x28\xb0\x7d\xc5\xf0\x90\xd0\xc0\x38\x7a\xfb\xf4\xc9\x8d\x95\x6f\xf2\xe5\x32\xdb\x68\xb6\x16\xe2\x9d\x77\x4b\x4c\xf6\xc8\x3b\xbf\x16\xef\x3c\x38\x3e\x44\x10\x12\xb7\x1a\xeb\x3c\x60\x01\x74\xef\xca\x3a\xff\x74\x76\x58\x2c\x89\x39\xfc\xd0\xc2\xaa\x68\x3a\x00\x7b\x04\xba\x95\x34\x88\xc3\x64\x5c\x33\x38\x60\xbd\xbe\xa2\x49\x4a\xe5\x70\x58\xea\xb0\x53\x83\xcb\x35\xdb\x67\x1e\x01\xf7\xc8\xa8\x74\x46\xc5\x89\x73\x21\x46\xf5\xd7\xce\xbc\xf0\x1f\xc5\xa8\x56\x0f\x76\x7b\x68\x63\x6d\x63\x6d\xd9\x47\x8c\x36\xd0\x3b\x9c\x5f\x24\x21\x6a\xba\xb8\x15\x84\xf6\xbe\x2d\xb7\xda\x0e\x43\xea\x3f\xa8\x2e\x88\x0a\x5c\x80\xaf\x5e\x52\x9b\xfe\xf1\x45\xab\x34\xf0\x3f\x38\x4d\x20\x77\x58\x7e\x81\x51\x8a\x33\x89\x2f\x2a\x1d\x21\xe5\x58\x8f\xc9\xb3\x81\xf7\xad\x78\x01\x5b\x88\xbf\x33\x1c\xd4\xd5\xe8\x6c\x1e\x40\x53\x78\xf6\x85\x9d\xc4\x18\x8d\x93\x14\x53\xe1\x71\x79\x19\xfa\xe6\x1a\x45\xbe\xde\x97\x97\x2b\x2e\x70\x98\xcf\x45\x16\xf8\xda\xdd\xa2\x9c\x3f\x2e\xf0\xaf\x76\x8a\x43\x71\x92\x4c\xaa\x89\x21\xef\x39\x39\x3a\x57\xb6\x20\x76\xf7\x9a\x28\x8a\x94\xd1\x9c\x68\x6a\x21\xa2\xbb\x5b\xb8\xd9\x47\xa2\xfb\x5a\x44\xf7\x3f\x12\xf3\x2b\x27\x39\x89\x07\xfe\x89\xc2\x6f\xe5\x83\xb3\x7c\xbe\x35\x04\xe0\x5a\xad\x5c\x04\xae\xa3\x2f\x5f\xf4\x57\xb7\xda\x62\xec\x3d\x9e\x1f\x57\x60\x75\x15\x7d\x24\xf0\xd5\x7a\x91\x11\x29\x00\x34\x0b\xa2\xcc\xd5\x45\x34\xc2\xa8\xf6\x5d\xad\xf0\xb5\x2e\x62\x70\x83\xc7\xa1\x11\x73\x5b\x98\x70\x1a\x8a\xcc\x48\x6c\x49\x48\x55\x51\xea\x8e\xdd\x10\x8f\xb7\xca\xee\x25\x51\xd0\x42\xbc\xe4\xaf\xed\xb8\x65\xc9\xd1\x45\x93\x64\x3d\x2c\x5f\x29\x32\x21\x41\x6b\x7f\x7e\x9e\x8f\x87\x4d\x12\x5e\x2d\x26\xb6\x11\xf3\x5a\x7c\x39\xde\xdf\xf6\x8b\x58\xcf\xe4\x49\xfa\x68\x26\x02\xb7\x39\x88\x7e\x08\xb2\x8c\x2c\xe4\x65\x82\x5a\x88\xde\xe0\x6b\xb4\x83\xd3\xe8\x92\xe6\x84\xdc\xe3\x83\xd2\x2c\x8f\x39\xfd\xe1\xd5\x9b\x9d\xbd\x66\xd1\x9a\x78\xae\x98\x78\xbc\x97\xc4\xc3\xe8\x7c\xca\x32\x51\x26\x90\x15\x32\x2b\xcb\x2f\x99\x26\x13\x9c\xe6\xd7\xe8\x0f\x7a\x2c\x06\x6f\x52\x60\xbe\x27\x17\x34\xc7\x71\x46\x1e\xa2\x98\xa5\x0b\xc8\x13\xe1\x4b\xb3\x82\x76\xf0\x30\x98\x8e\xf2\x4d\xd4\x46\x35\xbf\xb9\x0e\x89\x94\xeb\x2e\xf8\x8e\x84\xe6\x38\xe5\x89\xcc\x0b\x70\x64\xfc\xe7\xa1\x19\xe5\x2c\x79\x66\x06\xa0\x8a\x43\xbd\xf4\x21\x4f\xd0\x04\xa7\xc3\x24\x1d\x4b\xc0\x15\xc8\x52\xfa\xc7\xc1\xf0\x7c\xd3\x35\xca\x88\x5e\x7c\x1d\x43\xcc\x19\xbf\xb9\xbe\xda\x6a\x6a\x21\xb8\x69\x57\x28\xea\xda\xa7\x02\x21\xa5\xf1\x9b\x7a\x59\x42\xd2\xb2\x04\xf2\x64\x56\xc2\x82\xb4\xf8\x7a\x9b\x9f\x45\xf4\x10\xf8\xdc\x0d\xe9\xaa\x9c\x31\x94\x8c\xdf\xc0\x46\x37\xdc\xdf\x6c\x98\xa4\x70\x8a\x29\x1a\xbd\x87\xc4\xa0\x9f\xc3\xa1\x91\x34\x9e\x52\x3b\x3f\x3d\x2a\x66\x58\x8b\x54\xfc\xa3\x98\xac\x75\x9a\x7e\xf2\xce\x60\x3c\x75\x1a\x1b\x8d\x86\x0e\xb8\x24\x7b\xfd\x60\x78\x6e\x37\xbc\x20\x13\xb1\x25\x7e\x72\xc2\x23\xc5\x5d\xc1\x30\xcc\xf5\x0e\xd7\x15\xd4\x83\xae\x2a\x0b\xba\x4d\xbe\xd9\x09\x83\x0d\xd4\xc2\x1f\x56\x2a\x56\xce\x82\x51\x8e\xb6\xe1\x3f\x8b\x27\xa2\xe5\x6e\x34\x92\x5f\xfb\x5d\xc8\x8e\x26\x52\x0f\x87\x2b\x2c\x2a\x49\x8d\x77\xc6\x03\xfc\x9c\x93\xca\x8a\xcb\xf3\xaa\xd5\x5c\x28\xb7\x8b\x3a\xf5\x56\x03\xc2\x28\x77\x24\x85\x65\x5e\xf6\xe0\xbb\xcf\x68\x95\x90\x0f\xe5\x41\x9e\x98\x1d\xbb\x59\xa2\x3b\x41\x39\xc8\xa6\x74\xb0\x69\xba\x79\x43\x9f\x63\x0b\xf5\x04\x72\xf2\x41\x1c\xe2\x99\xad\xc6\x69\x63\xc6\x14\x40\x96\x68\x9d\x73\x42\x74\x09\x54\x84\xb0\x2c\xde\x38\xf3\xd7\x17\xd8\xf0\x4a\xc5\x1b\x67\x25\xbe\xe5\x6d\x91\x59\x59\x61\x4f\x36\x23\x8c\x62\x6b\xa1\x45\x8b\x17\x73\x8c\x2c\xd4\x8f\x4c\x50\xd7\x3a\xc8\xe3\x22\xbd\xe4\xf8\x58\x8d\x0b\x44\x27\x59\x9e\x63\x9e\x2c\x1b\x28\xb0\x48\xe3\x5b\xf4\x5a\x9f\x33\xc4\x32\x7a\x17\xa9\x81\xcd\xef\xf3\xb3\x31\x00\x7c\x65\x88\xad\xa3\x6b\x16\x17\x59\x8c\x8a\x57\xac\xe3\x0e\x44\x0e\xc4\x18\xdb\x41\x47\x72\x34\x3b\x06\xd6\x82\x85\x62\xcb\xe1\x53\x5b\x0e\x69\xfa\x9c\xc6\x1c\x08\xf8\xb9\xd2\x04\x8c\x9e\x18\x69\xf9\xa3\x6d\xac\xab\x8c\x37\x9a\x17\x0a\xca\xd6\x59\x3e\xfa\xf2\x3b\x7b\xc0\x2a\xa9\x89\x5f\x0e\x8f\xd4\xee\x80\xeb\x94\xc5\xe3\xda\x18\xb7\xdf\xa8\x0d\xcc\x6f\xdc\x06\x46\x9a\xcd\x17\xe8\xb7\x92\xd1\x23\x7f\x45\x8d\xd3\xdf\xc0\x1c\xc6\xe8\xc8\xe9\x6f\xba\x59\x0c\xff\xbb\x31\x5f\xeb\x01\xa7\xc8\x9f\xc4\x1c\x98\x6e\x1a\x1a\xb5\x4d\x89\xc6\x24\x4e\x1b\x67\x4b\x4b\xe5\x26\x45\x12\x70\xe9\xe8\xcb\xf9\x86\x25\x88\x19\xdb\xcb\x8a\x7a\x65\x06\x94\xf2\x31\xe2\x4e\x1b\x7a\x95\x60\x33\xa5\x1b\xf9\x82\x9b\xf8\x7d\x89\x96\x51\x66\x4b\xb7\x3f\x3f\x7a\x8d\x45\x34\xb8\x87\x20\x36\x54\x44\x10\x92\x21\x15\x0a\x5d\x62\xc2\x62\xd5\x3c\xe4\x90\x4d\xef\x02\xa6\x54\x36\x2d\x82\xec\x88\xa3\xa4\x4b\x80\xf1\x90\x2e\xa8\xb2\x61\x57\xc5\x62\x52\x68\x8e\xf0\x74\x53\x66\x8b\x46\xa1\xd9\x03\xf5\xe8\x29\x74\x79\x4e\xd8\x9b\x33\x6f\xed\xaf\xed\x43\xbf\x40\x5a\xf7\xf9\xc9\xd1\x1f\x56\x77\xe4\x4c\xaf\xed\xca\x7a\xfd\x77\xd0\x2e\x1d\x83\x71\x66\x8f\x1b\xef\x52\x25\x92\xfc\xb2\x4c\x8f\x24\xf0\x38\xc2\xd3\x2c\xe8\x8f\x30\x0b\x07\x26\xa1\x73\x8c\xe4\x54\x8b\x14\x8a\xfe\xe6\x35\x52\x33\xac\x49\xdb\xc2\x11\x64\x53\x46\xcc\xd0\x96\xd9\x18\x9b\x9a\x24\x51\x1e\x62\xac\x44\x19\x0a\x10\x4d\xc0\x8c\x2e\x71\x9a\x41\xd4\xb2\x8b\x20\x47\x31\x3e\x1f\xe1\x41\x8e\x43\xc2\x86\x07\x2c\xa5\x6a\xce\x14\x3e\x79\x82\x46\x51\x9e\x8f\xf0\x32\x0d\x70\xb9\xa2\x02\xc5\x69\x9a\xa4\x28\x4c\x70\x16\x3f\xcb\x51\x30\x1c\xe2\x01\xad\x4b\x91\x7a\x96\xa1\x0c\x0f\xa6\x69\x94\x5f\x7b\xa2\x62\x7f\x9a\xa3\x28\x87\x4a\xbc\x46\x94\x67\x22\xa0\x42\x34\x8a\x72\xe6\xc4\x4d\xf3\xba\x46\x84\x3f\x8f\x71\x4c\xf7\x83\xcc\xa6\x28\xa3\x03\xf2\x96\x76\x4e\xa8\xcb\xb4\xb7\xf2\xfc\xdd\x36\x69\x5b\xf9\x21\xe5\x8d\x6c\x06\xed\x3c\x60\x14\xd6\xdb\x70\x6a\xb8\x2c\x3b\x2d\x44\xec\x84\x46\x76\x2f\xec\x3c\xa7\xfd\x22\xda\x25\xbf\x2c\x89\xe3\xde\x9c\x36\xce\x3c\x54\x7b\x73\xda\x3a\x63\xc1\x02\xd0\x17\xf2\xc8\xae\x02\xfc\x6e\xdd\x92\x44\xee\xcd\xa9\x4f\x2b\x35\xd4\x4a\xad\xf2\x4a\x4d\x5a\xc9\x57\x2b\x35\xca\x2b\xb5\x68\xa5\xa6\x5a\xc9\x17\x95\xd4\x3a\xb6\xec\x48\xc6\x90\x71\x2f\x43\xd7\xa0\xf5\xc4\xa0\xf5\xec\x83\x66\xe2\x23\x0d\x17\xeb\x13\xbd\x30\x19\x0e\x79\xda\x41\x8a\x34\x0d\xb2\xda\x68\x90\x2f\xb6\xfe\x9a\x13\xd1\x52\x21\xfb\x56\xc8\xcd\x4a\x90\x1b\xce\x81\x97\x60\x68\x90\x5b\x95\x20\xfb\xae\xd9\xf1\x24\x18\x1a\xe4\x86\x06\x79\xfe\x44\xf6\x82\x34\xbd\x46\x7d\x3d\x9d\x2a\x9d\xaa\x3e\x8d\x7f\x61\x6a\x32\x72\x3a\xf9\x84\xf5\x64\xd7\x59\x8e\xc7\x68\x98\x4c\x53\x94\x47\x63\x7d\xee\x17\x0c\xca\x1b\xe3\x59\x7e\x4c\x56\x9f\x3b\x7e\xac\x25\xe2\xed\xbb\x24\x8c\x86\xd7\x94\x13\x52\x3a\xac\x80\xc5\xba\x1b\x8b\xde\x29\x75\x1c\xf8\xe5\x14\x52\x5e\x42\xb4\x15\x23\x53\x9c\x2d\x49\xee\x4f\x28\xc3\xf9\x74\xa2\x7e\x28\xf1\xe8\x98\x7f\xd8\x3f\xf8\x89\xba\x76\x94\x9d\xf0\x0f\x7e\xfa\xd4\x40\x5b\xe8\xe0\x27\x33\x35\x9a\x54\xc4\xa7\x45\x7c\x6b\x34\x63\x79\x49\xc3\x54\x66\xd3\xfe\x25\x26\xa2\x82\xeb\xe8\xdf\xa0\xc1\x8f\xa1\x6d\x1a\xfd\xf8\x0b\xa2\x4f\xae\xe8\xc7\x72\x71\x16\xe6\x58\x94\x2f\xae\x43\xed\x61\x8e\x45\xb3\x4d\xd1\xac\xaf\x34\xeb\xcf\x6b\xd6\x57\x9b\xf5\x17\x6b\x16\xc2\xe8\x44\x0d\xbe\x04\x09\x90\xa8\xa9\xae\x40\x57\xd5\x16\x54\x6d\xf2\xc5\x0c\x55\x1b\xea\x32\x75\xcc\x08\x23\xeb\x32\xd6\x8a\x80\x5a\x1b\xf4\x5c\xaf\xc7\xf6\xa7\x1f\x7d\xfa\xd1\xb7\x7e\x6c\xd2\x8f\x4d\xeb\xc7\x16\xfd\xd8\xb2\x7e\x6c\x97\xb5\xd9\x29\x6b\xb3\x5b\xd6\xe6\x9a\x68\xb3\x44\x23\x55\x89\xf3\xa0\xc5\xb9\x0f\xaa\xc6\x81\x90\xa9\xa4\x90\xfd\x88\xee\x25\xb9\xab\x53\x79\x2d\x49\x1f\x95\x38\xb3\x5a\xc4\xde\x3b\xf7\xf6\x0e\x83\x5b\x78\x99\x01\x17\x52\x4b\x1f\xd3\x50\x43\xbf\x00\x11\xa2\xda\x2f\x64\xee\xf9\x2a\x81\x67\xb1\xf7\xbe\xd0\x2b\xfa\xb4\x62\x93\x55\x5c\xd3\x2a\x76\x9c\x15\x9b\xb4\x62\x9b\x55\xf4\xb5\x8a\x6b\xce\x8a\x2d\x5a\xb1\x7b\x26\x50\x53\x2a\xfa\x45\xc5\x3b\xed\x62\x65\x51\xea\x29\x22\x3c\x76\xfc\x31\x4b\xc9\xce\x82\xc7\xc3\xe3\x6d\xa2\xc7\x73\x38\x8c\xc1\x09\x38\xb6\xf8\xf1\x56\x7c\xad\x4e\x78\x48\xca\xd1\x2b\xbc\xe9\x8e\xcb\xbd\xe8\x64\xea\x17\x76\x3c\xc5\xcd\x6d\xf1\x31\xba\xa4\x5f\xba\xed\xd5\x56\x53\x57\xcb\x89\x65\x22\x08\xb6\x56\xd1\x15\x4a\x59\x1f\xca\x17\x49\x04\xd5\x0c\x7e\x8e\x83\x4b\x8c\x92\x51\xe8\x64\xb5\x0b\xc8\x0f\xbd\x4f\x74\x72\x7b\x7a\xbc\x43\xa5\xc5\x5e\x30\x1a\x4c\x47\x64\x85\xc5\xf8\xca\xd9\x6c\x8f\x25\x82\xe9\xd1\x44\x30\x8d\x59\x3b\x6c\xc1\xff\xa1\x25\x2e\xa1\xe9\xf9\x5a\x7a\x2c\x2f\x4c\x8f\xe6\x85\x69\xcc\x58\x8d\x16\xc4\x94\xef\x71\x01\xb5\x51\x47\x2f\x51\xad\xf7\x49\x7a\xfe\x2f\xe4\xa3\x4d\xd4\xa8\x9b\x10\x9b\x0c\x62\x93\x42\x64\x00\xdb\x0c\xa2\xaf\x41\xf4\x2b\x40\x6c\x31\x88\x2d\xa3\x5b\x35\xda\x8e\x02\xb1\x59\x01\x62\x9b\x41\x6c\x5b\x7b\xdd\xd2\x20\xb6\x2a\x40\xec\x30\x88\x1d\x6b\xaf\xdb\x1a\xc4\x76\x05\x88\x5d\x06\xb1\x6b\xed\x75\x47\x83\xd8\xa9\x00\x71\x8d\x41\x5c\xb3\xf6\xba\xab\x41\xec\xce\x85\x58\x88\xfd\x14\xa8\x52\x7d\x4d\xaf\xae\x7b\xc7\x08\x9a\x26\xbb\xcf\xf9\xf2\x1d\x16\x11\x29\x75\x3e\x03\x5e\x1d\x91\xae\xf5\x2c\x49\x38\x78\xba\xfc\x74\x3a\xc8\xd1\x45\x74\x7e\x81\x82\x38\x44\xa3\xe4\x0a\x05\xe9\xf9\x14\xc2\xbf\x80\x9b\xf3\xbf\xa7\x41\x6a\x24\xee\x81\x06\x02\xb4\x45\x5a\xe1\x52\x9c\x45\x79\x70\xde\xa7\x45\xe8\x2e\x61\x3d\x3e\xf1\x3e\x2b\x18\xa4\x38\x9b\x8e\x72\x94\x0c\xcb\x9a\xbf\xa0\x5b\x40\xed\x3c\x40\xcf\xd1\x79\x40\x5d\x57\xfc\xb5\x3a\x5a\x42\xf4\x55\x9f\xbd\xea\xc0\xab\x3e\xbc\xb2\x21\x39\xa2\x80\xa4\xae\xd0\x23\xe1\x73\x74\x3e\x83\x19\xae\x03\x41\xf0\x02\x42\xec\x94\x0a\xd8\x12\xc1\x90\x0e\xfd\x72\x78\x84\x20\x9c\xa4\xfc\xf1\x35\xe5\x70\xe7\x17\xe8\x57\x74\x3e\xaa\xca\xe4\xec\x4a\x95\x5f\x18\x8b\x7b\x4d\x59\x5c\xad\xf6\xba\xd8\xbe\xc9\x4e\xf6\x5a\x12\x0b\xea\xac\x40\x57\x2d\xd0\x2d\x0a\xe8\xf4\xfc\x0b\xe3\x86\xaf\x29\x37\xac\xd1\x66\x8a\xfd\xf6\x35\xe7\x7f\xb0\xdf\x2e\x21\xd2\x9a\x09\xa3\xc9\x60\x34\x39\x0c\x5f\x45\xc0\x37\x30\x6c\xa8\x05\x1a\x65\x18\xb6\x18\xf4\x16\x87\xde\x54\x31\x6c\x6a\x18\xfa\x16\x0c\xdb\x0c\x46\x9b\xc3\x68\xa9\x08\xb4\x0c\x0c\x9b\x6a\x81\x66\x19\x86\x1d\x06\xbd\xc3\xa1\xb7\x55\x0c\xdb\x1a\x86\x2d\x0b\x86\x5d\x06\xa3\xcb\x61\x74\x54\x04\x3a\x06\x86\x6d\xb5\x40\xbb\x0c\xc3\x35\x06\x7d\xed\x4c\x21\x11\x81\x61\x57\xc3\xb0\xa3\x60\x58\x29\xf1\x47\xc6\x93\x4e\x08\x5d\x6b\x85\xb4\x13\xf3\xae\xbb\x28\xac\x1c\xcf\x72\xf9\xde\x49\xd6\xa4\xf2\x50\x0a\x4a\x1a\x07\x7a\x5b\x64\xde\x5f\x4d\x46\x01\xc1\x66\x96\x23\x27\x38\x16\x67\xa6\x56\xb4\x6c\x83\x28\x2e\xae\xca\x94\xba\x6a\xf2\x0e\xb9\x64\xbd\xec\x0e\x4a\x2e\x58\xd9\x18\xd9\x53\xef\x46\x36\x3b\x6d\xaf\xb8\x14\xd9\xec\x74\x3d\x76\x57\xb2\xd9\xf5\x6f\xce\xbc\xb5\xbf\x76\x24\xc2\xc7\xfb\xaa\xc7\xfb\xaa\x07\xbb\xaf\xd2\x96\x78\x71\x9f\xa3\xdf\xe4\xfc\xb5\xee\x70\xee\x2b\x2b\xdc\x1b\x71\x34\x7f\xa3\x1e\xcd\xdf\xdc\xf6\x68\xfe\x46\x3d\x9a\xbf\x29\x3b\x9a\xcf\x53\x30\x3f\xde\x54\x3d\xde\x54\x3d\xde\x54\x29\x5f\x1e\x6f\xaa\x1e\x6f\xaa\x1e\x6f\xaa\x8a\x66\x1f\x6f\xaa\xf4\x8f\x8f\x37\x55\x8e\xc7\xc7\x9b\xaa\xc7\x9b\xaa\xc7\x9b\x2a\xf8\x7b\xbc\xa9\xaa\xa6\xc4\x7d\xbc\xa9\x7a\xbc\xa9\x7a\xbc\xa9\x92\xfe\x1e\x6f\xaa\x1e\x6f\xaa\x1e\x6f\xaa\x1e\x6f\xaa\xfe\x93\x6f\xaa\xee\xed\x8e\xea\x76\xb7\x53\x55\xee\xa5\x2a\xdc\x48\x3d\xd4\x5d\xd4\x5f\x3b\x1f\xca\xe3\x5d\xd4\xdf\xff\x2e\x4a\xbe\x3b\xea\xb5\xe7\x3a\x3a\xc9\x37\x47\xbd\xb6\x74\x6d\x04\x0f\x0f\x7f\x67\x44\xbd\x34\xc5\xad\x91\x3d\xa8\x00\xf7\xd0\x2e\xbb\x56\x02\x37\x4e\xd9\xa3\x58\x8a\x99\x6e\xea\x2b\xe2\x28\x47\x59\x3f\x99\x99\x70\x8e\x05\x3a\xc7\xf2\x35\x1d\xff\xb3\x49\x93\xcd\x4e\xd7\x7d\x28\x67\x87\xee\x68\xbe\x1a\xf7\x0d\xbe\xb6\xe9\x71\xd5\x16\x3d\xee\x3f\x3e\xb7\x61\x36\x28\x64\x08\x78\x54\x89\x08\xfd\x43\x1e\x27\x87\xea\x90\x55\x22\x5b\x1b\x1f\xfb\x53\x05\x90\x19\x09\x4d\xf9\x6c\x04\x45\xb3\x9d\xfd\x49\x2f\x6a\xbf\xa1\x25\x3a\x3e\x4b\xbc\xd1\x3a\xfa\x07\xf4\xca\x11\x4b\xe1\x2a\x98\xd8\x71\x86\x7d\xc3\xd4\x10\x48\x13\x70\x6c\x77\x8c\x27\xaf\xc9\x8c\xcf\x9f\x9e\x9e\x55\xc5\xcf\xb2\x6a\x08\xa2\xf9\x8d\x65\x99\x15\x80\xee\xac\x96\xe3\x9a\x10\xd0\x82\x18\xf9\xd7\xc9\xf4\xd8\x55\x86\x4a\xcb\xc2\xc9\xb9\xd9\xe9\x3a\x14\x22\x0d\xa7\x32\xc4\xda\x68\x55\xc5\x88\xb4\x9e\x34\xc5\x48\x31\x68\x91\xf6\xe5\xb7\x62\x38\xe7\x66\x80\x07\xe5\xa0\x5a\xfd\xb3\x8c\xa7\x36\x1f\x62\x35\xc5\x74\x19\xc5\x54\xa5\x16\x5b\x16\x51\x04\x1a\x74\x9a\x30\x8e\x51\xa5\xf2\x5d\x21\x61\x07\xe1\x5a\x89\xb6\x84\x60\xdd\xc4\x5a\x10\xaa\xfa\x5e\xed\xec\x17\x52\xb7\xc6\xd6\x14\xa9\xc2\xf0\x3a\x2b\xf2\x1a\xc4\x7a\x1e\x03\xed\xf8\xf4\x11\xe2\xa0\x58\x6e\xb4\x0a\x52\x8f\x8c\xb3\x3b\x19\x0b\x65\xae\x98\x58\xa6\x60\xf7\xad\xca\xbd\xbd\xf6\x7d\x08\xbd\xbd\xf6\xc2\x12\xaf\xb9\xc7\x6a\xe2\x6e\xaf\x6d\x8d\x6d\x01\x37\x34\x11\x0e\x6f\xb1\xc3\xef\xa4\xc9\x44\xd9\xe5\xd9\x0b\x18\x84\xaf\x10\x15\x2f\x24\xcd\xa9\x81\xe6\x34\x3d\x3f\x99\x78\x52\x4a\x84\x9a\x43\xfe\x46\x53\x06\xab\xc7\x9a\x23\xa8\x4b\x51\xbf\xb4\x55\x4c\x40\x6d\xaa\x20\xd4\x88\x71\x95\x84\x18\xd2\x06\x2f\x58\x7e\x87\x41\xc6\xb3\x64\x03\x17\x86\x2f\x04\x2f\xb2\x8b\xff\x08\x9b\xf9\xf2\xb2\x75\x0f\x5f\x80\xdd\xa3\x39\x09\x90\xbe\xa1\xd5\x46\x86\xe8\x7e\x56\x1c\x40\x5a\x7c\xd5\x31\x9a\x2f\x5f\x79\xa4\x50\xf9\x49\xb3\xd7\x7e\xa8\x63\xe6\xdd\xd2\xf5\x7d\xcd\xf3\xe5\x83\x9d\x02\xbf\x6e\x10\x67\xc2\xaa\x70\x86\xd3\x4b\xfc\xf4\x49\x6d\x50\x47\xcd\x86\xdf\x44\xfd\x6b\xd4\xfb\xff\xfe\xdf\x30\x8d\x06\xe8\x1d\xce\xe2\x68\xb4\x82\xb6\x47\x23\x94\x46\xe7\x17\x79\x86\x58\xf9\x70\xe5\xe9\xd3\x27\x47\x38\x8c\xb2\x3c\x8d\xfa\x53\x80\x1f\xc4\x21\x04\xe5\x89\x62\x94\x25\xd3\x74\x80\xe1\x4d\x3f\x8a\x83\xf4\x9a\xb0\x83\x71\xe6\xb1\x28\x0d\x29\xfc\x37\x99\xe6\x68\x0c\x3c\x7d\x00\x9c\xd5\x43\x41\x8a\xd1\x04\xa7\xe3\x28\xcf\x71\x88\x26\x69\x72\x19\x85\x38\xa4\x41\x27\xc8\x3a\x1d\x26\xa3\x51\x72\x15\xc5\xe7\x68\x90\xc4\x61\x44\xd7\x30\xa9\x34\xc6\xf9\x26\x5b\xf1\xcb\x48\x45\x2b\x03\xc5\x30\xc5\x67\x90\x84\x18\x8d\xa7\x59\x4e\x36\xea\x20\x8a\x01\x68\xd0\x4f\x2e\xc9\xa7\xc9\x35\x74\x11\xc5\x49\x1e\x0d\xb0\x47\xe3\x0a\x8d\xa2\x0c\x34\xcb\x72\x7b\x71\xa8\x21\x13\x46\xd9\x60\x14\x44\x63\x9c\xae\xb8\x70\x88\x62\x79\x20\x38\x0e\x93\x34\x09\xa7\x03\x7c\xef\x68\x20\xd6\xb5\x30\x19\x4c\x45\x1c\x0c\x52\x63\x35\x49\x59\x8c\x8c\x71\x90\xe3\x34\x0a\x46\x59\x31\xcc\x30\x37\x50\x4d\x42\x9d\xcc\xf3\xc9\xfe\xc1\x31\x3a\x3e\xdc\x3b\xf9\x79\xfb\x68\x17\x1d\x1c\xa3\x0f\x47\x87\x3f\x1d\xec\xec\xee\xa0\x57\xff\x42\x27\xfb\xbb\xa8\x77\xf8\xe1\x5f\x47\x07\xaf\xf7\x4f\xd0\xfe\xe1\xdb\x9d\xdd\xa3\x63\xb4\xfd\x7e\x07\xf5\x0e\xdf\x9f\x1c\x1d\xbc\xfa\x78\x72\x78\x74\x8c\xbe\xdf\x3e\x46\x07\xc7\xdf\xc3\x87\xed\xf7\xff\x42\xbb\xbf\x7c\x38\xda\x3d\x3e\x46\x87\x47\xe8\xe0\xdd\x87\xb7\x07\xbb\x3b\xe8\xe7\xed\xa3\xa3\xed\xf7\x27\x07\xbb\xc7\x1e\x3a\x78\xdf\x7b\xfb\x71\xe7\xe0\xfd\x6b\x0f\xbd\xfa\x78\x82\xde\x1f\x9e\xa0\xb7\x07\xef\x0e\x4e\x76\x77\xd0\xc9\xa1\x07\x8d\x9a\xd5\xd0\xe1\x1e\x7a\xb7\x7b\xd4\xdb\xdf\x7e\x7f\xb2\xfd\xea\xe0\xed\xc1\xc9\xbf\xa0\xbd\xbd\x83\x93\xf7\xa4\xad\xbd\xc3\x23\xb4\x8d\x3e\x6c\x1f\x9d\x1c\xf4\x3e\xbe\xdd\x3e\x42\x1f\x3e\x1e\x7d\x38\x3c\xde\x45\xa4\x5b\x3b\x07\xc7\xbd\xb7\xdb\x07\xef\x76\x77\x56\xd0\xc1\x7b\xf4\xfe\x10\xed\xfe\xb4\xfb\xfe\x04\x1d\xef\x6f\xbf\x7d\x6b\xed\x25\xc1\x5d\xe9\xe3\xab\x5d\xf4\xf6\x60\xfb\xd5\xdb\x5d\xda\xd2\xfb\x7f\xa1\x9d\x83\xa3\xdd\xde\x09\xe9\x4e\xf1\xab\x77\xb0\xb3\xfb\xfe\x64\xfb\xad\x87\x8e\x3f\xec\xf6\x0e\xc8\x8f\xdd\x5f\x76\xdf\x7d\x78\xbb\x7d\xf4\x2f\x8f\xc1\x3c\xde\xfd\xbf\x1f\x77\xdf\x9f\x1c\x6c\xbf\x45\x3b\xdb\xef\xb6\x5f\xef\x1e\xa3\xda\x9c\x21\xf9\x70\x74\xd8\xfb\x78\xb4\xfb\x8e\xe0\x7c\xb8\x87\x8e\x3f\xbe\x3a\x3e\x39\x38\xf9\x78\xb2\x8b\x5e\x1f\x1e\xee\xc0\x40\x1f\xef\x1e\xfd\x74\xd0\xdb\x3d\x7e\x81\xde\x1e\x1e\xc3\x68\x7d\x3c\xde\xf5\xd0\xce\xf6\xc9\x36\x34\xfc\xe1\xe8\x70\xef\xe0\xe4\xf8\x05\xf9\xfd\xea\xe3\xf1\x01\x0c\xda\xc1\xfb\x93\xdd\xa3\xa3\x8f\x1f\x4e\x0e\x0e\xdf\xd7\xd1\xfe\xe1\xcf\xbb\x3f\xed\x1e\xa1\xde\xf6\xc7\xe3\xdd\x1d\x18\xdd\xc3\xf7\xd0\xd5\x93\xfd\xdd\xc3\xa3\x7f\x11\xa0\x64\x0c\x60\xf0\x3d\xf4\xf3\xfe\xee\xc9\xfe\xee\x11\x19\x50\x18\xa9\x6d\x32\x04\xc7\x27\x47\x07\xbd\x13\xb9\xd8\xe1\x11\x3a\x39\x3c\x3a\x91\xfa\x88\xde\xef\xbe\x7e\x7b\xf0\x7a\xf7\x7d\x6f\x97\x7c\x3d\x24\x50\x7e\x3e\x38\xde\xad\xa3\xed\xa3\x83\x63\x52\xe0\x80\x36\xfb\xf3\xf6\xbf\xd0\xe1\x47\xe8\x32\x99\xa3\x8f\xc7\xbb\xf4\xa7\x44\xb1\x1e\xcc\x24\x3a\xd8\x43\xdb\x3b\x3f\x1d\x10\xb4\x59\xe1\x0f\x87\xc7\xc7\x07\x8c\x4e\x60\xc8\x7a\xfb\x6c\xb8\x57\x9e\x3e\x79\xbe\xaa\xea\xbc\xde\x05\xf9\xc5\xfd\xea\xbd\xaa\x45\x9d\xa6\x81\x8f\x45\x11\xfa\x58\xc9\x3a\x1b\x2e\xec\x82\x38\xcf\x50\x1e\xf4\xb9\xc4\x42\xaa\x7c\xfa\x7d\x64\x0d\xb6\x59\xc8\x51\x0d\x0f\x21\xdf\x43\xa8\xe9\x21\xd4\xf2\x10\x6a\x7b\x08\x75\x3c\x84\xba\x1e\x42\x6b\x1e\x42\xeb\x1e\x42\x1b\x1e\xf2\x1b\x1e\xf2\x7d\x0f\xf9\x4d\x0f\xf9\x2d\x0f\xf9\x6d\x0f\xf9\x1d\xc9\xc2\x72\x8d\xd6\x25\xdf\x08\x3c\x52\x9e\xc0\xf0\x3b\x14\x2e\xa9\x07\x6d\x6d\x30\xf8\x4d\x06\xc3\x87\x36\x0a\x38\x2d\xd6\x56\x9b\xe1\xb2\xc1\x60\xac\x4b\x78\xae\x31\x58\x5d\x86\x8b\x4f\x61\xfa\x72\xac\x65\x9f\xd5\xe5\xb8\x34\x28\x0c\xc0\x83\xe3\xd9\xa2\xb0\x08\x7c\x5f\xee\xb7\x0c\xa7\xcd\xea\x76\x18\xee\x6b\x0c\x46\x53\xc2\xd3\x67\xb0\xd6\x19\x2e\xac\xdf\x7e\xeb\xac\xfe\x42\x9e\x8b\x74\xce\x5c\x70\x3c\xd6\xa4\xb1\x6a\x32\x98\x1c\xe7\xae\x3a\x1e\xd0\xb7\x96\xd6\xf7\x2e\xab\xd3\x2a\x60\x41\xdd\x4e\x81\x33\x87\xc1\xc7\x03\xda\xf2\xb5\xbe\x43\xa1\x8e\xd4\xc1\x35\x86\x60\xb7\x18\x5c\x01\xa4\x29\x0d\x34\x45\xb6\x00\xb4\xce\xea\x48\x83\x05\x13\xd3\x29\x06\x57\xc0\x68\x49\x03\x4d\x91\x95\x10\x6a\xb2\x91\x6d\x48\xc0\xf8\x68\xac\x89\xd9\x13\x14\x8a\xd8\xe8\x50\x64\xd5\xd9\xc8\xe6\xad\x0c\x8a\x22\x1b\x2b\x40\x4f\x6e\x89\xd3\x56\x4b\x1a\xcf\x6e\xf1\x4d\xa1\xe9\x35\x0f\x3e\xc1\x50\x71\x7a\xdd\x28\x68\x8f\xd3\x94\xdf\x91\x86\x75\x8d\x95\x55\xe6\xc3\x2f\x88\x40\xcc\xc5\x06\x2b\xc8\x89\x67\x5d\x2a\xc3\x11\x5f\x83\xdf\xf2\x59\x4a\xac\xe5\x76\x51\x95\xb7\x2f\xd6\xbc\xbc\x26\xd6\x15\x90\x05\x28\xbe\x3e\x3b\x05\xed\x8b\x7e\x36\x0b\x14\xc4\x38\x31\x92\xa1\x70\x91\x36\x25\xf3\x16\x08\x43\x4c\x19\xfc\x4e\x81\x00\xf4\x73\xad\x58\x88\xd0\x60\x9b\x21\xd2\xd5\x90\x6e\xa9\x83\x2f\x3a\xed\x17\x70\xc4\xd8\x89\x05\x0d\xdf\x15\x38\x82\x81\xf8\xd2\x20\x75\x8b\x76\xc5\xc2\x63\x0b\xd8\x6f\x59\xe6\x43\x74\x40\x43\x9c\x03\x12\x0b\xae\x29\xfd\xb7\x23\x56\xb1\x3a\x40\x1d\x4b\xb9\xb6\x3a\x33\x62\x26\x8b\x4e\x21\xdf\x47\x67\x4a\x96\xec\x4f\x17\x64\x85\x58\xe6\x03\x89\x50\xcd\x0d\x0f\x35\x66\x9d\xed\xf5\xe6\xda\xc6\xc6\x06\xf9\xdd\xdd\xdd\xd9\xd8\x7d\xb5\xed\x93\xdf\xeb\x7b\xfe\xab\x57\xbd\x9d\x1e\xf9\xbd\xbd\xd1\x69\xed\xed\xb4\x77\xd5\xf9\xbe\x48\x9d\x0d\x74\x1a\xdb\xcd\xf5\x57\xbb\x5d\x68\xa0\xd7\xde\xd9\xf1\x9b\x6d\x68\x60\x67\xad\xd1\xda\xdd\x6b\x91\xdf\x6b\xdb\xdd\x9d\xb5\xee\x2e\x34\xcc\x11\x3a\xb3\xea\x03\x8e\x0e\x3e\xec\xbe\xdb\xf1\xbb\x0d\x08\xbf\x3f\x47\x87\x24\xca\x16\x5a\x24\xe9\x15\xdd\x95\x6f\x7b\x57\x44\x95\x89\x80\x84\x23\x08\x76\x77\xad\xdd\x69\xb6\x1a\x30\x82\xbb\x7b\xbd\x9d\xed\x57\xeb\xd0\xc1\x8d\xf5\x57\xdb\x3b\xbd\xbd\x5d\xf2\xdb\x6f\xb4\x9a\x9d\xf6\x1a\x0c\x4e\xaf\xb5\xd3\xdc\xf5\xf7\x1a\x67\x4e\xd5\x78\x55\xa5\xbc\x55\xb1\x5b\xd9\x4b\xc9\x2f\xb9\xa9\x99\x6f\x8e\x4f\xb1\x00\xdd\x6b\x61\x16\xe9\xb8\xbe\x79\xf7\x49\x2a\xcd\x2f\x0f\x3e\x99\x86\x4c\xa8\xec\x4e\x45\xaa\x87\xb6\x50\xcd\x2c\x80\xa8\x01\xa8\xd4\x58\x61\xf8\x20\xbd\x5c\xcc\xa8\xd4\x00\xc8\xec\x4a\x35\x80\xa6\x75\xa9\x09\xae\x44\x35\x86\xe6\xd9\x3a\xef\x23\x71\xff\x40\x48\xd1\x79\xe5\x08\x0c\xe0\xd3\xc5\xc8\x5d\x20\x85\x02\xa9\xb3\x00\x88\x9f\x9f\x7e\x77\x43\x00\x99\xe8\xd3\xef\x6e\x08\xb0\x4d\x7f\xca\xdc\x10\x60\xd3\xf8\x94\xa5\xf6\x88\xd6\xab\xab\x64\x95\x7d\x26\x87\xe6\xcb\x20\x8d\x88\x74\x6c\xb9\xa4\x0d\x46\x1e\xea\x8f\x3c\x34\x18\x79\x28\x1c\x79\x08\x8f\x2c\x0d\x05\xa9\x87\xfa\xa9\x87\x06\xa9\x87\xc2\xd4\x43\x38\xd5\x1b\x0b\x08\x2a\x01\x41\x78\xdf\x74\x19\xe9\xa7\x10\x74\x1c\x3e\xfa\xfa\xc7\x01\xf9\x38\xa0\x1f\x9b\xfa\xc7\x90\x7c\x0c\xe9\xc7\x96\xfe\x11\x0e\x0c\x98\x7e\x6c\xeb\x1f\x45\x9a\xea\x40\xcd\x4b\xcd\xbb\xa4\xdf\x0a\x5a\x4d\x09\xe1\xbf\x4b\x5b\xc8\xb7\xae\xed\x9c\x2c\x9f\x60\x84\x96\x8a\x35\xb5\xf4\xfb\xe8\x34\x3a\x3b\xab\x7f\xb1\x39\x31\x80\xd7\xce\x4b\xbf\x5b\xff\xe3\xe9\x13\x95\x35\x92\x36\xd0\xd0\xaf\xf5\x47\xde\x60\xe4\x85\xa3\x3a\x5a\x42\x17\x23\xbb\xef\xcd\x0d\x12\x0a\xb9\xe8\x65\xab\x49\x55\x6d\x16\x68\x4d\x1d\x9a\x31\xf2\x06\xb4\xf6\xba\x13\x5a\x4b\x87\x66\x4c\x95\x01\xad\xdb\x76\x42\x6b\xeb\xd0\x8c\xb9\x95\xa0\xfd\xb1\xba\xca\x20\xae\x37\x9c\x10\x3b\x3a\x44\x83\x20\x90\x3d\x4c\x3a\x99\xc4\xdc\x3a\x5d\xe4\x0b\x4a\x93\x7c\x54\xcb\xbd\x8c\x4c\xab\xcd\x69\x03\x68\x20\x5f\xc2\x23\xfb\x94\xc3\x8a\x30\x96\x14\xf9\x03\xba\x0d\x6d\x5f\x80\xdc\xa1\x5d\xb2\x26\x7d\xab\x1b\x10\xac\x97\xbe\xad\x36\x2c\x33\xe3\x26\x51\xa0\x1a\xa4\x68\x49\xa2\xd6\xf4\xf6\xd4\xda\xa9\xf5\x53\x6f\x90\x7a\x61\x0a\x23\x9e\xde\x8d\x5a\xdb\x3a\xb4\xbb\x52\xab\x0a\xed\x4e\xd4\xda\xd4\xa1\xdd\x99\x5a\x7d\x1d\xe2\x3d\x53\x6b\x0a\xb7\xd6\x25\xe4\x9a\x3a\xc8\x15\x38\x6a\x6a\x23\x57\x60\xc4\xb6\x2f\xc0\xa2\x29\xb9\xa6\x4e\x72\x85\x0d\xc0\x56\x1b\xb6\x06\xd3\x42\x43\x67\xe5\x07\x72\x3a\x06\x90\x21\xc1\xea\x57\x93\x30\xc9\x3f\x5b\xa8\xb6\x4f\x4d\x73\x07\x84\x33\x87\x96\x9e\xee\x33\x13\xde\x7d\x6a\x7e\x1b\x92\x72\xb6\x11\xd9\x67\x66\xba\xfb\xd4\x90\x16\x93\x72\x81\xb5\x5c\x8b\x95\x03\x63\x59\xd8\x11\xfa\xd6\x72\x6d\x56\x0e\x0c\x93\xfb\xa4\xdc\xc0\x5a\x0e\x0c\x98\x95\x61\xd1\xc5\xda\x3d\x96\x5a\xe3\x0e\xe6\x59\x61\x90\x07\x42\x18\x22\x0f\x96\x8d\x7f\x7e\x1a\x46\x5e\x32\x7e\x15\xe5\xd9\x49\x92\x03\xc7\xa3\x30\xe3\x9d\x20\x0f\xa8\xd5\xd6\x73\xb4\x6e\x81\x0e\x75\xde\xe2\x61\x6e\x24\x6d\x84\xf2\x46\x67\xb6\xc3\xd0\xcc\x42\x8c\x58\xbe\x45\x6a\xcc\x54\x80\x24\xd2\x64\xe7\x0c\x7d\xd9\xa2\x89\x85\x0b\x1b\x09\x51\xe2\x1f\xa8\xd5\xd4\xa9\xb5\x80\x54\xab\xd5\x8a\xa2\x4b\x88\xf0\x07\x02\x72\xa3\x4e\x40\xb5\xc9\xba\xf5\xdb\x0e\x01\x9a\x57\xa5\xc3\x51\x08\xcf\xd2\xcb\xea\xc2\xb3\x01\x8c\x09\xce\x1a\xb0\x79\x82\xb3\xad\xa3\x72\x9e\x8e\x22\x1f\x26\xcf\xb1\x03\xc6\x31\x96\xb4\x1d\xab\xab\x70\x12\x44\x90\xdd\x85\x3a\x64\x59\x0d\xa7\x26\xf4\xe4\x65\x66\x73\x29\x27\x4b\x58\xdd\xb2\x8c\x6e\x21\x9c\x7d\xb4\x85\x64\xf1\xfd\x6e\xe7\xb7\x4e\xa5\xe3\x9b\xfd\x44\xb6\x0f\x47\xb1\x7d\x8b\x33\x09\x2a\x3b\x83\xed\x0b\x77\xbd\x7d\xe5\x78\xb5\xbf\xf0\xb9\x8a\x52\xc8\xbe\x72\xa6\xda\x77\x1e\xa6\xe6\x9b\xc2\x1d\xd1\x9b\x70\x3a\xb9\x2c\x83\x45\x08\x83\xad\x16\x65\x37\xe6\xda\x04\x29\x6c\x6a\x30\x4a\xe2\x72\x06\x05\xa6\x04\xa4\x54\xa1\x5d\x80\x47\xb7\x19\x04\xfd\xfc\xc9\x20\x12\x5a\xcf\xa4\x35\x86\x26\x7c\x55\xec\xa2\xe0\xe7\x0d\xbd\xfd\x47\xb2\x45\xdc\xd0\xaf\xcd\x3c\x74\xed\xa1\xdf\x6d\x69\x3e\x6a\xb5\x19\x78\x76\x5e\xc3\xbf\xbf\x17\xd9\xda\x6f\x0c\x38\xcd\x72\x38\xb5\x59\xfd\x87\xda\x75\x9d\xba\x93\xff\x2f\x79\xf8\xbd\x5e\xaf\xbf\x70\x41\x6b\xcd\x85\x46\x00\xfd\x2f\x81\x58\xa0\xe6\x80\xd5\x9e\x0f\xeb\x07\x80\x00\xb8\x5d\xd7\x7f\xa8\xfd\x2f\x20\xe7\x86\xd8\xa9\x32\x66\x64\xd0\xbe\x14\xa0\x1c\xb0\x40\x94\x98\x79\xb1\x15\xd2\xec\xe5\xcb\x18\xb0\x9a\xfd\xf8\xe3\x8f\xb5\x56\x73\x39\x96\x91\xa2\x3f\x4a\xad\x61\xb8\x31\x0c\xcd\x03\x57\xcd\x18\xc6\x99\xed\x87\xd9\xb7\x80\xcd\x13\xff\x9d\x27\x94\x33\x99\x60\x1c\xf9\x79\x1c\xa5\x6f\x9b\x98\x87\xad\x8c\xc2\x92\x85\x2b\xf0\x6a\xcf\x18\x8a\xcf\x2c\x56\x38\xee\x5a\x57\x1c\x5b\x9b\xb9\x8d\xa9\x1c\xd4\x4c\x6d\x78\x81\x6a\xa6\x4a\x7c\x72\xf6\xdf\x6d\xf7\xbe\xc2\xd4\x94\x54\xff\x8c\xaf\xa1\x6a\x86\x07\x29\xce\x1d\xb9\x93\x1c\x13\x0a\x29\x07\xef\x71\x42\x69\x22\x43\x31\x35\xfb\xe3\x60\x50\x4c\x8f\x6c\x62\x65\x99\x21\xa5\xb0\x39\x4b\xe3\x60\x60\x99\xa9\x27\x37\xf4\x1e\xd8\x61\x1a\xc5\x4b\xda\xb3\x13\xdd\x9c\x79\x6b\x6b\x8f\x26\x4e\x7f\x07\x97\x95\x87\xbe\xba\xd7\x02\xab\x49\x0d\x3b\x43\xa6\x1d\xef\x6f\x2f\xfb\x15\x6e\x32\xcc\x5c\xd5\xf7\x79\x7f\xb1\x05\xde\xa7\xc5\x15\x46\x14\x47\x79\xcd\x12\x80\x4a\xbd\xd2\xc0\xc3\x41\x18\xf4\xd7\x37\x2c\xb1\x99\x1a\xb3\x8d\xf5\x7e\x10\x0e\x86\x58\xb9\xe3\xb0\x15\x1c\xb4\xc2\x26\xf6\x87\x0d\xf5\xdb\xdd\xaf\x40\x5c\x12\xba\x5d\xf8\x36\x35\xe8\x06\x80\x2a\xba\x67\xbb\xba\x98\x7c\xea\xdb\x95\xc5\x20\x30\xda\x55\xc5\x70\x5c\xb5\x2b\x8a\xc9\x27\x2c\xd4\xc4\x06\xa6\x4e\x3d\xb1\x53\x27\xec\x38\x2d\x80\xde\x07\x51\x0f\x53\x47\x2c\x98\x9f\xa9\xe0\xaf\x86\xc0\x50\x7d\x4f\xf9\x1f\x57\x28\xd9\x01\x71\x3f\x87\x9f\x4f\x23\xb4\x8c\x5a\x67\xe8\x57\xf6\x73\xbd\xf8\xe9\xb7\xa5\xdf\x5d\x57\xee\x48\x86\x52\x2d\x06\xe7\x58\x7a\xb6\x84\xe3\x43\xcb\xb7\x87\xa9\xb1\x9f\x84\x40\xb5\x54\x0b\x08\x90\x0e\x00\x09\xe8\x49\x66\x0d\x1c\x64\x31\x5a\x82\x86\x5c\x8a\x46\xf4\x12\x35\x1b\xce\x51\x03\xb5\x59\xad\xd6\x47\x3f\xa0\x01\x95\x73\xc9\xcf\x10\x20\x37\x66\x9d\x80\xde\xc2\xce\x51\xf1\xa1\x97\xa8\x3d\xaf\x89\x3e\xfa\x15\x0d\xd0\xaf\x28\xa4\x90\xbb\x38\xdc\xc0\xfd\xc0\x16\x74\x48\x83\xdc\x5d\x00\x79\x8a\x3b\xf9\x35\x60\xbd\x58\x46\x8d\xd9\x5a\x03\xb7\xdb\xad\x66\xdb\xdd\xd6\xea\x73\xd1\xdc\x7a\xa3\x8e\x9e\xaf\x56\xee\x0b\x81\xdf\xea\x6c\x84\x2d\xdc\xd4\xb5\x3c\xc8\x31\xa5\x64\xbd\x84\x36\x75\x1f\xda\x42\x03\x9b\x8a\x0f\x41\x93\x2f\x5f\xa2\x56\x83\xf5\x12\xa6\xdf\x9a\x5b\x14\x6d\x21\x1b\x1e\x41\x35\x6f\xad\x4a\xca\x40\xa6\x44\xe3\xca\xb6\x40\xf7\xf0\x46\x8a\x22\x10\x14\x86\x46\xe4\x13\xa4\x28\x01\x41\x59\x38\xb0\x97\x69\xc9\x8a\xc2\xd0\x5e\xa6\x2d\x2b\x09\xb1\x5e\xe6\x51\xc1\xf7\xad\x2a\xf8\x88\x2c\xbc\x32\x1c\x25\x49\x2a\xeb\xdc\x56\x61\xa3\x66\x7f\x77\x6a\x04\x62\x21\x14\x90\xe7\xe8\xe9\x0c\x35\xdd\x03\x69\xe8\x16\xd4\x03\x59\xd5\x75\x7f\x45\x6d\xd0\xa3\x0a\xc1\x50\x06\x10\xf1\x79\x21\xed\x01\x54\x28\x53\x1c\xa8\x02\xb9\xaa\x33\x20\xdf\x1e\xd5\x05\xf7\xaa\x2e\x80\xf9\xa8\xa0\x29\xb0\x4f\x4b\xa1\x24\x60\x53\xe3\x76\x9b\x22\x05\xdc\x6a\x81\xf5\xbf\x74\x80\x8d\xec\x22\x68\x76\xba\x0f\x1d\x1b\x83\xb5\xf2\x9f\xa3\x3e\x30\xd4\x03\xf2\x19\xbe\xd9\xe9\x2a\xa7\x78\xc9\x0b\x5b\xd7\x0a\x34\x9b\xed\x6a\x7a\x01\x52\x50\x81\x09\xcf\x14\xf8\x57\xd5\x0d\x0c\xfc\x46\x67\x03\x87\xeb\xe4\xc8\xdf\xea\xae\x0d\xc2\x4e\x63\x0d\x7e\x37\xd6\x1a\x61\xe8\xc3\xef\xe1\x5a\x03\x77\x36\x5a\x76\x9d\xc1\x70\x38\x68\x34\xfa\x2d\x50\x2e\x74\xd7\x3b\xeb\x7e\xc7\xa7\xbf\xdb\xc3\x8d\xf5\x61\x00\x00\xfa\x78\x18\xb4\x87\x41\x7b\x01\x75\x41\x25\xc9\x53\x62\xfb\x6c\xe8\xa4\x9a\x25\x5e\xb4\xc0\x51\x85\x38\xb3\xbc\x65\x0a\x2f\x8e\x8b\xa5\xc7\x2d\x7a\xce\x8e\xdb\x6c\xb6\x17\xdd\xa4\x49\x95\x39\xdb\xb4\xb2\x3a\x8c\x8d\xba\xd9\xb4\x3b\xb1\x3f\x6e\xd5\x77\xd8\xaa\xc9\xac\x54\xdb\xac\xad\x93\xa3\x6c\xd7\x74\x82\x4a\x37\xec\x66\x53\x77\x75\x96\xfc\x9a\xd9\x76\xb4\xb9\xb6\x41\x36\xf0\x8d\x47\xbd\xfe\x9f\xb3\x31\xff\xf5\xdc\xf2\x0e\x68\x12\x87\xe8\x77\xe1\x95\x8b\xd2\x64\x1a\x87\x68\xa0\xfa\xeb\x49\x3d\xd8\xd7\x53\xa7\xbc\x51\xaf\x01\xb8\xa2\x16\x17\x30\xe8\x17\x9b\x04\x83\xe4\x2b\xe5\x28\xfb\x90\x46\x63\x5c\x8b\xad\xdb\x58\xf6\xef\x34\x7f\xcf\xcf\xf9\xe4\xa1\x16\xeb\xe7\x4c\xa1\x08\xa6\xd3\x89\xb6\x50\xf3\x05\xff\xfd\x72\x8b\x42\xe0\x2f\x4a\x74\xc3\xdf\xfd\xff\xec\xbd\xff\x7a\xdb\x36\xb6\x28\xfa\xf7\xf4\x29\x56\xf6\x37\x8d\xa5\x98\x96\x09\x92\x92\x28\x27\x4e\x4e\x9a\x38\x6d\xce\x38\x4e\x4e\xe2\x4e\xbb\x8f\xeb\x74\xf3\x07\x64\xb1\x91\x48\x85\xa4\x6d\x79\x26\x99\xef\xbe\xc6\x7d\x8c\xfb\x0a\xf7\x51\xee\x93\xdc\x0f\x0b\x20\x09\x92\x00\x29\x3b\xe9\xec\x3d\xfb\x54\xfd\xea\x48\x24\xb0\xb0\xb0\x7e\x61\x61\x01\x58\x18\xc4\xf0\xad\x28\x36\xd4\xc6\x0b\x85\x8e\xce\xbd\x65\x46\xfb\x77\x05\x36\xe3\x63\xc5\x7c\x3c\xbd\xac\xcf\x70\x15\x64\xb9\xa0\xf9\x8b\xd4\xc3\xef\xde\xf2\xbb\x28\xcf\x14\x04\x2a\x97\xf0\x63\xd8\x83\x41\x8c\x99\x3d\x87\xf0\xa0\x16\xfc\x68\x46\xb2\xa4\xb6\x8a\x28\xb5\x9c\x99\x1d\x9f\x21\x43\x1a\xf9\x7b\xae\x17\xd1\x92\xc2\x40\xbc\x7b\x04\x62\x4b\x66\x93\x8a\x15\x37\xb5\x84\x2e\x41\xb8\x5a\x2a\xff\x70\xc6\x0b\x61\xda\xd1\x16\x21\x50\x16\xd6\xc9\xf5\x20\x36\x80\xc0\x3e\x58\xc3\x2d\x32\xb6\x03\xde\x84\x72\x1b\xb0\xf6\x50\x99\x3c\x9b\x83\xd8\xdd\xed\x09\x85\xc6\xb5\x12\x85\x87\x34\xa8\x60\xde\x7d\x8d\x8d\x39\xde\xdb\x79\xd3\x6d\x0f\xfd\x77\x5f\x69\xfb\x61\x94\x2d\xa3\x80\x0e\xcc\xe1\x1f\xab\x5e\x5b\xaf\x7a\xb5\x5e\xcd\xf1\xd5\x58\xf5\xea\x02\x5f\xb5\x16\x8c\xd0\x67\xc1\x57\xd3\x2f\x5e\x46\x9b\x74\xe4\xba\xff\x67\x2f\xa3\x5d\x78\xab\x95\x67\x6e\xca\xc5\x34\xd2\x22\x4a\xbb\x34\x6e\x34\x1e\x14\x35\x1f\x3d\x02\x8b\x2f\x7a\x15\x4f\x1e\x3f\x7e\x0c\xd3\xe1\x10\xe0\xbd\x1a\x52\xfd\x53\x83\x44\x9c\x16\x24\xe2\x0e\x87\xdb\x41\xaa\xd7\xb3\x95\xe6\xa5\xd6\x13\x52\xf5\x5b\xb9\x49\xbe\x5e\x58\xea\x36\xe1\xc8\x4a\xdd\x26\x9b\x22\xdf\xf4\x96\xc8\xd6\x21\xd9\x6d\x48\xb3\x5b\x76\xbb\xa8\xa7\xbe\x93\x00\x2a\xc1\x11\x4c\xdc\x15\x3d\xc7\x24\xbf\xa2\x87\xbb\x9d\x0b\xa6\xba\xd5\xcf\x00\x4f\x35\x0e\x28\xdc\x87\x39\x6e\x76\xfb\x07\xfb\x7a\xa1\xbb\xc2\x65\xe5\x61\x86\x39\x0f\xee\x83\x8f\xc5\x3d\xbe\x3a\xf8\x1e\xc4\x3a\xa1\x0a\x7f\x74\x56\xa2\x0b\x86\x78\xb9\xd4\x2a\x16\xdb\xc4\x5a\x2b\xdf\xfa\xc7\xdf\x90\x99\xf4\x86\xd8\xb5\x57\xb5\x4a\xea\xb1\xad\x6c\x0c\xef\xa9\x19\x50\x94\x71\x9e\x39\x99\x62\xbd\x89\x80\xc8\xdf\x10\xe9\x0d\x21\xf2\xab\x29\xdf\xd9\xca\x5f\x59\x63\xf5\x88\x87\x0b\xc8\xac\xa5\x05\xec\x16\xcd\xee\x32\xa2\xee\xf2\x8b\xde\xb4\x8b\xc7\x58\xd1\x82\xc3\x82\x30\xbb\x8c\xb4\xaa\x16\x98\xe1\xba\x50\x00\x60\xb6\xae\x99\xa7\x9d\x7d\x98\x79\x54\xb9\x5f\x98\x3b\x13\x6f\x4b\x20\xaa\x65\x3e\xe8\x59\x22\x6d\x66\x5b\x87\x9e\xe5\xd0\x41\xce\x08\x91\x5b\xaa\xb6\xfe\x4f\x59\x1a\xe5\x65\xc6\xa2\x0c\xa6\x0c\x9f\xab\xcb\x4c\x44\x19\x4c\x09\x7e\xa1\x2e\x33\x15\x65\x50\xe7\x17\x7f\x2c\xc3\xfe\xb1\x0c\xfb\xc7\x32\x6c\xdb\xdb\xfc\x63\x19\xf6\xbf\x64\x8c\x77\x3c\xb9\x75\x8c\x77\x3c\xe9\x8d\xf1\xca\x73\xb6\x76\x8c\x77\x3c\xf9\x23\xc6\xfb\xd5\x63\xbc\xe3\xc9\xb6\x31\x5e\x15\x73\xea\x31\x5e\x64\x50\xf7\xa6\xed\x72\xed\x4c\xbd\x34\xeb\x9a\xff\xd2\x4b\xb3\x9b\x89\xf3\x4f\xb9\xb8\xa0\x6c\xe7\x8f\x28\x70\x3d\x0a\xbc\x99\xe0\x9a\xea\x68\x33\x71\xa4\xe7\x3f\x4f\x1c\x91\xa5\x1b\x4b\x8c\xa4\x3c\xd1\xb7\xca\xe9\x26\xf5\xef\xed\x0f\xaf\x7f\x7d\xfd\xe2\xc5\xbb\xa3\xd3\x77\xcd\x68\xf1\x9b\x97\xbf\xbe\x3c\x79\x7e\xf4\xf3\x51\xfb\x56\xee\xb7\xaf\x7f\x3c\x79\xfe\xeb\xb3\xd7\x27\xef\x4e\x9f\x9e\x94\x35\xa5\xe6\x78\x58\xf9\xd9\x76\x61\x65\xa9\x46\xba\x48\x8a\xa4\x2d\x8d\x98\x74\xd1\x34\x9b\x5d\x13\x03\x6e\x74\xa9\xca\x73\x1e\x12\xc9\xe1\x11\x58\xce\x43\xc8\x15\x21\x11\xa9\xcf\x67\x1b\xd8\x85\x31\x3c\x80\x1b\x7e\x7a\x30\x2f\x0e\x69\xe2\x37\x6b\x88\x91\x4a\xf8\x16\x26\x2d\x5f\x04\xdd\x40\x7a\xfd\x33\x1c\xc2\x0d\x7c\x0b\x63\x95\x97\x48\xaf\xff\x9d\x41\xb5\xe0\x01\xb0\x76\x6c\xd6\xce\x50\x51\x78\xc3\xc3\x72\x3f\x37\x1e\xdf\xf0\xc7\xff\xae\x09\x05\x4b\x64\x5b\x47\x10\xe1\x75\x02\x0a\xa2\x95\x94\xd9\x70\xca\x6c\xf8\x01\xcd\x8d\x82\x30\x65\x51\x4e\x5d\xb8\xe1\x45\x6f\x34\x61\xa5\x4a\x40\xea\x64\xbc\xc1\x0b\x7e\xda\xbd\x66\x74\x6d\x76\xfd\x73\x6f\xdf\x1a\xab\x1c\x75\x69\x38\x7e\xf1\xee\x2d\xc3\x75\x63\x12\x95\x30\xc8\xf7\x4e\x68\xe2\x63\xac\x18\x36\x51\x08\xeb\xab\xec\xba\x21\x5b\xca\x62\xc7\x45\x31\x0d\x09\xc5\xcd\x13\xbf\xc1\x23\x98\x3e\x84\xdf\x3a\x22\x73\xd8\x07\x3c\x9a\xaa\xce\x8a\x52\x34\xef\x47\xf9\x9b\x24\xc3\x3c\xae\x4c\xaa\xf0\xb2\xdc\xdf\x86\xb0\x07\xaa\xdd\xd4\x05\x70\xb9\xd2\x23\x10\xf9\x22\x54\x85\xd9\xa7\xd5\xc1\xf7\x87\x80\xcd\x48\x50\x34\x6d\xd5\x77\x54\xcb\xad\x3e\x3e\xc4\x66\xf5\x9b\xab\x5b\x2d\xbf\x92\x5a\xae\x81\xda\x53\xcc\x7b\x4a\x04\xb6\x0b\x2d\x49\x82\x15\xd3\x4d\x8e\x02\xd4\xc3\x16\x57\xbf\x13\x7d\x7f\x1f\xde\xa4\xd1\x2a\xca\xa3\x2b\x0a\xeb\x64\x79\x13\x27\xab\xc8\x5b\x42\x72\x45\x53\xf8\xfe\xc5\xc0\x1a\x1e\xc0\xe6\xbd\x0b\xbb\xb0\x79\x3f\xc1\xbf\x63\xfc\xeb\x30\x33\xa3\x06\x29\x24\x9a\x37\xcf\xcf\x0f\xbc\x07\x73\x33\xed\xd8\x32\xaf\x41\x4e\x40\x38\x54\xca\x47\xcf\xa2\x57\xc3\xc0\xf3\x18\x9f\x18\x7e\x8a\x04\x63\x4d\x9e\x19\x2d\xf9\x19\xde\x76\x35\x25\x43\xfd\xc9\xe9\x6a\x9d\xa4\x5e\x7a\x53\xbb\x89\x8e\xa9\xc0\xa9\x3c\x10\x69\x57\x29\x95\xb7\xce\xa8\xb5\xff\x54\xd9\xb3\x3e\xbc\x1b\x6b\x3b\xf6\x76\x2b\x3b\x76\x6d\x5d\xc7\xee\x5a\xd5\xf9\xfa\x57\x09\x24\x97\xf9\xfa\x32\x3f\xc6\xa9\x75\xad\x2c\xa0\x93\x1e\xd2\x2c\x4a\x69\x28\x5d\x34\xe0\x47\x79\x56\x24\x84\xe6\x95\x6b\xb3\x85\xa2\xf2\xeb\x78\x59\xb0\x49\xca\xc1\xed\xa5\xf4\x00\x2c\xcb\x31\xc0\x1a\x4f\x0c\xb0\x5d\xc7\x80\x31\xb1\x9a\x95\xc5\x9d\x05\x07\xec\x9d\xfc\xaa\x79\x69\x41\x31\x69\xd6\xde\x5b\x20\xf7\xae\x01\xed\x0e\xf7\x17\x60\xa4\x16\x6f\x42\x2c\xe6\xde\xc5\xaf\xb3\x73\x8d\xb5\xdf\x42\xd4\xd8\x07\xe1\x70\x91\x8b\xe9\x75\x29\x76\xb8\x08\xd7\x97\x4a\x00\x31\x29\x6f\xeb\xc5\x11\x60\x62\x9a\xb0\x07\x6c\xa0\x2d\x6f\x4a\x90\x29\xc1\xbc\x17\xdb\xfa\xbd\x56\xf4\x14\x81\x39\x05\xd1\x94\xc1\xb3\xa2\x13\xc7\x5e\x8c\xb1\x9f\x46\xd7\xf6\xc1\x52\xc5\xd0\xfc\x2c\x49\xfd\x7e\xfa\x37\xc0\x7f\x49\x26\xc1\x57\x56\x04\xf5\x45\x31\x46\x6b\x6d\xd8\xfc\x95\x85\x77\xd0\x37\x8b\x33\x5b\xdf\x95\xcc\x42\x7b\x05\x35\x6b\xbe\x33\x9f\xa0\x55\x4b\x24\x68\xdd\x25\x83\xa0\x55\x4b\x1d\x68\xdd\x3d\x67\xa0\x40\x98\xf4\x61\x4c\xea\x28\x93\x3b\xe1\x4c\xea\x48\x93\xdb\x60\xad\xe4\x03\x17\xae\x32\x34\x12\xc5\x79\xc2\xa5\x59\xcd\xe9\xa5\x87\xc1\xbc\x42\x9d\x15\xa4\x60\x25\x46\x78\xdf\xec\xfb\x43\xa4\x8b\xae\xcc\x32\xb9\x06\x51\xa6\x7f\x35\xe2\x2d\x1b\x60\x33\x8d\x0e\x70\x47\x19\xf5\x80\x7f\xe5\x4e\x2f\x7e\xd7\xab\xc0\xe9\x82\xe6\x5e\xfb\xcd\x2d\x66\x0d\x12\xb0\x57\x11\x9b\x82\x2c\x2f\x57\x31\x76\x4e\xa1\x56\x05\x05\x0b\x37\xdb\x80\xca\x93\x56\x16\xbe\xe5\x9c\x44\x6e\xa3\xc6\xa5\x6a\x86\xa2\x69\x88\x7d\x0a\xd7\xb3\xe4\x5e\x57\xd9\x63\xa9\xec\x32\xb9\xd6\xfa\xa5\x5a\x6a\x9d\x2a\xfd\x1c\x55\x4f\x4e\x19\x17\x4e\xcf\x36\x3a\xdc\x4f\x37\x5c\xd6\x0e\xb1\x07\xfa\x42\x28\x6c\x87\x88\xfa\x76\xbb\x6f\xee\x26\x06\x1d\x66\xb5\xea\x91\x83\x5d\x1a\x30\xbe\x38\x38\x3d\xec\x5a\x2c\x3f\xdd\x90\xaa\x38\xd9\xa6\x38\x97\xaf\xd3\x0d\xe9\xe2\xa3\x28\x7b\x5c\x96\x45\x3e\x76\x8a\x77\x76\x99\xa2\x46\xf1\xeb\x44\x98\xa8\xf7\x4b\xf9\xe9\xc6\x11\xb6\x00\x06\x03\x81\x5b\x79\x34\x58\xb4\x2f\xce\x07\xeb\xa6\x37\x08\xed\xb8\x84\xc6\xad\x06\x87\x76\xdc\x80\xf6\xaa\x1f\xda\x3f\x55\xa9\x6a\xa6\xb0\x43\x3e\xa1\x69\x12\x35\x62\x0a\xb7\x9a\xed\xbd\x5d\x24\xf0\x26\xea\x90\x6c\xd6\x64\x71\xe7\x23\x79\x28\xfd\xe4\xae\x5c\xf9\xfb\x8b\x45\xbe\x46\xb9\x12\x6c\x97\x18\xb3\x42\x5c\x82\xfa\x0c\x52\x51\xfa\xb8\x2a\xad\x37\x49\x38\x58\x2c\x92\xd7\xdc\x4b\x39\xac\xc5\xc3\x64\xbc\xb4\x9d\x7d\x9b\xa0\xa3\xd7\x61\xe2\xd9\x04\xba\x6a\xa2\x37\xf0\x20\xe9\xca\xa0\xe8\xf4\xa3\x47\x15\x92\x28\xda\x45\xff\xf0\x2a\x4d\xdb\x82\x3d\xe9\xbd\x4e\xd0\xa1\xae\x3a\x25\x0c\x25\xf0\x57\xb7\x04\x5e\x8f\x79\x54\xdd\xdd\x2a\xe2\xd1\xec\xb2\xc0\x4a\x02\x83\xd1\x8e\x36\x72\x13\xe7\xce\x3d\x7f\xd5\xd3\xc6\xf1\x2d\xdb\xe8\x1a\xdb\x52\x2f\xce\xd6\x49\xd6\x29\x25\x68\x7e\xdf\x44\xc7\x5c\x31\x4e\xcf\xa4\x80\x62\x25\x87\xda\x31\x8f\x57\xdc\x66\xe0\x13\x25\xfb\x46\x3f\xad\xfd\x58\x47\xe0\xe5\x38\x04\xa2\xbd\x54\xfb\x84\xa7\x26\xf6\x41\x99\xb4\xb5\x9c\x1c\x99\xa5\x01\x50\x96\x3b\x35\x8b\xee\xf0\xd2\x3a\x95\x3f\x35\x8b\xce\x88\x72\x9a\x71\x6b\x7f\x1f\x9e\x2d\xba\x8c\xdf\xf6\xc3\xfa\x1d\x87\x8c\x7e\xd3\x08\x92\xf9\x2a\xec\x70\x39\xae\xf4\x08\xf7\xed\x4c\x6a\x51\xeb\xb4\x14\xb8\xed\xab\x6c\x48\x59\x69\x20\x39\x21\xc3\x6d\x06\x40\x0e\xc0\x6a\x00\xb0\x5a\x00\x3a\xa9\xc8\x7c\x8f\x34\xb9\xee\x20\xe2\x52\xd2\x86\xd3\x4a\x35\xde\xc3\xe0\x1f\x02\x7d\xfe\xe0\x7e\x81\x0c\xfe\xec\xb2\x1f\x4b\x49\x6b\x4e\x2b\x15\x92\x21\xe2\x83\x0a\xe2\x32\xb9\xfe\xf2\x00\xed\xcb\x44\x35\x23\x69\xf1\x5b\xab\x69\xb5\x30\x24\x1b\xdf\x1a\xc1\x4c\x7c\xdf\x3b\x69\xab\x41\xd1\x29\x62\xcd\x5f\xa9\xd7\x60\x2a\xd9\xb1\xd8\xf1\x5f\x6b\x5b\x94\x22\x48\xf3\xd5\x77\x45\xb5\xca\x97\x11\x1f\x56\xaf\x1d\x06\x7a\x80\xc1\xab\x76\x1c\xe8\xae\x7b\xa9\xc8\x5d\xb6\x52\xe1\x26\xa9\x80\x46\xcb\xfa\x7e\x27\x32\x84\xfd\x3a\xfe\x43\x78\xd0\x7c\x80\x8d\xe3\x02\x4d\xb9\x9b\xeb\xbf\xc8\x26\xa8\x2f\x8e\xe1\xc9\x61\xc6\x02\x79\x65\x0c\x12\xf6\x95\xac\x97\x8b\x14\x51\xc0\x36\xcc\x7d\xe5\x66\xba\x77\x1f\x2f\x29\xfd\x1b\x6d\x03\x5d\x78\xd9\xa2\x10\xee\xad\xee\xa2\x6f\x61\xf1\x25\xc1\xc2\xfe\x98\xd0\xf6\x2e\xbd\xce\x9d\xbf\x7d\x0c\xb1\x6a\x4f\x1f\x95\x93\x5c\x43\x11\x98\x93\x1d\xce\x5b\xc5\xe6\x24\x50\x22\x3c\x27\x83\xba\x6b\x5c\xb1\x22\x45\x77\x27\x8e\x5b\x9d\x38\xbe\x6b\x27\x8e\x5b\x9d\x38\xbe\x5d\x27\xd4\xac\xe2\xa2\x2b\x94\x2c\x4f\x20\xa5\x79\x1a\xd1\x2b\xaa\xd8\x80\x08\xe2\x70\x37\xb7\x07\xeb\xcb\x6c\x51\xa0\xa1\x22\x91\xa2\xe4\xab\x76\xc9\x2f\x4f\x4f\xac\x38\x3d\x54\x36\x6d\xb4\x55\x58\x7b\x9e\xe8\x2b\xed\x9a\xd4\xdb\x2f\xb1\x85\x52\x61\xce\xca\xc3\x4e\x5b\x58\x88\x2d\x17\x73\x8a\xaf\xd5\xfe\xcc\x4e\xb2\xff\xb1\x5d\xf3\x8e\xdb\x35\xed\xdb\x6e\xd6\xb4\xfb\xb6\x6a\xda\x1d\x1b\x35\xed\x3f\xb6\x69\x7e\xed\x6d\x9a\xf6\x96\x9b\x34\x15\x6c\xa9\x6d\xd1\xb4\xb7\xd9\xa0\x69\xeb\x8f\xe1\x97\x1b\x0f\x0f\x5c\xe7\xf3\xb9\xe1\x92\xff\x26\xdb\x35\x9b\x09\x76\xc6\xc4\xfa\xa7\xed\xe1\x2c\xd2\xed\xb0\x36\xff\xb5\xd2\xed\xdc\x69\xb7\xa5\x78\x5d\xed\xf6\x2c\xca\xdc\x2a\x21\xcf\x98\x58\xb5\x6d\x21\x63\x62\x69\xb7\x99\xb8\x5b\x26\xe4\x61\x05\x6b\x5b\x4d\x5c\x91\xd5\x62\x4c\xac\xaf\x76\x84\x58\xee\xbe\x36\x27\x4f\x6b\x93\x83\xb9\x09\x7c\xdf\x9f\x85\xe3\xd0\x90\x12\xf6\x0c\x0d\x55\xc9\x89\x35\xf3\xac\x99\xe5\xc9\xe9\x7c\x86\x8a\xbc\x3d\x8a\xaa\x33\x32\x9e\x99\x64\xec\xc9\xd9\x7f\xd4\x8d\x90\xb1\x35\xa7\x01\xcf\x19\x54\xe4\x06\xda\xb2\x91\xc9\xd4\xb6\xad\xc9\x84\xa7\x15\x12\x99\x83\xd4\x8d\xb8\xd4\x77\x1c\xcf\x9d\xca\x79\x85\xb6\x6c\x24\xf4\xcd\xc0\xa2\x66\x28\xa7\x21\x52\x37\xe2\x4c\xfd\xb1\xe3\x92\x50\x4e\x52\xd4\x70\x4d\xbf\x76\x96\x22\x26\x4f\x77\xcc\x52\x44\x26\x7f\xa4\x29\xfa\x4a\x3e\x91\x7b\xeb\x34\x45\xac\x4a\x9f\x5f\x24\xdb\x8c\xb6\x67\xe4\xfe\x91\xa6\xe8\xeb\xfb\x46\xee\xb6\x69\x8a\x94\xcc\xa9\xfb\x47\x6e\x6f\x9a\x22\xdb\xed\x4e\x53\xc4\x86\xf1\x03\xd7\x52\x79\x4b\xd6\x7f\x13\x6f\xe9\xbf\xf5\xe1\x96\xaf\x7b\xb0\xe5\x77\x3a\xb2\x72\x77\x27\x8a\xbf\x2a\xbb\x2b\x00\xfd\x5a\xec\xe0\x55\xdc\x75\x53\xdf\xe4\x3b\xf2\xd6\xeb\xe5\xcd\x40\x3c\x34\xc0\x4b\x2f\x2e\x57\x34\xce\xb3\xe6\x9d\x3c\xf2\xf1\x99\x0a\x1f\x4c\xa5\x54\x35\xd1\x68\xde\xdc\x38\x96\xeb\x59\xf3\x19\xfa\x15\xe1\xd4\x72\x3d\x6a\x59\x43\xa3\x5d\x6e\x4a\xec\xa9\xe3\xcc\x30\xcd\xa0\x65\xd3\xf9\x64\x1c\x84\xb2\x6b\xd0\xaa\xe0\x8f\x03\x73\xee\x07\x73\xbc\x00\x21\x70\x42\xdb\xb7\xe6\x2a\xc0\x74\xe6\x8f\x43\xdf\x1b\xe3\xed\xd9\xc4\x9d\x85\xbe\x1f\x74\x02\xb6\x67\xe3\x49\x60\x8d\x7d\x74\x67\x6c\xc7\xf5\xc7\xb6\xab\x02\x3c\x9e\xcd\x09\x21\x73\xc4\xd8\x9f\x98\xe3\xd0\x24\xb3\x4e\xc0\x33\xcb\x9e\xbb\x96\x87\x57\x6e\x7b\x73\x32\x73\xe6\x33\x5f\x05\xd8\xf3\x49\x30\xa6\x21\x62\x1c\x7a\x93\xd0\x25\xc4\xed\x04\x1c\xba\xe6\xd4\xf3\x38\x8d\x3d\xdb\xb4\x4d\xcb\x51\xd2\x98\x58\xae\x3d\xf6\xf9\x9d\x11\xce\x78\x6a\x4e\xe6\x3e\xed\x04\x6c\x39\x36\x71\xc7\x3e\xde\x1d\xe1\x50\xea\xf8\x96\x1b\x28\x49\x31\x36\x83\x69\x18\xe0\x05\xe2\xe1\x78\x3e\xf7\x1d\x6a\x75\x02\x9e\x5a\x3e\x1d\x87\x53\x24\xc5\xdc\x9a\xfa\xee\x6c\xa2\x64\x9e\x6b\x86\xd4\x27\xfc\xf2\x0a\xdb\x27\x93\xd9\xc4\x27\xdd\x34\xf6\xc3\xc0\x9c\xf0\x0c\x95\xd6\x38\x98\x12\xcb\x1e\xab\x00\x07\x64\xe6\xcf\x09\x47\x20\x98\x4f\x66\xd6\x64\xe6\x74\x02\xa6\xce\xcc\x9f\xcc\x02\xa4\xdd\x8c\xce\x89\xe3\x85\x4a\x1a\xd3\xb9\x4f\x9d\xa9\x8b\xd7\x88\xdb\xae\x33\xb7\xc6\xd4\xee\x04\x6c\xce\x03\x32\x0b\x03\xac\xe0\xfa\x6e\x10\x8e\x7d\x25\xc6\x96\x63\x06\x1e\x09\x02\xbc\xa4\x7d\xea\x05\xb3\x60\x32\xee\x66\x5e\x48\x67\x56\x30\x41\x05\x19\xcf\x2c\xdf\xb4\xa6\x4a\xc0\x8e\x37\x75\x5c\xc7\xc3\x39\xc2\x84\x7a\x13\xea\xb8\xdd\x18\x8f\x03\xdf\xf4\x66\x21\x62\xe2\x87\x0e\x99\xfb\xa1\xa3\x54\xe9\xc9\x7c\xe6\xba\x21\x02\x76\x6d\x42\xc6\xb6\xdf\x8d\xf1\xcc\xb5\xe9\x98\x8c\x2d\x54\x69\x3a\x99\x84\x73\x4f\xad\x20\xae\x4d\x82\xc9\x04\x3d\x7c\x2b\xf4\x1d\xdb\x22\x66\xb7\xad\x30\x4d\xdb\x9a\x06\x2e\xbf\xf3\x7d\xee\x5b\xc4\x56\x8a\x9b\x3f\x1f\xcf\xa6\xf3\x40\xe4\x37\xa5\x73\x93\xd2\x6e\xa9\x08\x26\xd4\x34\xfd\x39\x0a\xbe\x1d\x7a\xae\x3b\x0f\x94\x52\x11\x8e\xbd\xe9\x8c\x38\x08\x78\x66\x9b\x9e\x37\xb5\xba\x49\x61\x4e\x02\x6f\x62\x8f\xf9\xf5\x2e\xa6\x69\xbb\x96\x5a\x41\x88\x63\xcd\xac\x19\x9f\x7b\x99\x9e\x49\x27\x74\xda\x4d\x0a\x6b\xea\x4f\x4d\xcf\x45\xe3\xe2\x4c\x42\xcb\x9a\xcf\x95\x2a\x6d\x51\xc2\xc8\x84\x24\x1b\x07\xd6\x24\x98\x59\x93\x4e\xc0\x4e\x68\x05\x93\x70\x8e\x52\x31\xf6\x02\xc7\xf2\x68\xa8\xb4\x15\xb6\xed\x9a\x21\x41\x92\xcd\xc2\xd9\xd8\xb7\xc3\x79\x27\xe0\xc9\xd8\xf4\xa6\xf6\xd8\xe1\x0a\xe2\xcd\x27\x76\x48\xd5\xe2\x36\xf1\x4c\xcf\x47\xbb\x6d\x07\xd3\xa9\x6f\x79\xdd\x66\xd3\x25\x81\x15\xcc\x2c\x6e\xdd\xa6\x34\xf4\x28\x9d\xa8\x00\xcf\xac\xa9\x65\x05\x9c\x64\xc4\x71\x2d\x7b\x6c\xfb\x9d\x80\x3d\xcb\x9f\x53\xd7\xe3\x76\x36\x98\x13\xd3\x9e\x28\x15\xc4\x73\x89\x37\x99\x38\x88\xb1\x1f\x38\x96\x6d\x9a\xdd\xd6\x2d\xb0\x1c\xdf\xf5\xa7\x26\xda\x59\x73\xee\xce\xa6\x33\xa2\xb4\x6e\xd3\x49\x30\x26\x1e\xd2\xd8\x9c\x8c\x1d\x9f\xda\xdd\x52\x11\x92\x99\x45\x5d\x32\x43\xc0\x13\x3a\x1f\x5b\x44\x39\xe6\x85\x93\xd9\xcc\x9c\x58\xc8\x8b\xf1\x78\x32\xf6\x66\x3d\x9a\x37\x77\x4c\x6a\x8f\x39\xed\xc6\xd3\x29\xb1\x4c\xcb\x53\xca\xb1\x39\xf1\x3c\x93\xf7\xcc\xb6\x7c\x3f\x24\x7e\x37\xf3\xc8\xcc\x73\x02\x42\xd0\x6c\xfa\x6e\x68\x85\x66\xa0\xc4\x98\x50\x7b\x3a\x09\x4c\x2e\xc7\xc4\x21\x9e\x3f\xee\xb6\x6e\xd6\xd4\x71\xa7\x53\x07\xe5\x38\x9c\xbb\x94\xfa\xb3\x99\x0a\xb0\xed\xf8\xa6\x1f\xf8\xd8\x33\x4a\x66\xbe\xe3\xf6\x88\x9b\x3d\x23\x81\x19\xf8\xc8\x94\x60\x1c\xcc\xc6\xde\xc4\x56\xda\x63\x1a\xba\x9e\xe7\xa0\xd9\xa4\xb6\x43\x5c\x2f\xe8\x16\xb7\xb1\x3f\x0b\x02\xcf\x99\xf3\x91\x61\x62\x53\x7b\xaa\x04\x3c\x71\x2d\x3a\x99\x73\x63\x15\x4e\x7c\xcb\x77\xbd\x6e\x52\x4c\x1d\x77\xee\x5a\x14\x15\x64\x1c\xd2\xb9\x6f\xa9\x6d\xc5\xd4\xf5\xc6\x13\x9b\x8f\x34\x8e\x4d\xa6\xd6\x7c\xd2\x2d\x15\xae\x13\xb8\x53\x97\x70\x4f\x88\xcc\x4d\xcf\x9f\x2a\xcd\xa6\x1b\x04\x53\xd3\xe2\xcc\x23\xde\xc4\xb1\x67\xb4\xdb\x77\x9b\x99\x3e\x9d\xcf\xe7\x1e\xf7\x22\x27\x36\xa1\x96\x52\x2a\x3c\x67\x6c\x4e\x02\x8a\x9a\x17\x52\xd7\xf2\x43\xda\xed\xbb\xf9\x74\x3e\xf3\xec\x39\x1f\x19\xac\x60\x32\x9d\x11\xb5\x5f\x31\x99\x92\xa9\x3b\xe7\x43\x98\x3d\xb5\xc6\xb6\xd5\xcd\xbc\xc0\xb3\xa6\x36\x0d\x90\xc6\xd4\xb3\x26\x13\x32\x53\xd2\x38\x24\xee\xc4\x77\xf9\xd0\x64\x31\x41\xb2\xea\x41\xc0\xb6\x23\xe2\x85\xde\x34\x0c\x51\x41\x82\x90\x9a\xd4\x27\x4a\xb3\x39\x1f\x4f\x43\x67\x3e\x9d\x8b\x41\x97\x86\x64\xda\x2d\xc7\xe6\x64\x6e\x4e\xa6\xdc\x5f\x98\x5a\x64\x3a\x99\xfb\x4a\x95\x36\xbd\x89\x3d\x0d\x03\x54\x10\xcf\x0a\xdc\x99\xeb\x75\x8f\x20\x84\xd8\xf3\x99\x6b\x3a\x22\x70\x37\x33\x43\x4f\x89\x31\xf1\xa7\xc4\xf4\x6d\x6e\x8f\x6d\x12\x38\x53\xd2\x4d\x63\xcb\x0d\xfd\xe9\x74\x3e\xe6\x52\x61\x3a\xd3\xd0\x55\xda\x63\xdb\x0a\x3c\xcf\x9f\xa2\x54\x38\x66\x30\xb5\x9c\x59\xb7\x82\xd8\xc1\x8c\xfa\xd4\x44\x52\x90\x71\x30\xf3\xa9\xaf\x64\x9e\x63\x93\x70\x32\x0d\xb0\x67\xb3\x80\x98\x66\xe8\x74\xcb\xb1\x13\x04\xe3\xd0\xe1\x8e\x77\xe0\xdb\xd4\xb1\x7c\xe5\xd0\xc4\xdc\x15\x6b\x36\x43\x63\x35\x0f\x26\xe3\x29\x65\xe6\xb5\xcb\x56\xcc\x03\x7f\x32\xf7\xf8\x20\xe9\x85\x93\xb9\x47\x95\x18\x4f\x02\xc7\x21\x33\x17\x01\x3b\x9e\x33\x1d\xbb\x64\x2a\x82\xa8\xe7\x1d\xc7\x56\xab\x79\xe1\x4f\x77\x3d\xa1\xaa\xbb\x06\xed\xa7\xda\x09\xd5\x5f\xef\x76\x42\x75\x4c\xac\xed\x96\x0e\x14\xcb\x11\x5f\x3f\xfb\xe8\x5d\x97\x0e\x26\x9e\x39\xa3\x45\xc0\xdd\xf6\x83\x60\x66\x6a\x96\x0e\x7c\x7f\x32\xf5\x28\x1f\x7e\x5d\x27\xf0\xbc\x69\xdd\x75\xe9\x68\xc4\x0e\x26\x74\x6e\x4f\xd1\x92\xcd\xe9\xcc\x99\xbb\xcc\x92\xa9\x4a\x7a\x63\x67\x3e\x1f\xdb\xa8\x05\xe3\x39\x09\xed\xc9\x7c\xdb\xa8\xfe\x98\x98\x74\x6c\x71\xe3\xe3\x85\x74\xe2\x5a\xa1\x66\xe9\x60\xe6\x9b\xe3\x89\xcb\x05\xd2\xf2\x6d\x3a\x09\xc8\x7c\xcb\x46\xc8\xdc\xb5\xc3\x19\x97\xf9\xb9\xef\x10\x3f\x9c\x68\x7a\x32\xf6\xa9\x19\x84\xdc\x0d\x22\xf6\x94\x5a\x64\x3a\xbb\xcd\xd2\xc1\xd7\x3e\x47\xba\x4d\x6a\x58\x2c\x67\xea\x33\xbf\xfe\x40\xf4\xa9\x5f\x7f\xb0\xf4\xb9\x5f\x7f\xb0\xf5\xc9\x5f\x7f\x70\xf4\xd9\x5f\x7f\x18\xeb\xd3\xbf\xfe\x30\xd1\xe7\x7f\xfd\x61\xaa\x49\x00\xcb\x3b\x88\xe9\x61\x95\xfb\xc0\xf9\xfb\x25\x7f\xdf\x3e\xec\xc1\x69\x80\xd5\x95\x47\xa0\xf8\xfb\x25\x7f\xaf\xa9\x6e\x61\x75\x4b\x5b\xdd\x5a\xf2\xf7\x9a\xea\x36\x56\xb7\xb5\xd5\xed\x25\x7f\xaf\xa9\xee\x60\x75\x47\x5b\xdd\x59\xf2\xf7\x9a\xea\x63\xac\x3e\xd6\x56\x1f\x2f\xf9\x7b\x4d\xf5\x09\x56\x9f\x68\xab\x4f\x96\xfc\xbd\xa6\xfa\x14\xab\x4f\xb5\xd5\xa7\x4b\xfe\x5e\xb1\xad\x6f\xcb\xa4\xc7\x5c\x32\x54\xc0\x3d\x2e\x14\xcd\x8c\x7b\xb8\xe5\x96\x0b\x84\xaa\x96\xcf\x65\x41\x55\x2b\xe0\x72\xa0\xaa\x15\x70\x11\x50\xd5\x0a\x39\xfb\x55\xb5\x42\xce\x79\x55\x2d\xca\xb9\xae\xaa\x45\x39\xc3\x55\xb5\xe6\x9c\xd9\xaa\x5a\x73\xce\x67\x55\xad\x0b\xce\x63\x55\xad\x0b\xce\x5e\x55\xad\x05\x67\xad\xaa\xd6\x82\x73\x75\xa9\xca\x3b\xd8\x75\x74\x77\xcb\xeb\x50\xb5\xf9\xb4\x8b\xf6\x7f\x8a\x78\xee\x61\xdd\x71\xf3\x23\x1c\xc1\x8b\xe5\xb3\x76\x91\x2d\x12\x45\xf3\x66\x18\x09\x7e\x8a\x8a\xd3\x06\x72\xd6\x68\x78\x00\xd6\x39\x96\x54\xe7\x72\xad\x60\x2c\x39\x0c\x71\xbe\xa0\x09\x03\x4f\xcd\xdf\x29\x03\xf5\xfe\x3e\x7c\x8f\xd9\x88\xf5\x8d\x17\x29\x9d\x6f\x95\xa1\x7a\xb3\x28\xf3\x1c\x6f\xfa\xce\xe2\x89\x62\x4b\xa9\x46\xf7\x79\x3c\x5e\x6a\x51\xcb\x82\xbd\xe0\xc9\x7f\xe5\xe4\xd5\x4b\x4c\x51\x5c\xa4\x03\xae\x95\x73\x5b\xe5\x70\xd3\xeb\x7b\xa8\x17\x9b\x76\x9d\x30\xe5\x25\x97\x35\x2c\x96\x6d\x2c\x16\x2a\x2c\x96\x6d\x2c\x16\x32\x16\xf5\x72\xd3\x76\x39\x4d\x26\x63\x99\xa5\x9a\x9c\x39\x57\x52\xee\xed\xdb\x24\xdf\xae\x38\x4a\xb6\xe3\x28\xa9\x38\x4a\xb6\xe2\x28\x59\xd4\x12\x7c\x2f\x8a\x2c\xdc\x52\x62\xee\xa5\xc8\xd5\x2d\x11\x89\x08\x0a\xd7\x8b\xe1\x3e\xe6\x99\xc4\xd2\x02\xde\xa4\x97\xa5\x64\x59\x43\x63\xa9\x40\x63\xa1\x42\x63\xd9\x42\x63\x51\x43\xa3\x0e\x70\xd2\x82\x67\x4d\x3a\x79\x7a\xab\xdc\xe1\x5d\xa6\x64\x5a\xb1\x7d\xda\xc5\xf6\x9f\xa2\x29\xb7\x5c\xca\x81\xb9\x51\x72\x29\x4a\x76\x9c\x09\xe7\x25\xc9\x44\x32\x24\xda\x5b\xa1\x8b\xb2\x1c\x01\xa2\xf4\x2c\x9a\x65\x97\x45\xd9\x5e\x1c\x2a\x4b\xb3\x64\x44\x8b\xa6\xcd\x91\xab\x5e\xbc\x32\x65\x0b\x5e\x7c\x81\x39\xdb\x18\x1c\xc6\x49\x73\x08\x8f\x0a\xed\x2c\x9f\x3c\x01\x02\x07\xd0\xda\x36\xdd\xc6\x83\xfd\x2d\x38\xd8\x8f\x06\xfb\xbb\x5b\x6a\x8b\x06\x0b\x72\x57\x2c\x90\x8a\x5b\xe2\xc0\xb9\xd3\xc6\x80\x73\xa2\xd5\xbe\x1a\x68\x35\x2a\xfe\x14\xe9\xd8\x5b\x8d\x7a\x3f\x45\x2a\xe4\xf4\x39\xf1\x45\x52\xfc\x05\xdc\x87\xf9\x42\xa4\xc5\x67\x3f\xd4\xe7\xf8\x78\x1d\xae\xfb\x74\xc9\xea\x2c\x45\x1d\xf6\xe3\x62\xd9\x91\x4c\x7f\x81\xd9\xf4\x19\x68\x9f\xb7\x83\xdf\x03\xfe\xdd\x17\xdf\xf5\xd5\x97\x58\x9d\xb5\xe2\xf3\x26\xf1\x7b\xc0\xbf\xfb\xe2\x7b\x77\x4a\xfe\x05\xcf\xc9\x2f\x0c\x0e\x1f\x57\xbc\x25\x4f\x2f\x3d\xe4\xc9\x0f\xbc\x45\x91\xb1\x5f\xbc\xac\xe5\xec\x5f\x48\xb7\x48\x78\xc5\xa8\xd3\x99\x99\x1f\x67\x53\x83\x12\x90\x68\x73\x51\x6f\x73\x59\x6b\x73\x51\x6f\x73\x29\xb7\xb9\xd8\xa6\x4d\xc2\xfb\x49\xc5\xd0\xc0\xcf\x9b\x50\x3e\x28\xb8\x45\xda\xff\x45\x71\x69\x85\xf4\xd2\xa9\x5e\xb2\x36\xed\xe2\x1d\x4f\xc3\xdd\xdd\x26\xef\xa7\x28\x5c\xb4\xb9\xa8\xb7\xb9\xac\xb5\xb9\xa8\xb7\xb9\x94\xdb\x5c\x54\x6d\x2a\xbd\xce\xfe\x7b\x08\xd4\xb8\xfe\x05\xb3\x2f\xfd\x45\x7f\x98\xea\x2f\xa8\xbc\x7f\x89\xba\x8e\x51\xfd\x05\x8d\xc1\x5f\x22\x9d\x09\xbd\xc2\x8b\x12\x58\x99\xc5\xb2\x44\x51\xa5\x94\xbc\x20\x6b\x70\x51\xf5\x85\x9b\x8b\x9c\xc8\xe6\x62\xb1\x8d\xad\xaa\x9a\x65\x7f\x19\x45\xba\xdb\xcc\xb1\xa9\x60\xa1\x6a\x30\xb8\x53\x8b\x7f\x51\x9a\x9e\x66\x8b\x7f\x89\x54\x2d\xfe\x25\xba\x4b\x8b\x6a\x63\xd7\x6c\xf1\x27\x65\x8b\x3f\xa9\x5a\x54\x4b\x5b\xf3\xf2\x0a\x4d\x93\x18\xbc\x28\xd4\x1e\x0b\x6a\xb1\xc3\x38\x48\x61\x95\x76\xb9\x79\x44\x14\x2d\x19\xc5\x02\xd6\x76\x68\xfe\xb8\x0e\xbd\x9c\xc2\x75\xf7\x4c\x9f\x7d\x70\xbe\xa9\x94\x6f\x9c\x6e\x5e\xa8\xd0\xc6\x01\x68\xae\xaa\x83\x13\xdb\xb9\xaa\x0e\xce\xa1\xa9\xaa\x0e\x4e\xa1\xa9\xaa\x0e\x4e\xc9\x07\xe1\x12\xaf\xef\x58\xea\xee\xef\xc0\x39\xfd\x20\x5c\x60\x29\x4e\x3a\x2a\x53\x2e\x6c\x11\x4d\x7b\x13\x08\x83\x14\xa8\x70\xc4\x90\x42\xa0\xc2\x11\xa3\x17\xbe\xaa\x0e\x06\x2f\x7c\x55\x1d\x8c\x93\x78\xaa\x3a\x18\x26\x69\xdd\x66\xc0\x3e\x18\x76\x19\x70\x51\xcf\x2d\x2d\x31\x30\x70\x33\xe0\x74\x60\x92\xb5\x5b\x8d\x38\x9c\x1a\x79\xdb\xd9\xf9\xaa\x97\x95\x48\x31\x43\xf4\x0c\x7e\x40\xf9\xf7\x5a\xde\xc0\x0f\x65\x32\x8a\xc1\x0f\x28\xf7\x1e\x47\xf6\x07\x53\xc6\xd6\x6b\x23\xdb\x84\x23\x45\x19\x79\x83\x48\x22\xbf\xdd\x20\xa9\x1a\x44\xf2\xf8\xa2\xc1\x9a\x25\xf0\xfb\x1b\x94\xe2\x92\xbc\x41\x0b\x4d\x6c\xbb\x41\xab\x6a\xd0\x5a\x14\xe3\xd2\x00\xcb\x4b\xe6\xb5\xbf\x41\x29\x92\xc9\x1b\xb4\x59\x83\x61\xbb\x41\xbb\x6a\xd0\x66\x6d\x85\xa2\x41\xbb\x47\x1d\x9a\x70\xa4\xd8\x27\x6f\xd0\x61\x0d\xd2\x76\x83\x4e\xd5\xa0\xc3\xda\xa2\xa2\x41\x47\x6e\x90\xf6\x37\x28\x45\x4b\x79\x83\x63\xd6\xe0\xbc\xdd\xe0\xb8\x6a\x70\xcc\xda\x9a\x8b\x06\xc7\x72\x83\xf3\xfe\x06\xa5\xf8\x2a\x6f\x70\x82\x93\x8a\x76\x83\x93\xaa\x41\xf4\xde\x2f\x44\x83\x93\xda\x24\xa2\xbf\x41\x29\x22\xcb\x1b\x9c\xb2\x06\x17\xed\x06\xa7\x55\x83\x38\x6d\x12\x63\x32\x2b\xdf\xe5\x04\x7c\xf1\xd9\x8b\x3f\x2e\xc5\xf9\x7a\x97\xe2\x10\xe6\xdc\x8b\x9b\xcd\x18\x30\xcc\xc3\x62\x9b\x5f\xfb\x5a\x1c\x75\x33\xe4\xbf\xe4\xc5\x38\xcf\x92\xf8\x8a\xa6\x3c\xcb\x2f\xe4\x09\xd8\xd6\x9e\x1f\xe5\xcc\x41\x09\xc1\xc3\xfd\xd9\x3e\x9d\x27\x29\x15\xdb\xa9\x5b\x5c\x93\xce\x9a\x48\x6b\x77\x79\xf2\xb3\x6d\x7d\x8d\x8b\x78\xfe\x55\xaf\xe0\x91\xf1\x2c\xf3\x83\x1c\x00\x31\x2d\x67\xdf\x16\x79\x8a\xff\x38\xdd\xa4\x3d\xaa\x34\x26\xd6\x6d\x4f\x37\xb1\x2a\x3d\xa7\x9b\x6a\xdb\x1a\x5a\xa7\x9b\xc6\xc4\xfa\xe3\x74\xd3\xd7\x3e\xdd\xc4\xb8\xb2\xdd\xe9\x26\x25\x73\x6a\xa7\x9b\x38\x83\x3a\x4f\x37\xf1\x73\xb4\x5b\x9e\xfe\xb6\xff\xa5\xcf\x33\xd1\x38\xd8\xf3\xbd\x8c\x4e\x9c\xc6\x8b\x55\x38\x6e\x16\xbd\x5a\x7f\x08\xe7\x8d\x87\x41\xb4\x5e\xd0\xf4\x9f\x72\x24\x4a\x42\x15\x7f\x33\x0c\xf9\x0b\x8e\x18\x7e\x97\xf1\xf9\xef\x70\x74\xea\xa7\xad\xee\x04\xc2\xcd\x33\xcf\xb0\xeb\x65\x39\xe9\x59\xff\x51\xa8\xfd\x7d\x78\x43\xd3\x15\x8e\xa2\xcf\x16\x49\x14\x50\x20\xcd\x6b\x53\x58\xf5\x37\xcf\x48\xfd\xec\xd2\x78\x6a\x80\x33\x33\xc0\x21\x06\xd8\xb6\x01\xd6\xd8\x00\x32\x35\x60\x66\x00\x10\x69\xab\xd1\xd8\x35\x60\x6c\x1a\xe0\x58\x06\xd8\x8e\x01\xd6\xc4\x00\xe2\x1a\x40\x4c\x03\x2c\xb9\xdc\xcc\x80\x31\x31\xc0\xb1\x0d\xb0\xc7\x06\x58\x53\x03\xc8\xcc\x00\xc2\xe0\x4b\xe5\x26\xa6\x01\x63\xcb\x00\xc7\x31\xc0\x9e\x18\x30\xb1\x0d\x18\x8f\x0d\x70\xa6\x06\xd8\x33\xa9\xa0\x4d\x0c\xb0\x6c\x03\xc8\xd8\x80\xa9\x01\x30\xb1\x0c\x18\x3b\x06\x38\x78\xb5\x80\x5c\x90\x61\x62\x19\x40\x1c\x03\x26\xac\x20\x31\x60\x6c\x1b\xe0\x8c\x0d\xb0\xa7\x52\x41\x6b\x66\x80\x45\x0c\x20\xac\x49\x03\xc0\x72\x0d\xb0\x4c\x03\x08\x43\x87\x17\x3b\xef\xa0\xab\xa5\xa6\xab\x55\xa7\x2b\xc3\x82\xd1\x91\xf5\xdb\x62\xdf\x0d\x80\xb1\x8c\xad\x68\x98\x75\x8b\x61\x8b\x08\x99\x32\x96\xb6\x20\x1c\xc3\x8a\x15\x98\x18\x20\x77\x97\x4c\x38\x3d\x18\x81\x11\x7b\xbb\xce\x08\xc6\x50\x46\x60\x46\x3f\x7b\xca\x09\x3b\x1e\x37\xe8\xe5\x98\x82\x5b\x63\xce\x7d\x47\x6e\x81\xb1\x86\x89\x86\xcd\x58\x3a\xe1\x6c\x1f\xcb\x3c\x64\x2c\x60\xf2\xc0\xe4\x82\xf1\x90\x11\xb6\xf0\x6a\x6a\x37\x42\x5d\xae\x2e\x97\x1e\x5e\x93\xc2\x9c\xca\x6c\x11\xcd\x5b\x37\x3c\xa1\x16\xbc\x3c\xfd\xf5\xdd\x0f\x2f\x5f\xf0\x3b\xa5\x18\xc5\x2c\x03\xb0\xf3\x8c\x42\x2e\x93\x48\xc1\x26\xa4\xae\x90\x54\x22\xd8\x69\x09\xe9\x45\x82\xb8\x72\xfb\xef\xbe\x7b\xfd\x33\xcd\xc0\x8b\x43\x91\x1b\x7d\x8d\x2c\xe5\xf7\x69\x28\xf0\x60\xe5\x7f\x7d\x53\xe7\x67\xc3\xa5\x34\x37\xe6\x01\x4e\x46\x5c\xcb\x34\x8d\xe6\xbb\x62\xae\xc0\x8b\x28\x0a\x58\xb5\x02\xae\x69\x5a\xad\x22\xb6\x54\xa4\xfd\xd6\x91\xdf\x2a\x1a\x18\xd7\x1b\xb0\x14\x0d\x4c\xea\x48\xaa\x8a\x4c\x1b\xfd\x50\x34\xe4\xd6\x10\x69\x83\x98\x35\x5b\x69\x83\xf0\xe4\x22\xaa\x02\x7e\x93\x5a\xed\x22\x41\xa3\x99\x56\x81\xb0\xd9\x95\x76\x11\x2a\x15\x69\xb7\x30\xaf\x63\xd9\xae\xee\x76\xd5\x26\x6e\x2f\x3f\x2c\xb7\xa7\x01\xdb\xed\x91\x2a\xa7\xd9\x88\x42\x2e\xdc\x6e\xb9\x99\xb8\xbd\x82\x39\x75\xbb\x04\xd3\x75\x7b\xf9\x3d\x73\x7b\xf8\xed\x35\x91\x50\x88\x44\xb3\x99\x36\x26\x81\xdb\xcb\xf1\xd0\xed\x91\x1a\xea\x76\x4b\xf7\xbc\xd9\x86\x82\xf3\x5a\x76\x09\x2b\x41\xd4\x84\xb4\xa4\xb7\x1a\x66\xda\xb5\x22\xca\xd6\x9d\x3a\x14\x55\x1f\xc7\x72\x11\xa5\x4c\xc8\x78\x2a\xde\x4f\xeb\x68\x74\xe8\x06\xe9\x10\xff\x59\x13\x53\xad\xa1\x20\x1d\x1c\xf5\xeb\x9d\x51\x48\x45\xad\x33\x5a\x3b\x41\x3a\xe4\x97\x36\x8a\xe8\x4c\x05\x51\x9b\x02\xb7\x97\x14\xc4\xed\x25\x85\xe5\xf6\xb2\xde\x76\xbb\xd9\xe6\x34\x40\xe8\x6c\x45\x17\xb9\x27\x6e\x97\x08\x4f\xdd\x1e\x66\xb8\x6e\x0f\x25\x67\x6e\xaf\x68\x79\x6e\x37\x43\xfd\x26\xbd\x15\x83\x47\xb3\x95\x76\x91\xd0\xed\x62\x29\x75\x7b\x54\x68\xde\xe4\xa8\x7c\x47\x95\xd1\xe7\x65\x38\xa6\xe9\x3a\x26\xd1\x5a\x10\x51\x46\xeb\x66\x94\x0c\xd4\x59\x90\xa2\x11\x53\xd5\x88\x53\x6f\x44\x59\x66\x5c\x87\xa3\x44\x66\x52\x87\xa3\x2c\x33\xad\xca\x28\x5a\x91\x8d\xad\xb2\xfa\xac\xd9\x84\x02\x88\xd7\xec\x8e\xde\xe1\x10\x0d\x29\x80\x04\x35\xc2\x2a\x0a\x84\x55\x01\xad\x01\xe1\x28\x28\x2a\xcf\x9b\x5c\xd1\xfa\x5d\x9d\xc4\x24\x6e\x4f\x2f\x2c\xb7\x8b\xda\x76\xb3\x09\x95\x6c\xb8\x0d\xbe\xab\x64\xc3\xed\x27\xf8\xc4\xed\x11\xd4\xa9\xdb\x2f\xa8\xae\xdb\xc3\x94\x99\xdb\xc1\x14\xcf\xed\xd6\x25\xbf\x89\x81\xde\x90\x74\xaa\x4a\xe8\xf6\x08\x31\x6d\xd2\x54\x6f\x4f\xb4\x12\x24\x4f\x40\x14\x6f\xc9\x16\x6a\x4f\xac\x2d\x94\x89\xd8\x5b\x28\x3e\x71\xb6\x90\x67\x32\xee\x54\x7d\x32\xe9\x53\x49\x32\xed\x31\x86\xb2\x0b\xae\x86\x30\xeb\x33\x97\xc4\xeb\xd3\x7b\xe2\x6f\x61\x2d\x49\xd0\x67\xc8\x48\xb8\x85\xb1\x24\x74\x0b\x53\x46\xe6\x4d\x0e\x29\xc5\xa5\xcf\x54\x10\xd2\xa7\xa1\xc4\xda\x42\x41\x88\xdd\xa3\x65\xc4\xd9\xc6\xb0\x8d\xb7\x30\x3b\x64\xd2\x69\xdd\xc8\x74\x0b\xb3\x44\xdc\x2d\x74\x91\xcc\xb6\xd0\x7a\xe2\x6d\x61\x4d\x89\xdf\x67\xc1\x48\xd0\x65\xc2\x48\xd8\x67\x16\xe8\x16\x66\x94\xcc\x1b\x16\xea\x36\xae\x0a\x31\x1d\x8d\x31\x52\xa3\x6c\xd5\xa8\x42\xb4\x2e\x0a\x87\xad\x82\xee\x48\xef\x4d\xc5\xfb\x71\x83\x39\xed\x12\x93\x1a\xd1\x54\x6d\x4c\x6b\x25\xfa\x87\x63\xbd\x6f\x52\xb5\xa2\xf3\x4c\x8a\x9e\xea\xbc\x92\x0a\x8b\x36\x9e\x41\x83\x9a\xed\x12\x61\x8d\x5a\x3a\xd7\x04\x21\x68\xdc\x12\x51\x57\x4d\x81\xae\xee\x11\xb7\x0f\x7d\xcb\xd5\x0b\x8a\xed\xf6\x09\x8a\xe3\xf6\x31\x7a\xec\x76\x77\x7e\xe2\x76\x8b\xd2\x54\x7a\xdf\x7e\xeb\xba\x7a\xd2\xcd\xdc\x2e\xd2\x79\x6e\x9f\x78\xf9\x6e\xb7\x12\x04\x6e\xb7\xe8\x84\x6e\x9f\x60\x50\xb7\x4f\x09\xe6\x6e\x9f\x88\xd7\xdc\x0a\x8d\x10\x90\x1e\x75\x25\x56\x8f\x84\x12\xbb\xd7\x64\x10\xa7\x53\x52\xc9\xb8\x57\xe1\xc9\xa4\xd7\x6a\x90\x69\x97\x25\x76\x7b\x35\x91\xcc\x7a\x4d\x06\xf1\x3a\xb4\x91\xf8\x3d\xe6\x82\x04\xbd\x56\x8b\xc8\xe6\x40\xd1\x04\xed\xb1\xbd\x64\xde\x6b\x92\x84\x6b\xd1\xd9\x4d\xd2\xa9\x57\xc4\xea\x37\x2d\x76\x87\xe5\x20\x4e\x8f\x5a\x93\x71\xaf\x6d\x21\x93\x4e\x05\x26\xd3\x5e\xdb\x46\xdc\x1e\xe3\x43\x66\xbd\x1a\x48\xbc\x1e\x33\x40\xfc\x5e\x1b\x48\x82\x5e\x53\x40\xc2\x5e\x7b\x44\x68\x87\xb1\x23\xf3\xba\x35\xba\x8d\xff\xe0\x9a\xbc\x49\xb5\x6d\x29\xbc\x4f\x62\x3a\x1a\x57\xa2\x40\x5a\xf1\xde\xae\x20\x38\x6a\x41\x74\xf4\x42\x34\xae\x53\x44\xed\x43\x94\xce\xb1\xaa\xf9\xa9\x59\x73\xff\xf4\xe3\x67\xb1\xa2\xa2\xf6\x20\x2a\xde\xaa\xfd\x07\xfe\x5e\xed\x3b\x54\xe4\xd3\xad\xa0\x54\xe4\x51\xc0\x08\x25\x2d\xd5\x78\x0e\x85\x78\xab\x7d\x87\x8a\xc1\x9a\xfe\x77\xf2\x97\xb8\xfa\xee\x59\x6e\x1f\xf2\xb6\xdb\x47\x00\xc7\xed\x66\xf1\xd8\xed\xeb\xc2\xc4\xd5\xca\xcf\xd4\xed\x13\x3e\xd7\xed\xa2\xdf\xac\xde\xb8\xce\x89\xe8\x90\x0e\xdf\xed\xe2\x5e\xe0\xf6\x49\x5f\xe8\x76\xcb\x2f\x75\xbb\xd5\x6f\xee\xf6\x69\x08\x31\x7b\x54\x84\x90\x1e\x2d\x24\x56\xaf\x1a\x12\xbb\x6b\xa4\xe8\x94\x70\x32\xee\x55\x11\x32\x31\xfb\xf8\x44\xa6\xbd\x96\x8c\xb8\xbd\xda\x42\x66\xbd\xe6\x82\x78\xbd\x06\x8f\xf8\x3d\x36\x93\x04\xbd\x76\x83\x84\x3d\x66\x89\xd0\x0e\xbb\x44\xe6\x9d\x66\x83\x7b\x0f\xdd\x7d\x20\xbd\x7a\x49\x2c\xbd\x62\x12\xbb\x47\xed\x89\xd3\x23\xf8\x64\xdc\xab\x3b\x64\xd2\x6f\xdd\xa6\x1d\xe6\x8d\xb8\xfd\xca\x33\xeb\xb4\x1f\xc4\xeb\xb5\x7f\xc4\xef\x35\xa2\x24\xe8\x34\x22\x24\xec\xb5\x52\x84\xf6\x98\x29\x32\xaf\xdb\x91\xdb\x39\x0f\x4a\x9b\x52\xe0\xab\x5b\x21\x29\xb1\x51\xba\x0c\x07\xd2\x76\x0d\xa5\xc7\x20\x0a\x60\x3c\x45\xe9\x37\x94\x3e\x9f\xe2\xfd\xa4\x00\xa0\x2b\x30\xad\x10\x54\xbc\x95\x79\xae\x73\x19\x2a\xfc\x34\x3e\x43\xd5\x43\x45\x0b\x7e\x85\xa0\x1a\x85\xa0\x56\x40\x35\x70\x68\x75\x8f\xca\xcc\x51\x80\x9e\xd7\x88\xa3\x8e\x39\x74\xd5\x27\x6e\x0f\x71\x2d\xd7\xd4\x09\x8e\xed\x76\x0b\x8e\xe3\x76\x09\xce\xd8\xed\x91\x8b\x89\xdb\x43\xb5\xa9\xdb\x23\x7a\xae\xdb\xc3\xda\x99\xab\xa3\xbb\xe7\xf6\xf0\xd4\x77\xbb\xa5\x36\x70\x7b\xa4\x26\x74\x7b\x38\x47\xdd\x6e\xc1\x9d\xbb\x5d\x62\x4f\xcc\x4e\xb5\x25\xc4\xd4\xf2\x95\x58\x7d\x3a\x4d\xec\x3e\x9d\x24\x4e\x8f\x56\x93\x71\x9f\x52\x90\x49\x9f\xe5\x20\xd3\x1e\xdd\x2e\xc7\x3d\x2d\x1b\xc9\xac\x4f\x81\x88\xd7\x63\x1f\x89\xdf\x67\x41\x48\xd0\x69\xa1\x48\xd8\x67\x61\x08\xd5\x0f\xce\xf3\x1e\x0b\x81\xfe\x41\x37\xaf\x48\x8f\xa4\x11\xab\x47\xd3\x89\xdd\xa7\xcc\xc4\xe9\x53\x56\x32\xee\x33\x55\x13\xbd\x29\x22\xd3\x3e\x63\x41\xdc\x6e\x75\x99\xf5\x29\x3c\xf1\xb4\xc6\x82\xf8\x7d\xba\x4c\x82\x1e\x73\x41\xc2\x4e\x63\x49\x68\x9f\x29\x23\xf3\x86\xc1\xb9\x8d\x57\x20\xd0\x76\x55\x56\xa4\x80\xa9\xf2\x0b\x78\x5d\x4b\xdd\x67\xbb\x7a\x6f\xa9\x60\x3b\x15\x45\x94\xf0\xc7\x72\x7f\x54\x5e\x41\xf9\xb6\x0d\x7b\x5a\x13\x68\xed\xa8\xa8\xf4\x06\x24\xa4\xda\x80\xbd\xa2\x59\x25\xca\xbe\x10\x50\x95\x07\x20\xd1\xaa\xfd\x3e\x94\xc0\xb6\xdf\xd2\xb2\xaf\xed\x77\xf3\x1a\x95\x55\x3d\xed\x64\x12\x71\xbb\x99\x64\xb9\x9a\x1e\xd9\x6e\x17\x77\x1c\xb7\xab\x3f\x63\xb7\x5b\xea\x26\x6e\xb7\x64\x4c\x5d\x3d\x3d\x5c\xb7\x4b\x2e\x66\xae\x5e\x9e\x3d\xb7\x9b\xf5\xbe\xdb\xcd\xc3\xc0\xd5\xc8\x54\xe8\x76\xb3\x88\xba\x5d\x32\x35\x77\xbb\x45\x99\x98\x3d\x7a\x44\x48\x8f\xf0\x11\xab\x47\x53\x89\xdd\x21\x80\xc4\xe9\xd4\x53\x32\xee\x51\x45\x32\x31\x7b\x6c\xd0\xb4\x53\xe7\x4a\x0f\x56\x83\xfb\x4c\x6b\xb5\x3d\x9d\xb6\x12\xbf\xc7\xb4\x91\xa0\xc3\x2e\x92\xb0\xc7\x86\x10\xda\xa3\xb3\x64\xde\x69\xdc\xd8\x88\xae\x41\x9c\x74\x8a\x12\xb1\x3a\x95\x96\xd8\x3d\x7a\x49\x9c\x1e\xc5\x24\xe3\x0e\xcd\x24\x93\x1e\x5b\x43\xa6\xbd\xc6\xaa\x47\x93\xc8\xac\x47\x47\x89\xd7\x61\x00\x88\xdf\x69\xb5\x48\xd0\x69\x5a\x48\xa8\xd3\x7f\x42\xfb\x54\x78\x5e\x37\x3d\xb7\x1f\xba\x15\x32\x52\xa0\xea\x98\x44\x31\x74\x0b\x57\x43\x31\x68\x0b\xa0\xaa\x6a\x4e\xe9\xe4\xa8\xde\x8e\x35\xdd\x9f\x70\x90\x8a\x31\xba\x72\x99\xda\x6f\x5d\xa9\x03\xaa\x61\xba\xec\x7b\xbb\xaa\x27\x09\x79\xfb\xad\x2f\x75\x42\x35\x55\x97\xfc\x38\xc5\x30\xcd\xe9\xd6\x86\x4a\x2b\xba\xa9\x26\xe9\x92\xe7\xdb\xee\x69\x17\x19\x88\xab\x26\xaa\xe5\x76\xf1\xd7\x76\xbb\xfa\xe8\xb8\x1d\x82\x33\x76\xbb\x88\x37\x71\xbb\x7a\x32\x75\x75\xe4\x71\xdd\x0e\xb1\x9a\xb9\x5d\xac\xf6\xdc\x2e\x8e\xf8\x6e\x87\x20\x04\xae\x4e\xcc\x43\xb7\x4b\x92\xa9\xab\x96\xd8\xb9\xdb\xc1\x64\x62\x76\x72\x99\x90\x4e\x75\xb5\x3a\xf5\x95\xd8\x9d\xba\x42\x9c\x2e\x75\x20\xe3\x4e\x55\x22\x93\x4e\x85\x20\xd3\x2e\x8b\x20\xc6\x1b\xe5\xab\x59\xa7\xb5\x20\x5e\x97\xc6\x10\x5f\x63\x34\x48\xa0\x33\xb2\x61\xa7\xe6\x12\xda\x69\x14\xc8\x5c\x6b\x11\x89\xd9\xc9\x75\xd2\xa9\x88\xc4\xea\xd6\x6e\x5b\x23\x69\xc4\xe9\x54\x34\x32\xee\x52\x61\x32\xd1\xea\x21\x99\x76\x5a\x06\xe2\x76\x6a\x3f\x99\x75\xea\x22\xf1\x34\xc6\x8a\xf8\x9d\xea\x46\x82\x2e\xeb\x40\x42\xad\x16\x13\xda\x69\x39\xc8\x5c\x32\x0e\xb7\x19\x53\x5d\x36\xc0\x5b\x0a\x80\x25\x71\xda\xf6\xf8\xa0\x5a\xdc\x68\x9b\x63\x5e\xaf\x6d\x88\x05\x3c\xc5\xab\x31\x87\x67\x29\xf1\x98\x94\x2f\x55\x46\x58\x60\xa2\x1e\x67\x5c\x53\x8d\xff\xac\xec\xb7\xca\x04\x73\x3c\x55\xaf\xfc\x12\xa8\x02\xcf\xe0\x80\x1f\xf6\x68\x9b\x5f\xb5\x9c\xd0\x92\x88\x8a\x3a\x73\x81\x84\xe2\x55\xb1\xa8\xa4\xed\x39\x7f\x4d\xba\x68\x2a\xca\x58\x5d\xfc\x17\x65\xec\x2e\x5e\x8b\xe7\x4e\x17\xb1\x45\x99\xb1\x9e\xac\xa2\xc4\xa4\xb7\xcf\x53\x8d\x68\x89\xd7\x6e\x17\x45\x45\x99\x99\x8e\x4b\xe2\xbd\xa7\x97\x52\x51\xc2\xef\x92\x47\x51\x26\x50\xb3\x5c\xbc\x0d\xbb\xc4\x48\x94\xa1\x5d\x22\x2a\xca\xcc\xf5\x1a\x5a\x78\xc4\x4a\xc5\x26\x5d\x3d\x20\x96\x86\xc8\xc4\xd6\x49\x1c\x71\xba\x90\x25\xe3\x2e\xb6\x90\x49\x17\x31\xc8\xb4\xa3\x8b\x3a\xfb\x3b\xd3\xb3\x90\x78\x5d\x92\x4a\xfc\x4e\x7b\x18\x74\x69\x14\x09\xf5\xf2\x4d\xa8\x4e\xe8\xc8\xbc\x5f\xbb\xaa\xc9\x8d\xb6\x04\xe9\xb6\x05\xc4\xea\x17\x38\x62\xf7\x69\x1f\x71\x3a\xb5\x8f\x8c\xfb\x8d\x40\xc1\xec\xce\xee\x4e\xfb\x8d\x12\x71\xfb\x8d\x1b\x99\xf5\x5b\x83\x42\x1c\xba\xb4\x8c\x0b\x85\xf6\x6d\xd0\x67\xd6\xb8\x60\x74\xe0\x49\xfb\x2c\x4e\x21\x24\xd8\x8a\x34\xb2\xf3\xaf\x72\x5e\x83\x57\x5e\xf6\x21\x83\x7c\xe1\xe5\x90\xd1\x25\x0d\x72\xcc\x47\xf4\xee\xbb\xd7\x3f\x43\x14\xaf\x8b\x6b\x22\xca\x8c\x06\xaf\x9e\xbe\x6b\x5c\x5c\x5c\x1d\x4c\x34\xa0\xda\xf8\x8f\x17\x28\x8a\x1f\xf8\x5d\xfc\x30\xe4\x8a\xa6\x78\xca\x0b\xf0\x1f\xc5\x77\xf6\xc3\x90\xfa\xd3\xc4\x5c\xca\xaa\xf4\xfc\xe8\x1d\x4f\x8c\x05\x3c\xf1\x4b\xf7\x1d\x55\xac\x74\x79\x41\x15\xff\x21\x65\x49\xb9\xeb\x15\x55\xdd\xa9\xf5\x3e\xd0\x9b\x32\x05\xd8\x07\x7a\xa3\x48\x7d\xf7\x81\xde\x14\x79\xf5\x3e\xd0\x1b\x75\x5a\x3d\xd6\x06\x67\xd1\x78\x02\x7e\x94\x67\xe0\x05\x41\x92\x86\x51\x7c\x01\x79\x02\x6f\x9e\x11\x25\xdc\xef\x22\x4c\x05\x74\xd6\xcc\x81\xac\xba\x3b\x64\x3c\xd1\xdf\x1d\x52\x81\x7b\x93\x30\x80\x6f\x9e\x91\xb3\xe8\x1c\xf6\x80\x28\x72\x94\x8a\x76\x79\x7a\xfe\x41\xd1\xbb\xb3\xaa\xbe\x48\xc7\xc7\xfe\x19\xd8\x04\xf6\x24\xd0\x98\x87\x6f\x08\xf7\x5b\x80\x15\x09\x4b\x9f\x66\x19\x5d\xf9\x4b\x0a\x64\x02\xd9\xa5\xff\x81\xde\x28\xc8\x9f\x5d\xfa\x7f\xa1\x37\x59\xc9\x82\xea\xb7\x9e\x28\xf1\x3b\x2c\xc4\x49\x53\xfc\x78\x04\x64\x52\xfe\xd2\x5f\xb1\xf2\x0c\x33\x4e\x09\x7c\xd4\x84\xcc\x0a\xe8\x02\x97\x33\x01\xf4\x5c\x20\xa5\x84\xdb\x7d\x75\x8b\x1f\xe5\xef\x30\x2b\xca\xa1\x94\x04\xa5\x84\xab\x03\xc9\x05\xca\x71\x95\x02\x65\xb5\xeb\xa8\xa4\xc6\x72\xf4\x52\x53\x6f\x67\x9e\x26\x2b\x34\x30\x4b\x3a\xcf\xc1\x72\x51\x33\x58\xcb\xea\x8a\x9c\x38\x67\x83\x08\xf6\xf9\xdd\x10\x26\x26\x70\x2c\x84\x6b\x30\x78\xf3\xcc\x12\x32\x38\x84\xdd\x92\x02\x43\xf8\x16\x2c\xf7\x1c\x73\x3c\xa2\x6c\x45\xf0\x2d\xde\x71\xb1\x35\x7a\x69\x74\xb1\xd8\x1e\x3f\x07\xd3\x77\x56\x48\x0e\x6b\x58\x5a\x2e\xbe\xe6\xb8\xc2\x2e\x58\x8e\x06\xe1\xa1\x02\xe3\x56\xb3\xaa\xcc\xfe\xac\x03\x51\x1c\x50\xa0\x5e\xb0\x10\x62\x07\x51\x06\xde\x7a\xbd\x8c\x68\xc8\x78\xe9\xc5\x40\x37\x6b\x2f\x0e\x69\x58\xe4\x65\x44\xf3\x6e\x28\xa1\x31\x12\x08\x30\x81\x17\x83\x4f\xc1\x4f\x93\x0f\x34\x86\x28\xce\x13\x70\x79\x52\xe0\x0c\xb2\xc0\x5b\x72\xf0\x1c\x64\xa6\x86\x76\xbd\x88\x82\x05\x78\xcb\x65\x72\x9d\x21\x68\x06\x37\x4f\x18\xd8\xcb\x8c\x86\x70\x1d\xe5\x8b\xe4\x32\xe7\x08\x66\x51\x12\xb7\xa1\x08\x42\x63\x7a\xcd\x41\xf5\xe3\xd1\x23\x71\xad\x4c\xf5\x88\x19\x14\x9b\xa8\x28\x57\x93\x5c\xc2\x25\x77\xda\x2d\xb8\x02\x2c\x1a\xb1\xea\x3b\xda\xac\x41\xc4\x99\xf8\x00\x18\xf7\x6d\x35\xab\x74\xfd\x98\xca\xfd\x98\x9e\x8b\xc4\x9e\x9f\xe4\x47\x78\x29\x40\xeb\xaa\x1d\x85\x05\x7c\xc6\x13\x5f\x42\x14\x5f\xd1\x34\xa3\x7a\x2b\x18\xc5\x57\xef\x1a\x86\xb0\xf6\x68\xab\x01\x82\x74\x0c\x10\x15\x34\x99\x62\xd9\x19\x19\x33\x81\x6e\x42\xff\x5c\x0b\x38\x54\x3f\x68\x1c\xa4\x37\xeb\xfc\x16\x57\x01\x8a\x8c\xb5\xc9\xb3\xb2\x5e\x55\xd8\xa8\x9b\x7c\x6d\x0a\xdd\x90\xfe\x1e\xad\x56\x14\xe9\xca\xdd\xfb\xac\xbb\x65\xa3\x20\xa4\xca\xe9\xf8\x9e\xe6\xb2\x9f\x56\x47\x6e\x89\x40\xa5\xab\xb1\x9a\x3c\xe0\xc5\xd2\x66\x31\xbc\x39\x4b\xe1\x7d\xbc\x8c\xa3\x3c\xf2\x96\x72\xea\xab\x7a\x19\xba\x09\x16\x5e\x7c\x41\x8f\xdf\x56\x69\x51\x79\xe6\x31\x73\x63\xce\xf9\x7f\x4d\x91\x56\xd7\xe1\xf7\x53\xe3\x8c\x75\x3e\xd7\xd6\x79\x7b\x2c\xd7\xb1\xb0\x1d\x5b\x7c\xb6\xab\xe3\x72\xdc\xcc\xf9\x9c\xfd\xbf\x25\x6e\x58\x67\x2c\x3e\xca\xcc\xb4\x5d\x57\xb5\xf1\xf4\x61\xa8\x51\xfc\x2b\xd7\x2a\xfc\xde\x7f\x6d\x9b\x62\x24\x52\xfa\x13\x08\x4e\x77\xed\x45\x29\x18\xb2\x9c\x68\xca\xa6\xf5\xb2\xa9\x28\xab\x44\xf2\x05\x8d\xb2\x9c\x2e\x4b\x29\x56\x43\x9c\x63\xe7\xb7\x73\x2d\xdc\x6e\x03\x3d\x67\x03\x2d\x4f\xb5\x76\x16\x9d\x9f\x0d\x06\x02\xdb\xf7\x95\xb9\x66\x8e\x64\x39\x75\xc1\xdf\x98\x56\x5b\x45\x1a\x85\xc1\x6e\x28\x52\xaa\xa3\x54\x43\x93\x96\x05\x1a\xf3\x7e\x03\xfe\x63\x1c\x26\x90\x5d\x7b\x6b\xee\x7e\x2c\xbd\x2c\xe7\xc2\xd0\x36\xe1\x79\x37\xcb\x1a\xc8\xd6\x19\xd6\xa5\xf8\xb9\x42\x86\x31\xa3\xf8\x6d\x55\xbd\xa5\x1a\x5f\x4d\x05\xef\xa2\xea\x77\x31\x29\x3d\xa6\x4b\x31\x23\xcb\x21\xb9\xcc\x5b\x16\xb8\x34\xb9\xdd\x2c\xab\x99\x5c\x3d\xcf\x6a\x43\xc6\x07\x7a\xc3\x53\x40\x4f\x9c\x7d\xdb\x92\xdf\x44\x57\x9a\x17\x52\xde\xe8\x89\x32\x6b\xf4\x3e\xbc\x63\x12\x28\x26\x01\x69\x92\x65\x95\x9b\x8e\x39\x0f\xd1\x21\xc6\x69\x29\xaf\x51\x0e\x54\x15\xe1\x06\xc5\x78\xb5\xf2\xb2\x0f\x35\x95\x2d\x64\x77\x30\xa8\x89\x28\x53\xc4\x62\x74\x7d\x5f\xeb\x3a\x53\x5a\x06\x45\x22\x41\x4d\x64\xdf\xa3\xcc\xfe\x49\x29\xf8\xec\x1d\xf3\xa8\x38\x64\x51\xaa\xd0\xbb\x16\xda\x6f\x8f\xb7\x47\x3b\xd5\xa3\xbd\xec\x46\x7b\xd9\x81\x76\xba\x05\xda\x9d\x49\xa4\xb3\x22\x8b\x34\x0f\x7f\x6c\x97\x47\xba\x2f\x09\x33\x87\x95\xd3\x4d\x2e\xa7\x62\x7e\x7e\xf4\x6e\x24\x1c\xb4\x5a\x2e\x66\x03\x82\xf9\x85\x22\xb9\xf6\x7a\xe9\x31\x24\x36\x39\x34\xa1\x08\x87\x6b\x50\xb5\xa3\x02\x54\x66\x76\x6e\x07\x6a\xea\x49\xb7\x9f\x1f\xbd\x53\x66\xdc\x3e\x4d\xa3\xf5\x92\xee\xdd\x2e\x44\xc4\x2b\xd5\x02\x45\xf2\xa3\x7f\x9d\x70\x91\x08\x44\x30\xb4\x23\xcc\x50\x1a\x34\xaf\x07\x12\x5e\x2c\xcd\x08\x1c\xb2\x72\x23\x4e\xd5\x23\xce\xe3\x24\x1d\x54\xf7\xac\x8b\x8b\xe3\x8b\xa6\x47\xd9\x32\x0a\xe8\xc0\x34\xc0\x1a\xb6\xee\xc2\x28\xc1\x5a\x77\x04\x6b\x19\xe0\x74\x80\xb5\xef\x08\xd6\x31\x60\x32\xd4\x5f\xa4\x71\xe7\xb9\x07\xcd\xc8\x48\xae\x2c\xd5\xd0\x52\x66\x24\xcf\x39\xb6\xa8\x60\x6f\xd1\xc2\xd7\x99\xd3\xb0\xb6\x6e\x89\x9c\x75\xdb\xee\x93\x2d\x5a\x50\x8f\x7a\x64\x66\x7d\xb5\x61\xef\xbf\x88\x59\x2d\xad\xcb\x57\x30\xae\x15\xac\x5b\x9a\x58\x9d\x89\xab\x1b\xda\xb2\x54\x67\xfe\xfc\xb2\x54\x23\x85\xbe\x94\x98\xfd\x60\x6c\x19\x8d\xac\xfa\x52\x72\xf7\x83\xb1\x63\x54\x59\xdd\x0f\xc6\x13\x43\x24\x7b\x3f\x98\x90\xcf\xe7\x86\xeb\x7c\x51\xc2\xfd\x7f\x66\xa6\xfd\xdf\x2d\x1f\xfe\x7f\x4e\x66\x7b\xbc\xa9\x20\x8a\x69\xf8\x75\x53\xdc\x7f\xe7\x65\xb4\xca\x5a\xef\x65\x54\x7a\xf7\xb3\x6d\x75\x66\xc0\x6f\xeb\xf2\x66\xe2\x40\xec\xad\x68\xb6\x96\xb5\x74\x5f\x46\x83\x15\x61\x68\xf0\x7f\xff\xfe\x59\x05\xe6\x29\x4c\x9c\xf2\x0a\x1b\x15\x98\x9f\x27\x0e\xc3\x03\x91\xda\x4c\x9c\x91\xf8\xc1\xf0\x57\x78\x06\x15\x68\x0e\x5e\x84\x53\xa2\xbf\xd1\x0c\x3c\x88\xe9\xf5\xf2\x06\xb8\xae\x85\xaa\x86\x65\x83\x02\xb5\xdb\x3c\xe2\xcb\x95\x4f\xd3\xcf\x80\xb7\x4a\xe1\xad\x2a\xec\x8b\x6d\xa1\x3b\x3f\xea\xac\xb2\x4c\xae\xb1\x06\xfb\x57\x55\xa1\x5e\xb9\x6e\xdd\xda\x05\x0a\xba\x6c\x2a\xba\x14\x16\xa1\x20\x4f\x31\x30\xf3\xd5\x3f\xd3\x32\x6d\x9c\x95\x39\xe6\xd8\x9c\x98\xf5\x78\x67\x41\x69\x34\xf1\x71\x54\xf3\xa8\x58\x0f\x0d\x86\xb5\x7a\x0c\x13\xf7\x6b\x29\x6e\xf5\xc4\xd7\xac\xb7\x87\x50\xbf\x7d\x5b\x9e\x99\x37\x39\xf5\x5d\x94\x5f\x47\x19\x85\x93\xd7\xa7\x19\x42\xe8\x63\x4c\x71\x51\x8a\x10\x90\xcf\xf0\x94\xf1\x97\xd1\x65\x0f\x09\x23\x46\x12\x6f\x9e\xd3\x14\x62\x7a\xe1\xe5\x51\x7c\xf1\x15\x08\x8f\xa0\x28\x23\xbc\x60\xc1\x28\x4e\xf2\x81\x96\xaa\xfb\xfb\x10\x27\xbd\x9e\x2a\xde\xc9\xc2\x09\xfa\x8f\x92\xba\x0f\x95\xc5\x38\x61\xff\x51\x10\x59\xe1\x92\x0a\xca\x08\xc2\x14\xd2\x50\xb1\xf3\x61\x0d\xbb\x9a\x07\xa0\xe3\xca\xd3\x93\xe7\x12\x57\x70\x39\x01\xc7\xed\xb5\x97\xe1\xf2\xc2\x56\x3a\x54\x72\x0a\x61\x30\x95\x28\x99\x95\x27\xac\x89\x02\xee\x57\x66\xfe\xd3\x93\xe7\x5f\x87\xf5\x7c\x6d\xa7\x62\xbc\x17\x87\x03\x2f\x4e\xf2\x05\x4d\x05\x22\x5d\x62\xe0\xc5\xa1\x2c\x06\xac\x87\x3d\xa2\x50\xe9\xd9\x7d\x4e\x90\x3e\xa9\x28\x35\x4f\x94\xff\xa7\xc9\xc7\xeb\xb7\xbf\xb7\x78\xbc\x7e\xfb\x3b\x49\xc7\xeb\xb7\x5f\x47\x38\x92\xb4\x26\x1b\x49\x7a\x0b\xd1\x48\xd2\x3b\x4b\xc6\xa7\x5b\x4a\xc6\xa7\x7f\xb2\x64\xfc\xfc\xfb\x8b\xc6\xcf\xbf\x9b\x6c\xfc\xfc\xb5\x84\x63\xd3\x90\x8e\xcd\xad\xc4\x63\xf3\x05\xf2\xf1\xfe\x96\xf2\xf1\xfe\x9f\x24\x1f\xb8\x28\x2f\x4b\x46\xcc\x23\xa3\x62\x42\xb8\xa4\xf3\x7c\x7b\xaf\x2c\x46\x99\xe0\xbf\x20\x99\x97\x90\xf0\x0a\x9b\xaf\x25\x0c\x08\xec\xeb\x88\x03\x82\xaa\x09\x04\x3e\x39\x1e\x58\xe3\x2e\x39\xe0\x85\x64\x51\x88\x55\x72\xc0\xa6\x40\x31\x3c\x02\xdb\xd2\xad\x74\x49\x92\x32\xa8\x44\xe5\xd1\x23\x88\x71\x89\xbc\x14\x06\xbe\x75\xc8\x82\x3d\x88\x95\x97\xd5\xab\x45\x88\xc1\x69\xcb\xda\x67\x28\x26\x4f\xdd\x08\xc9\x60\x06\x31\xec\x29\x6e\x0c\x6d\x35\xdd\x5c\xea\x62\xcd\xfd\x67\x4a\x2f\x86\xf2\xff\x8f\x13\xdf\xb7\x03\xfd\xe4\xa2\x90\xde\xb7\x5f\x49\x7a\x39\xdf\xeb\x92\x2a\x09\x6f\x21\xcf\x5b\x08\x6f\xcb\x62\x22\xa8\x3b\xc8\xaf\xa4\x05\x25\x9c\x7e\x01\x16\xcd\xff\xd3\x25\xf8\x6d\x92\x7b\x39\xfd\xbd\x0d\x70\x8a\xad\x7c\x2d\x11\x46\x68\x5f\x47\x84\x39\x62\xb2\x08\xa7\x49\xaf\xfd\x65\x45\x7a\xe5\x57\xf4\x08\xe5\x40\x58\xf5\x78\xc8\xdc\xc1\xea\xc9\xdb\xc1\xc4\x69\x89\xe5\x97\x32\xec\x2b\xd9\x9c\x7f\x2d\x8e\xf5\x98\x1c\x56\xe2\xf6\x0c\x7b\xdb\x62\xd8\xf1\x5d\x18\xf6\x34\x0c\x7f\x6f\xcf\xd7\x0b\xc3\xdf\xc9\xf3\xe5\x57\x7e\x7f\x8d\x39\x73\xd8\x98\x33\x87\xb7\x9a\x33\x87\x5b\xcf\x99\x9b\x23\xc2\x6e\xe9\xc8\xe2\x86\x51\xb5\xf3\x1b\x78\x69\x7a\xc3\xaa\x15\x63\x08\xbf\x18\xbe\x36\xac\x54\xd7\xc3\xab\x61\xb4\x1d\xa9\xdd\xca\xe7\x86\x5d\xde\x86\xc0\xe1\x4b\x2d\x3a\xff\xa5\x5e\x5d\x79\x1a\x8b\x2b\xc0\x93\xb9\x1c\xdb\xcc\x54\x37\x1c\xa7\xc9\x9a\xa6\xf9\x0d\xfc\x5d\x5c\x31\x8c\x05\x51\xbc\x4a\x10\xad\xb0\xa2\x10\x90\x6c\xa4\x82\x53\x98\x95\xf2\x4e\xf4\xba\x75\xc9\xa2\x8b\x38\x9a\x47\x81\x17\xe7\xe0\xe3\xfb\x28\x96\x74\x03\x1b\xed\x88\xfe\x56\x71\xe9\x02\x99\xe2\xc9\x57\x88\x03\xb7\x31\xd0\xab\x63\x8d\x5c\x83\xd7\x6b\x26\x96\xde\x72\x58\xa3\x7d\x2f\xe1\x40\x69\x90\x4b\xca\x49\x60\xb7\x22\x22\xad\xb3\xf9\x0b\x74\xf5\x5a\x26\x75\xb3\x17\xb5\x35\xdf\xba\xce\x7e\x21\xb0\xb3\x56\x7d\xf6\xb9\x6d\x58\xdb\xb8\x2d\x14\xe2\x92\x19\xf1\x88\x8f\x67\x6a\x02\x12\x12\x4a\xe6\xc3\x16\x90\xf3\xff\x83\xba\x6a\x00\x31\xb7\x5e\x1e\x40\xa1\x33\x4a\xb1\x6d\x99\xe5\x6b\xb1\x79\x02\xcd\x62\xf1\x83\xff\xfb\xe9\x93\xe2\x00\x06\xf3\xfb\x4b\x1d\xb8\x77\x08\xed\x55\x30\xf9\xc3\xc7\xe6\xa2\xf8\x61\x89\x46\x73\x2f\xa0\xd6\x69\x6f\x02\xe0\x3a\xb4\xa4\xf1\x45\xbe\x80\x07\xe0\x6e\xb9\x95\xba\x69\x68\x9e\x25\xf1\x15\x4d\x8b\xa9\xa1\x64\x86\x85\x7d\x60\x83\x76\x71\x3a\x60\x2b\xc3\x53\x8c\xda\x25\x77\x6b\x2b\x73\x9f\xe1\xb4\x6e\x44\x77\x32\x08\xbd\xdc\x03\x2f\xbb\x65\x3b\x5b\x47\xb2\xea\x2b\x85\x1b\xc9\x40\x8f\xf2\xe4\x67\xdb\xd2\x2f\x85\xe0\xeb\x2f\xd8\xb3\x23\xda\xaa\x0b\x95\x62\xe7\x4e\x51\xee\x98\x33\xb3\x44\xb2\x60\xaf\x6a\x17\x0f\x67\x9b\x02\x16\xef\xee\xd6\x9b\xf7\xeb\x6d\x77\x9f\xf4\xaa\x96\xf0\x8a\x5a\x67\xad\x2d\xfc\xec\x53\xe0\x30\x5a\x5f\x66\x8b\x41\xe1\x48\x31\x1f\x41\x35\xaf\x54\x97\x6e\xf8\x12\xa0\xd8\x27\x5b\xb8\x22\x12\x83\x0b\x0b\x52\xc0\x34\xea\x6a\xa3\xdd\x48\xd2\xd2\x0a\x04\xc3\x44\x32\x48\xd6\x38\x48\x6a\xc6\x7e\xe8\x75\x5b\x4b\xb1\xa7\x10\x2c\x93\xb8\x6b\xa6\xb2\xad\x48\x23\x9c\xa6\x2c\xe3\x43\xbd\x2c\xe3\xeb\x4e\x59\x96\x21\xa3\x97\xc2\xd1\x2d\x77\xbe\xaa\x76\xba\x3e\xc3\xf2\xff\x86\x82\xfd\x6f\x9c\x32\x6d\xa0\x85\x2d\xe5\xf0\xda\x66\xb6\xd8\x35\xa6\x6f\x00\xcf\x30\x15\x0b\xeb\xdc\x39\xd1\x34\x53\xaa\xd0\x75\x4d\x7f\x7a\xd5\xe0\x7a\x1b\x1d\xb8\x16\x22\x5f\x80\x3f\x8b\xce\x55\x64\xd7\x8b\x2a\x16\xae\xad\x2f\x97\xee\xb1\x76\xdf\x4c\x63\xb7\x8c\xd8\x1a\xf3\xf9\xdc\x70\xc7\xdb\xec\x77\xd9\x7f\x70\x0f\x16\x79\xbe\xce\x0e\xf6\xf7\x57\xf9\x22\x1b\xf9\x74\xff\x32\x9f\xbb\xbf\x65\x70\x65\x8d\xc8\xc8\x02\xff\x06\xfe\xc7\xca\xcb\x17\x91\x97\x31\x89\xa9\x36\xc8\xe0\xae\x10\xbe\xd9\x63\x7f\x1f\x9e\xd3\x9c\x1f\x87\xa3\x94\x91\x3b\xf2\xfc\x25\xcd\xe0\x3f\x44\x4b\xff\xf1\xcd\x9f\x70\x1b\x7f\x4a\xe9\x51\xb9\xff\xa5\xb5\x93\x06\x76\x38\xf3\x76\xe0\xfe\xfd\xe2\xf1\x43\x3d\x78\xf8\x0f\xde\x1d\x09\xf8\x2b\x7c\x50\xc1\x5e\x89\xdf\x75\xd0\xe2\xe9\xfd\xfb\x8a\xfd\x39\x87\x35\x24\xcb\xc2\x9d\x68\x5c\xe0\xce\x99\xff\x30\xf8\x6e\xfc\x93\x24\xa4\xa3\xdf\x32\x48\x52\xf8\x8e\x6f\xa5\x89\xe6\x11\x0d\x21\x48\x42\x6a\x20\x14\x2f\x0e\xe1\x32\xa3\x10\xe5\x6c\x5c\xfb\x0f\x46\x47\xa9\x0f\x62\x1f\x4e\xd9\x87\x0b\xf1\xbb\xde\x07\xfe\xf4\x21\xdf\x93\x54\x55\x1b\x95\xa5\x0f\x65\x60\x9f\x3e\x49\xbf\x46\xd7\x51\x1c\xb2\xd9\x65\xad\x0c\xdf\x3a\xc4\x70\x01\xf9\x31\x6e\xf6\xf9\xe6\x4f\xfb\x0f\xf6\xbe\xda\xe7\xc1\xfe\x37\xbc\xb7\x59\x9e\x46\xf1\xc5\x8b\x34\x59\x3d\x5b\x78\xe9\xb3\x24\x64\x9c\x7b\x87\x0f\x47\x73\xe9\xa9\x20\xfe\xa9\xf7\x81\xc6\x9c\xc6\x4d\x91\x5d\x5f\xc6\x37\x8c\xbe\xdf\xfc\xa9\xb4\x60\x97\x41\x66\x85\x94\x3d\x1c\xf0\x76\x78\x07\x71\x69\x13\x37\xdf\x17\x43\x20\x3e\x0a\x92\xcb\x38\xa7\xa9\x88\x5c\xe2\xa3\x65\x61\x2b\x78\xf5\xca\x58\xe0\x5b\x3c\xcf\x58\xfc\xa0\x9b\x3c\xf5\xd8\x8f\xeb\x45\xb4\xa4\x30\x28\xa0\x3d\x12\x40\x78\xd3\x7f\xc2\x3a\x15\xc0\x40\x74\xef\x69\x5e\x54\xd8\xdd\x65\xaa\xfe\x27\xe4\x29\x2f\xfc\xf8\x10\xcc\xcd\x73\xd7\x34\x19\xcf\xf9\xa3\x47\xf8\xe8\xbb\x17\x2f\xd8\x23\x4d\x4b\x8c\x5c\x38\x5d\xcf\x2e\xd3\x34\xb9\xf0\x72\x6a\xa0\xd4\xe5\x0b\x9a\x52\x3c\xe7\x09\x31\xdd\xe4\xc0\x50\xf0\x82\x9c\xa6\x58\x09\xbb\xb1\x0d\x7e\x88\xe0\x80\x17\xbf\x0f\xe6\xe6\xc5\x33\xd3\x1c\x32\x09\x35\x37\xcf\xf1\xeb\xdf\x99\x71\x5e\x26\xd7\x55\xfb\x58\xed\x4f\x9c\xf2\x7c\x28\x1f\x88\x2e\x32\x00\xf6\x8b\x17\x43\x3c\x9a\x69\x0e\x61\x17\x24\xc8\xf8\x62\xb7\xc8\x38\x24\x5a\xaf\xbc\x60\xd1\xd5\xcb\x78\xe5\xe5\xc1\x82\x86\x55\x7b\x0f\x21\x89\x97\x37\xe0\xad\xd7\x14\xfb\x1d\x65\xa8\x80\x70\x19\x47\xb9\xc1\x26\x9a\x81\x97\x51\x9c\x6d\x32\x42\x94\x90\xca\x32\x8c\x48\x79\xb1\x2f\xaa\x84\xca\x86\x7a\x4f\xfa\xb9\xf6\xa2\xb4\xdd\x33\xec\x97\xc0\xf5\x4f\x82\x74\x7b\x7b\x02\xf7\x6f\x9a\x1d\xd0\xd4\x64\x05\xd9\xff\xc2\xde\xf3\x52\x85\x36\xde\x45\x19\x68\x8c\xca\x80\xa3\x70\xa5\x0b\xa5\x94\x73\xbf\xa5\x2e\xe4\x51\x1c\xd2\x0d\x1c\xc2\x1e\x51\x8a\x7d\xa9\x47\x3b\x3b\x92\xf0\xef\xee\xf2\x6a\x1a\xe1\xc7\x76\xce\xb0\xc8\x79\x53\xd8\x99\x28\xbd\x60\x1c\xe7\x94\xe1\x4f\xf7\x0e\x0b\xf6\x3f\x94\xe8\x05\xbb\x87\x0a\xfb\x51\x00\x7a\xfc\x18\x88\x59\x08\x10\x7c\x12\x3a\x24\x58\x52\x60\xc2\x85\x15\x3e\x41\x4d\x0e\x4b\xe2\x6f\xd1\x10\x02\xd4\x31\xa9\x24\x7e\xb0\xa0\xc1\x87\x77\x81\xb7\xf4\xd2\xbf\xb2\x5a\x03\xc6\x87\x37\x49\x14\xf3\xdd\xd4\x48\x80\xf2\x51\x5d\xe3\xab\xc7\x5c\xeb\x2b\xe2\xe4\x8b\x34\xb9\x86\xa3\x34\x4d\xd2\x01\xf6\x6a\xe7\x98\xb9\x42\x95\x68\xfe\xb8\xbb\x03\xbb\x15\x80\x51\x9e\x70\xcb\x3a\x20\x93\xe1\x28\x4f\x7e\x5c\xaf\x69\xfa\xcc\xcb\xe8\x60\x08\xbb\x1c\x00\x13\xf9\x38\xc9\x99\x80\x23\xb2\x9c\x2e\x3b\xec\x65\xd1\xd1\xcf\xbf\xc3\x48\x50\xd1\x09\xbd\x6a\xe6\x89\x57\xe4\x30\xf8\x32\x9b\x18\x9c\x38\x95\x15\xdc\x18\xc8\x04\x7c\x5c\xd4\xe1\x1c\xc5\x50\xe5\xc6\x35\x87\x4d\xbe\x70\x85\x78\x56\x54\x54\xb1\x45\x02\x7b\x5f\x08\xe7\x8b\x17\xae\xb0\x75\xc2\xcc\x91\x3d\xff\x26\xa7\x90\xd1\x8f\x97\x34\x0e\xd0\xd0\xe9\x11\xad\xda\x28\x44\x07\x07\xc2\x9b\x95\x9f\x2c\x4b\x45\xd2\xb5\xec\x9a\xf5\x96\xad\x76\xcb\x25\xa4\x7e\x22\x4d\x38\x81\x88\x20\xd0\x33\xb3\x44\xa9\xdc\x78\xac\x40\x02\xcd\xb0\x8c\x84\xdd\x46\xa2\x43\xe0\x1f\xde\x12\x49\x62\x71\x2c\x4d\x81\xe5\x91\x59\x03\xb1\x7b\xa8\x91\x9a\xc9\x16\x9d\x39\x32\x5b\x9d\x71\xbe\x88\xa2\xc4\x15\xc8\x4e\x39\xb2\x2f\xb6\x44\x96\x58\xb7\xed\x54\x55\x52\x85\x55\xbd\xa3\x75\x0d\x28\x65\x13\x21\x34\x55\x82\xb9\xfe\x62\x9c\x68\x3a\x4d\x25\x50\xe6\xba\xb7\x9d\xab\x96\xd7\x54\x95\xef\x1d\x54\xca\xa2\xc5\x03\xc6\x04\x6e\xad\xb6\x1c\x5c\xaa\x1e\xcb\x0d\xcb\xa3\x8c\x04\x72\xf7\xb0\x43\xf5\x1b\x16\xbd\xaa\xf6\x7b\x39\xc2\x25\xed\x53\xea\x85\xcf\x92\x38\x8f\xe2\x4b\x3c\x3c\x8b\xdc\xaf\x4c\x11\xc3\xe4\x25\xf6\xfd\xf1\x21\xa2\xf5\x8c\x39\x16\x8a\xd1\x60\xe7\x65\x7c\xe5\x2d\xa3\x10\x0b\x71\x6a\xef\x88\x6e\x95\xf4\xae\xb7\x02\x1c\x20\x06\x0a\xce\xca\x76\xce\x85\x9a\xb0\xaa\xe5\xc3\xdd\x5d\xe6\x8c\x17\x16\xaa\x01\xe6\x3e\x37\x23\xdc\x11\x64\x56\xf2\xef\x92\x31\x54\x96\xb6\x5f\x94\x88\xed\xef\xc3\xcb\x39\x5c\x53\x60\xfe\xda\xe5\x1a\x98\xa7\x6a\x40\x94\xff\x7f\xff\xd7\xff\x5d\x0c\x4b\x32\x08\xc4\xf8\x1b\x4d\xcf\x5b\x05\x77\x5a\xc6\x9f\x4b\xef\x3b\xd4\x82\x41\x25\xe5\xac\x30\x91\xc5\xd0\x92\x7f\xd8\xf2\x0f\x47\x21\xbe\x6d\x5e\x7d\x01\xab\xea\x90\x0e\xdb\x5c\x17\x94\x9d\x7b\x4b\x3c\xfc\x50\xd2\xf1\x2d\xf5\x42\x98\x47\x69\x96\x17\x54\xc2\x6e\xdd\x9e\xcd\xed\xd1\x0d\x06\x71\xd2\x26\x6f\x36\x2c\x64\x82\x37\x74\x5f\xf0\x5f\x58\x56\x09\xd7\x92\xbe\x05\xae\xed\x31\xac\x01\xe7\xa8\x10\xa8\x67\x05\x28\x64\x0b\x1c\x6a\x14\xe6\x61\xd3\x1e\xc8\xc0\x08\x9f\x66\x60\xce\x9d\x92\xbb\x2a\x07\xac\x94\xde\x4a\x7c\x25\x1b\x55\x77\xe0\x6f\x21\x82\x85\x5b\xcf\xfb\x6e\x37\x69\xbb\xf2\x6e\x20\x8a\x83\xe5\x25\x4e\x42\xd8\xe4\x42\x9e\xd2\xa8\xa8\xfc\xa2\xa0\xce\xd1\x2d\xa8\x83\xa2\x7c\x37\x02\x9a\x62\x9e\x66\xe1\xde\x24\xde\x96\x4c\x50\x5b\x47\x50\x13\x9d\x17\x4e\xb0\x3e\xff\xe0\xf7\xa4\x79\x7b\x84\x6f\x52\xd4\x15\x14\x7d\xf1\x75\x29\x8a\x26\xe3\x8e\x44\x9f\x22\xd1\xcd\x4d\x93\xec\xe6\xc6\x7c\x36\x84\x4f\x48\x91\x01\xc7\x81\x3f\x2d\xf9\xe1\x68\xf9\x81\x33\x2a\xc5\x1c\x83\x98\xf2\x14\x4c\xcd\x89\x82\x9e\x4a\x2e\xfc\x78\xfa\x62\xcf\x85\x10\x23\x65\x34\x2c\x2d\x6f\x61\x36\xc5\x09\xac\xf2\x37\x1a\x34\xe9\x37\xda\x9f\x87\x0d\x9f\x44\xf8\x1a\xd5\x68\xcc\xf1\x2b\xe1\xd5\x5d\x12\xa9\x58\x61\xd5\xb0\x15\xd9\x00\x4a\x4e\x89\x64\x63\xab\xe8\x4f\xcd\xdd\xa9\xe2\x44\xf9\x6a\x2d\x79\x23\x83\x7c\xb5\x86\xc3\xc6\x58\x32\x84\x7b\x87\x87\xdc\x28\x37\xbd\x13\xb1\x88\x91\xaf\xd6\x4d\x3f\x43\x9a\xa0\x57\xa5\x87\xbf\x67\xf0\x8d\x91\x15\x0e\x11\xc1\x9d\x2b\x9a\x66\x51\x12\xef\x1c\xc0\x0e\x06\x7d\x77\x0c\xf6\x94\xe3\xb3\x73\x20\x79\x85\xf8\x9c\x77\x57\x3c\xe7\x3f\xbe\xf9\xd3\x67\x11\xa4\x7b\x97\xac\x28\x3c\x7d\xf5\x1c\xfc\xcb\x68\x19\x42\xb2\xce\xa3\x55\xf4\x37\x9a\x66\x06\x2c\xa3\x0f\x14\xd2\xd1\x6f\x99\xc1\xa7\xc4\x18\x69\xcf\xd6\x34\x88\xe6\x51\xc0\x94\x37\x8c\x90\xe1\x6b\x2f\xcf\x69\x1a\x67\x08\x0f\x2b\xe5\x0b\x0a\xf3\x64\xb9\x4c\xae\xa3\xf8\xe2\x80\xc7\x3c\x99\xf8\x35\xce\x45\xc2\x4e\x21\x34\x3b\x3c\xb8\x5b\x2b\x30\xf2\x56\x61\x23\x8a\x5a\x1e\x91\x64\xef\xbe\xf9\x13\x67\x97\x38\x34\x59\x86\xb9\xeb\x03\x18\xeb\x33\xf2\x0e\x99\x53\xcd\x2e\x1a\x51\xe3\x7b\xd2\xef\x51\x9c\x84\xf4\xf4\x66\x4d\x2b\x67\xae\x8a\x55\x8b\x89\x47\x14\xcb\x71\xe3\xb7\x51\x7c\x91\xfc\xcf\x77\x70\x65\x8e\xdc\x91\x89\xd3\xf3\xaa\x86\x74\x96\xb4\x44\x46\x98\xc6\x02\x92\x97\x5e\x2f\xbc\x65\x03\xd2\x74\x64\xee\xf1\x40\x4c\x5a\xec\x8d\xe2\xa7\x18\xc5\xb3\x85\x97\xbd\xbe\x8e\xdf\x14\x5b\x60\x0e\x45\xa1\x51\xfd\x39\x16\x2f\x97\x48\x30\x6b\x1c\x27\x4a\x61\x31\xea\xc5\xf9\xfa\x10\x7b\x8f\x07\x89\x87\x8c\x36\x32\xad\xce\x3e\xf0\x04\x86\xac\x04\x7e\xaf\x05\xbf\x1a\xfd\x7a\xbb\x88\xe2\x84\xf5\xca\x83\x6b\xea\x83\x38\xa8\x2a\xa2\xd6\x23\x21\xd0\x82\x26\x9f\xbf\x11\x47\x54\x71\xd9\xe4\xb3\xf1\xf7\xcf\xe7\x86\x3b\xd9\x66\x49\xa4\x75\x62\xf7\xe7\x57\xc7\x3f\xe4\xf9\xfa\x2d\x1b\x32\xb2\xbc\x84\xf6\x6f\x7e\x74\xc1\x37\xb3\x8c\x7e\xcb\xfe\x6d\xdb\xc5\x16\xb9\x12\x5c\x59\x23\x73\x34\x2d\x03\x78\x17\x51\xbe\xb8\xf4\x47\x41\xb2\xda\x7f\x15\x7d\xa0\xaf\x82\xe5\xbe\x5c\x7c\xff\xf8\xe5\xb3\xa3\x93\x67\x47\xc0\x74\x58\x3e\xa8\x7c\x51\x06\xf0\x01\x00\x76\x2e\x33\x8a\xd3\xc2\x20\xdf\x79\xf8\x0d\x3e\xda\x7f\xf0\x0d\x5f\x51\x52\xb4\x2e\xde\x3c\x85\xff\xe9\x5d\x79\xef\x82\x34\x5a\xe7\xb0\x8c\xfc\xd4\x4b\x6f\x50\x41\xbd\xd4\x8f\x72\xf6\x6b\x6f\x9d\xd2\x20\x62\x76\x02\x3c\xcc\x83\x41\xf3\x28\x18\x89\xea\x5b\x76\x41\x94\x7e\x96\xac\x6f\x78\x7a\x98\x41\x30\x04\xcb\x24\x63\x78\x15\x05\x0b\x8f\x2e\xe1\x55\xb0\xf4\x2e\x2f\x16\xcb\x28\x86\x47\xaf\xdc\x60\xe1\xba\xcb\xff\x71\xb1\xf2\xa2\x25\x83\xf9\x58\xd4\x7f\xf5\xf2\x14\x8e\x36\x6b\x2f\x87\xe3\x28\xc0\x61\x5c\xac\x67\xf2\xee\xe2\xe9\xe0\xe8\xe2\x04\x5b\x35\x80\x67\x7a\x30\x60\xed\xa5\x19\x3d\xb9\x5c\xd1\x34\x0a\x8c\x6f\x8a\x45\xb6\x28\x13\x8f\xe0\x10\xf6\xdf\xef\x3d\x19\xfc\x12\xee\x0e\x7e\x19\xfd\x12\x3e\x18\x3e\xf9\xc4\xfe\xdd\x1d\x0e\xe8\xd9\xee\xde\xf9\x13\xf6\xf5\xc9\x9f\xf7\xa3\xaa\xee\xca\xcb\x17\x01\x8d\x96\x70\x08\xaf\xbc\x7c\x31\x62\xdf\xeb\x6f\xe7\xcb\x24\x49\x8b\xd7\xf8\xa3\x7a\x1f\x27\xf9\x77\x09\x0f\xfb\x88\x09\x8e\x9f\x24\x4b\xea\xc5\x4c\xc4\xfd\x28\x66\x1c\x08\xa3\x8b\x28\xdf\xa9\xea\x60\x96\xa7\x28\xbe\x78\xc5\x17\x4b\x76\x8a\xdf\xb0\x62\x26\xb9\x2a\x97\x27\xc9\x2b\x2f\xbe\x79\xce\xaa\x33\x19\xde\x11\xdb\xae\x98\x45\x64\x9a\x0e\xab\x24\x65\x76\xd5\x8b\x81\x8c\x6b\x3b\xb1\xb0\xc5\x4c\x02\xf5\xf4\xf8\xcd\x0f\x4f\xbf\x3b\x3a\x65\x50\x4c\x62\xd9\xce\x78\x32\x75\x67\x9e\x1f\x84\x74\x7e\xb1\x88\x7e\xfb\xb0\x5c\xc5\xc9\xfa\x63\x9a\xe5\x97\x57\xd7\x9b\x9b\xbf\x3d\xfd\xee\xd9\xf3\xa3\x17\xdf\xff\xf0\xf2\x7f\xfe\xe5\xf8\xd5\xc9\xeb\x37\xff\xeb\xed\xbb\xd3\x1f\xff\xfa\xd3\xcf\xff\xfe\xbf\xff\xfc\xab\x04\xf6\xbb\xa7\xef\x8e\xe0\x10\x08\x25\x4e\xf5\xf0\xf8\xf5\xf7\xbf\x16\x2f\xa4\xc7\xaf\x9e\xfe\xfc\xeb\xbb\xa7\x2f\x8e\x7e\x7d\x79\x72\x7a\xf4\xfd\xd1\x5b\x0c\xde\x92\xb9\xfc\x31\xca\xc5\x54\x36\xa9\x78\x3f\xb6\x61\x0f\xc8\x37\xd2\x33\x06\xe3\xe5\xc9\xa9\x6d\x61\xe5\x69\xab\x1a\xd4\x01\x60\x4a\xcd\x0a\xc0\x9b\xd7\x3f\xbd\xfb\xf5\xf4\xe8\x84\x39\x03\xc4\x00\x62\xb2\xff\xd9\x1f\x6a\xb3\x3f\x0e\xfb\x33\x66\x7f\x26\xec\xcf\x94\xfd\x71\xd9\x9f\x19\xfb\x83\xa5\x29\x21\xf8\xd7\xc2\xbf\xf6\x79\xd5\xbb\x77\xff\xeb\xed\x69\xd9\x6b\x3a\x35\xbe\xa9\xd0\x7e\x50\x7e\x85\x07\xfc\xd0\x75\xb4\x8a\x72\x48\xf8\x3e\x39\x1e\xb7\x4e\xe6\xf0\xfc\xe8\xd9\xcb\x57\x4f\x8f\x7f\x7d\x73\xfc\xf4\xd9\xd1\x3b\x03\x4e\x5f\xff\x7a\xf4\xf3\x9b\x5f\x4f\x8e\xbe\x2f\xbf\xbf\x79\xfd\xce\x80\x57\x2f\x4f\xd8\x0f\x03\x89\x81\x5f\xbc\x38\x94\x9b\xc8\x71\xc7\xe4\xc5\xe5\x8a\xc6\x62\x27\x76\xc2\x0c\x75\x4c\xe3\x3c\xf2\x96\x06\xe4\xc9\x8b\x68\x43\x43\xfc\x92\xa4\x2b\x2f\x17\xcb\x4a\xc9\x9b\xc2\x36\x18\xe0\xd3\x9b\x24\x0e\x8b\x14\x9e\xb1\x0c\x9e\x6e\x02\x8a\x9b\x01\xf9\xea\x4a\x9a\x5c\xc7\x30\x88\xe6\x70\xf4\xf6\xed\xeb\xb7\xef\xf0\x61\x7a\x49\x87\x23\xa9\xce\xbe\x2c\x04\x8c\x40\x47\xb3\x87\x0a\x9e\x29\x78\x68\x32\xfc\x4b\xae\x7f\x53\xb7\x84\xc5\x1e\x0e\x9e\xa9\x8a\x0f\xed\x5e\x65\x34\x98\x37\x92\xe5\xe9\x65\x90\x27\xa9\xc0\x46\x60\x52\x5a\x5d\xb1\xe9\x77\x10\x24\xf1\x3c\xba\x78\xed\xff\x56\xd8\x5f\x10\x16\x28\x8c\xae\x24\x56\x0a\xa4\xa2\x10\xf2\xd4\x0b\x3e\xf0\xc5\x25\x36\x38\xd2\xb4\x84\x69\x40\x96\x00\xd3\xd7\xd8\x5b\xd1\x22\x8d\xaa\x98\x0f\x86\x6c\x00\xa4\xcc\xd3\x06\x91\xe8\x23\x1b\xd5\x80\x47\x98\x20\xd0\xa8\x3d\x7b\x03\x87\x55\x9f\x46\xeb\x34\xc9\x13\x66\x00\xea\x85\x5e\x9f\x30\xc1\x8b\xe9\x75\x55\x74\x40\x86\xc6\x37\x0d\xdc\x1f\xf4\x7d\xe0\xe8\xf9\xcb\xd3\xa7\xdf\x1d\x1f\xc1\xf3\xa3\x17\x4f\x7f\x3c\x3e\x7d\x07\xbd\x75\x4a\x93\xad\x92\x78\x28\xa5\x3e\xa4\x73\xef\x72\x99\x17\x49\x64\x7d\xba\x4c\xae\x61\x75\x99\xe5\x9c\x40\x39\xbd\xa0\x69\x86\x3b\xc7\xc5\x0e\x52\x24\x5a\x16\x5d\x51\x48\xbd\xf8\x82\x66\x90\xe1\x66\xfb\x91\x0a\xb8\x00\xca\xc8\xed\x2d\x33\xcc\x31\xcb\xf3\x7c\x85\xe0\xe5\x90\x5e\xc6\x7b\x79\xb4\xa2\x70\x99\x31\x33\x5b\x51\x93\xf3\xbd\x09\x71\xbf\xc5\x71\xd6\xc4\xca\xdb\x44\xab\xcb\x95\xb4\xf7\x35\xa4\x41\xb4\xf2\x96\xb0\x5e\x7a\x01\xcd\x70\xa0\x65\x0e\x93\xc7\xb3\xc8\x44\xf1\x55\xb2\xbc\x62\xed\x85\xd1\x15\xaa\x55\xbd\x9d\xba\xbe\xc3\x21\x58\xa6\xca\x90\xd5\xd4\x60\x1b\x3a\xd7\x46\x13\x91\x69\x77\x41\xe3\xea\xb9\x38\x9b\xe1\xf9\xc9\x15\x6d\xf4\x81\x5b\x02\x2c\x8e\xa4\x6a\xc2\xef\xb3\x24\x6d\x43\x82\xaa\x89\xe9\x2e\x07\x35\x01\x18\xb6\xd8\xf8\xe3\x9b\xf2\x87\x09\x4f\xaf\xbd\x1b\xbe\x30\xfa\x37\x9a\x26\xad\xb2\xcf\x5f\xff\x74\x22\x7e\x10\x38\x4d\xae\xbd\x34\xcc\xd4\x25\x9f\x1d\xbd\x3c\x16\x3f\xac\xb2\xe4\xee\xcb\x78\x1e\xc5\x51\x7e\xd3\x2a\xfe\xe2\xf8\xf5\xeb\xb7\xfc\x87\x5d\x16\xdf\xd3\x16\xff\xe1\xe9\xf1\x8b\x5f\x39\xe2\x4e\x59\x3c\xa6\x5e\x4a\xb3\x1c\x62\x1a\x5d\x2c\xfc\xe4\x32\x1d\xc1\xcb\x39\x30\x7f\x32\x8c\xb2\xdc\x8b\x73\x03\x2e\xd7\x6a\x50\xbc\x5f\xe3\xdb\x80\x0a\x93\xeb\x58\x0d\xec\xe8\xaf\x47\x27\x00\x93\xdb\x00\xcb\x45\x51\x7a\x45\x63\xa9\x9c\x12\x3c\xa7\xec\xf4\x2e\xe0\xf5\xf4\x47\xc8\x9c\x09\xee\x5d\x20\x6b\x59\xb5\x5f\xfb\xfd\xf6\xf5\x8f\x27\xcf\x5f\x9e\x7c\xff\xeb\xab\xd7\xcf\x99\xe1\x74\xd4\x9a\x57\xe9\x9e\xdb\x32\x09\x47\x3f\xbf\x79\x7d\x72\x74\x72\xfa\xf2\xe9\xf1\xaf\x4f\x4f\xe1\x00\xce\xaa\x01\x1b\xe4\x11\xfb\x5c\x69\x4d\xa8\xd0\x23\x31\xfe\x0b\xd5\xf1\x69\x4c\xbd\x7c\x21\xc6\xdd\x62\xb5\x57\x8c\x6d\x59\x59\x29\xf2\x96\xcc\xd9\x44\x43\x33\x6a\x42\x3f\xa9\x9c\xc4\x03\xd8\x9b\xd6\x5e\x4b\x28\x1e\xc2\xde\x54\xd7\xeb\xaa\xdf\x7b\x6d\xa3\xd3\x85\x3f\xb7\x29\x5f\x0d\x7b\x8b\xa8\xb0\x7f\xf3\x1a\xad\x25\xe9\xc7\x5e\x85\xfc\xdb\xa7\x27\xdf\x1f\x31\x76\x35\xfd\x28\x35\x9f\x56\x51\x8c\x56\xbf\xde\x5f\xa3\xc1\xa9\xcb\x38\xa4\xe9\x9c\x0d\x68\x79\x82\x76\x08\x92\x20\xb8\x4c\xb3\x1e\xe6\xd8\x96\x03\x30\x18\x53\xf6\x65\x58\x2b\x2a\x90\xc3\x15\x36\xda\xc1\x27\x06\x73\x8f\x74\x72\xaa\x18\xb7\x9a\x3d\x90\x79\x95\x5c\x55\xe8\x17\x1a\xb4\x55\x17\xc0\x36\x5d\x80\x01\x19\x4d\x67\xd3\xc9\xcc\x26\xb6\xe3\x4e\x2c\x9b\x8c\xa7\x74\xd7\x36\xdd\x61\xb3\xee\x8b\x24\x2d\xc8\x0d\x8f\xb9\x8f\x4d\x47\x17\xa3\x86\xe3\xb2\xc3\xbc\x6d\xf1\xd9\x19\x8e\xd6\xcb\xcb\x6c\x40\x86\xb0\xf2\x6e\xd8\xb8\x9e\x2d\x93\xeb\x3a\x52\x05\x44\xee\x79\xeb\x69\x85\x0b\xfd\x3a\xb9\xf8\x69\x41\x99\x2b\x28\xb9\x8f\x18\x12\xcd\xc0\x4b\x29\xb3\x87\xa9\xf0\x75\xeb\x4d\x0b\xa7\xf7\x10\x7d\xde\x9e\xa6\x59\x11\x36\x2b\xc4\xa8\x62\xab\xfd\x67\xe8\xae\x30\xec\xa2\x38\xff\xab\xb7\x8c\x42\x2f\x4f\xd2\x93\x44\x60\x51\x73\xb0\x11\x42\xc3\x73\xcc\xb0\xce\x4b\x0c\x90\xca\x10\x7e\x8a\xf2\x05\x87\x61\x14\x4d\xa9\x5f\xef\xab\xda\xd5\x92\x29\x4f\x70\xf7\x23\x9f\x96\x5f\xa4\xde\x7a\x11\x31\x47\xf8\x66\x2f\xa3\xc1\x65\x8a\x2e\x5b\x98\x94\xce\xd2\x05\x8d\x85\x5f\x64\xb0\x9e\x78\x57\x5e\xb4\xf4\xfc\x65\xa3\x0f\xcf\xde\xfe\xfb\x9b\xd3\xd7\x20\xe2\xae\xdd\x42\xdf\x45\x4c\xa5\x5b\x84\x81\x9c\xa4\xe9\x14\x05\xde\x32\xb8\x5c\xe2\x71\x50\x74\x8a\xb0\xd4\x65\x76\x00\x1e\xfb\x0a\xed\x91\x95\x81\xfa\x78\x99\xe4\x11\xd3\xa4\xc1\x47\x38\x04\x0f\xf6\x21\x1e\x32\xb6\x14\xc0\x98\xd3\x29\x5f\xa8\x81\xb3\x84\x24\x4d\x69\xb6\x4e\xb8\x0b\x56\xf3\xd1\x94\x6d\xa4\x74\xe5\x45\xcc\xaa\xc0\x20\x6d\x01\xcf\x0e\x20\xc5\x96\xf7\x20\x86\x07\xf0\xb1\x09\x41\xef\x5a\x99\x0d\xe0\x51\x06\xeb\x24\x8b\x72\xe6\x65\x47\x73\xc4\x94\x79\xab\x21\x8d\x43\xdc\x49\x84\x29\xaa\xae\xa8\xc1\x63\x78\xd2\x93\x0e\x97\x8c\x34\xda\x58\x78\x7c\xa2\x94\xb1\x09\x51\x16\x5d\xc4\x20\x1e\x14\x2d\xb5\x60\xc9\x1f\x3c\x4b\x22\x33\x0f\x37\x01\xae\x56\xb8\x33\xf0\x43\xcc\x66\x9f\x5e\x06\x3b\x79\x7a\x19\x07\x48\x9d\xc2\xdb\xde\xc1\x11\x29\xca\xba\x80\x33\x1f\xe2\xca\x5b\x32\x5e\xe6\x09\x0c\x3c\xf8\x16\x59\x19\x4b\x71\xb4\x0e\x17\xd1\xbe\x4d\x47\xb3\x24\x85\xc1\x9b\x9b\x7c\x91\xc4\xf0\x6d\xdb\xfb\xad\x3c\xb6\x89\xa2\xcb\xab\xf5\x92\x8a\xe9\xfc\x82\xc2\xcb\xa3\xa3\x23\x98\x8e\x1d\xa9\xe9\x62\xf6\xd9\x82\x7b\xf4\xe3\xb3\xe3\x97\xcf\xd9\xf7\x19\x1c\x5d\x06\xcb\x28\x8c\xbc\xb8\x9a\x91\xc0\x47\x7e\x4e\x29\x1e\xc4\x43\x78\x00\x18\xdc\x1a\x30\x89\xf6\xfc\x6c\x10\x0f\xdb\x78\xd6\x59\xd3\x10\x25\x6f\x79\xed\xdd\x54\x12\xd5\x27\x96\xac\x7e\x9b\x6f\x06\xc7\xa2\xf6\xa4\x8d\x39\x32\xb7\x4d\x88\x66\x13\x8c\x7c\xdc\x84\x97\x32\x83\xca\xcf\xe6\x6a\x92\xbe\x57\xf3\xb6\x56\x87\x9f\x2e\xf3\x45\x72\x79\xc1\x8f\x49\x63\xb4\xa0\xae\xbd\xf5\x49\x27\x03\x6e\xb0\xa2\x37\x38\x5c\xc5\x49\x0e\x17\x4c\xb7\x2e\x33\x3a\xbf\x5c\x42\x4a\xb3\xcb\x65\x9e\x75\x3b\xa7\xaf\x5e\x3f\xff\xf1\xf8\x75\xe1\x9a\x6e\xe1\xe6\xcc\xb6\x9c\xaf\xb6\x23\x84\xfc\xd4\x0b\x15\x78\x15\xbf\xf2\xe4\x4d\x72\x4d\x53\x1d\x51\xf8\x26\x8f\x37\xaf\x7f\xfa\xf5\xcd\xdb\xa3\x67\x2f\xdf\xbd\x7c\x7d\xc2\x98\x6f\x1a\x62\x67\xf2\x75\xb4\x5c\x22\x2d\x62\x0c\x74\xd1\x50\xd1\x70\x1d\x62\x1d\xd6\x21\x8f\xca\x75\xf5\x58\xe7\xeb\xcc\xf9\x2c\xb4\x58\x8f\xe2\x8b\xc8\xc8\x70\xff\x06\xbb\xa6\x08\xa4\x8c\xca\xc9\xeb\x8a\xe6\x8b\xa4\x61\x8d\x5e\xbc\x7e\xfb\xea\xe9\x29\xae\xb1\x35\x91\x11\x53\xe7\x77\x74\xed\xa5\x6c\xcc\x3c\x80\x9d\xd1\x8e\xd1\x2a\x76\x91\x26\x97\x6b\xb9\x90\xa1\x2d\x84\x19\x6b\xed\xf6\xdb\x8c\x06\x49\x1c\x7a\xe9\xcd\xf7\x55\x31\xb3\x5d\x6c\x9e\x7a\x68\x04\xbe\x6f\xb6\xf8\xcb\xe6\xa9\xb9\x63\x94\x94\x8a\x93\x78\xcf\x4f\xa9\xf7\x81\xc9\x30\xe6\xca\xec\x01\xc5\x1b\xac\x15\xfa\xfc\xf0\x1b\x39\xc4\xf9\xbb\x7d\xe4\xd8\x12\xf3\x92\x5e\x9f\xbc\x3b\x7d\xfb\xe3\xb3\xd3\xd7\x6f\xbf\xe9\x0a\xb1\x2a\x83\x80\x68\x33\xf8\x4a\x0e\x33\x01\x6d\x93\xa9\x0e\x28\x32\xe7\xb4\x48\xa3\xcd\xf7\x8e\x57\xd0\xc5\xf2\x9a\x04\x42\x86\x16\x17\x27\xa9\x3f\xf1\x0d\x76\x9f\xca\x8a\x98\xe8\x40\x2c\x59\xa0\x3f\x5e\xc3\xe2\xcc\x3f\xaf\xce\x60\xb3\xee\xf8\x5e\x86\x4d\xc7\x23\x78\xc9\x23\x65\x06\x58\x4c\x11\x26\x4e\x15\x26\x53\x47\x5c\xcb\x58\x67\xe5\x5f\x43\x6c\x80\x0f\xc3\x86\x48\xe3\x82\xb9\x01\xd4\x80\xc8\x60\xb8\x19\xb0\xa4\xb1\x01\x59\x9e\xb6\x25\x6d\x23\x0e\x77\x3d\x6c\x4f\x8b\x63\x3c\x4e\x23\x53\xfd\x32\xf3\x2e\x68\x79\xdb\x53\x4c\x1b\xde\x7b\x34\x87\x01\xdc\x1b\xc0\xa6\x24\x72\x32\x97\x28\x3c\x44\x44\x5b\x18\xec\xef\xc3\x4e\xd5\xa3\x61\xad\x41\xe6\x88\xca\xed\x1d\xc0\xdf\xe3\xcf\x3b\x2d\x10\xac\x61\xee\x53\x0f\x21\xf5\xa2\x8c\x0e\xc0\x9a\x18\xb0\xd3\x05\x6a\xc7\x80\x18\x86\x0f\x5b\xb0\x84\xb0\xd4\xe7\x31\x82\xce\xf5\xd2\x9f\x5b\x24\xdb\xa9\xd7\x1a\x72\x6e\xe3\x62\x52\x5c\x04\x46\x0f\xe0\xef\x7e\xa3\x0b\xda\x9a\x0c\xd5\x64\xce\x83\xa6\x8a\x7a\x48\x6f\x1f\x0e\x0f\x21\xbe\x5c\xe2\xa9\xa2\x7b\xd5\xe4\x61\x00\x3e\xde\xb2\x31\x71\x0c\x88\x42\x03\x76\x18\xc4\x9d\x0e\x26\x3c\xbf\x5c\x2f\x99\xa1\x6d\x0e\xf6\x45\x43\xb1\x8e\xab\x6d\x7b\xca\x3e\x9b\x51\x06\x87\x10\x8f\xb2\x36\x89\xf9\x6b\x8a\xaf\xa9\xee\x75\x00\x87\xd8\x28\x2b\x14\xc0\x10\x9e\x30\x58\x78\xf4\x70\x08\x07\x10\xab\xab\xf1\xa8\xbb\xfa\x1d\x67\x6c\xfb\xdd\xe7\x36\x35\xb0\xbf\x03\xa6\x3a\xd5\xb9\xaf\x18\x37\x2b\x70\x55\x66\x64\xbc\x7f\x1f\x3d\x76\x13\x77\x27\xf5\x50\x81\xb0\x89\x05\x3c\x02\x13\x9e\x88\x3e\xed\xc5\x06\x9b\xed\xb3\xae\x90\x87\x6d\x04\x40\x4c\xb2\xbd\x2c\x87\xb5\x97\x2f\xd0\xcb\x29\x22\xeb\x6d\xfe\x40\xc5\xa3\xc3\xc3\x43\xf8\xc7\x3f\x62\x2d\x42\x50\x1c\xa9\x04\x3c\x73\x61\xe0\xb1\xca\xf8\x21\x44\xf0\x98\x8d\xd6\xec\xcb\xfe\x21\x2e\xa8\xd1\xdd\x5d\x95\x7e\x54\x3d\x63\x00\x34\xec\x83\x92\x85\x67\xf1\xb9\xbe\x48\x17\xbb\xa0\x83\x65\xa0\x66\x1b\xfb\x64\x39\x9b\x4f\xc5\xb0\x8b\x1b\x95\x5b\x95\x8a\x4d\x6b\x4a\x6c\xd0\x7c\x95\x0b\xd0\xa3\x9c\x66\xf9\xa0\x06\x10\xb5\x47\x18\x08\x79\xf9\x7a\x00\x1b\x6e\x5e\x51\x64\x34\x44\xe3\xa2\x90\xe5\xa9\x7c\x92\x0b\xf7\x0b\x1e\x82\x33\x46\xc9\xe0\x6d\xb1\x22\x5c\xd2\xc9\x50\x96\x92\x36\x05\xb6\xea\x9a\x0f\x87\xe0\xf3\xfc\x30\xdd\xc4\x52\x19\x85\xa3\x38\xc3\x18\x00\xef\x33\x8f\x10\x46\x19\xf7\x9b\xf9\xc5\x81\x8d\xc5\x0f\x8f\x2f\xfc\x08\xff\x9a\xd9\x1c\x85\xbc\xee\xef\xc3\xd3\xe5\x32\xb9\x56\x06\x12\x9b\x17\x0b\x72\x53\x48\xcc\x72\x25\x54\x63\x9f\xd0\x10\x92\x0e\x55\x6c\x2d\xab\xe9\x4c\xda\x13\x88\xe1\x00\x89\xa3\x61\xa5\x20\x07\x52\x01\x79\xdf\x20\xc2\x2e\x6a\xc7\x2e\xf3\xf8\xeb\xf1\x69\x05\x3c\x85\x1c\x33\xf2\x5c\x25\x51\x08\xeb\x24\x17\xc4\xc1\x1b\x0b\xd6\x29\x15\x24\x4a\xe6\x55\x70\x8f\x79\x38\x27\xde\x09\xa3\x3c\x52\xca\x71\x76\xc5\x22\x9a\x9a\xf0\xf1\x4d\x31\x91\x88\xe2\x1a\x03\x98\xcb\xcd\x5d\xfe\xb9\x17\x2d\x21\xbc\xa4\x45\xc8\xe3\xec\x88\x9e\x9f\xed\xee\x9d\x6b\x28\xbf\xad\xa5\xbc\xc7\x2c\xe5\xa7\x4f\x0a\x92\xde\x1b\x20\x6b\xde\xd2\x8b\xa3\xcd\x7a\x00\x3b\xef\xf7\x9e\xec\xc0\x2e\x0c\x80\x99\x90\x9d\x33\xf6\xbd\xd8\xf7\x20\x54\x83\x99\x2e\xe6\xf9\xec\xc2\xce\xf9\x2e\x6b\x65\x57\xc9\xa9\x9d\xc1\x93\x83\x5f\x7e\x19\xe1\xd9\x2b\x56\x76\xf8\xe4\xcf\x3b\x86\x0f\x8f\xc0\x9e\xc2\x13\xd8\x89\x76\xe0\x40\xe8\x35\x57\xf7\x2c\x4f\x87\x5a\x09\xea\xd3\x7c\x85\x8f\xa0\xe1\x30\x66\x21\xbc\x5c\xdd\x66\xd4\xe8\xb6\x0d\x7a\x83\x26\x62\x8d\xf7\xef\x63\xdd\x94\xe2\xf2\xe0\x00\xf6\xdf\x9b\xbf\x8c\xcc\x07\x9f\x7e\x19\xed\x1b\x48\x81\x22\x39\xc9\x63\x20\x63\xb5\x8f\x50\x7c\x54\xee\xca\x2d\xf7\xb3\x68\xfc\xb8\x92\xd0\xdc\x87\x8b\x70\x3d\x52\xda\x39\xa3\x71\xd9\x34\x44\x16\xb8\xbe\x49\xe9\x15\x8d\x73\x58\x7a\x39\x9b\x44\x94\x5b\x1d\x45\x7f\x13\x3c\x0b\x71\x45\x71\x26\x21\x76\x46\x29\x41\x71\x19\x17\xbb\xfb\x5b\xcd\x77\x0d\x2c\xbf\x83\xe5\xd7\x98\x72\xd1\x93\xef\x3c\x46\x3e\x14\x4b\x36\x92\xfb\x06\xa2\xd0\xeb\xbe\x3e\x2f\x56\x90\x93\x28\xce\x9f\xb4\x5d\x4d\xee\x33\x30\x24\xf1\x6c\xc4\xeb\xf9\x60\x67\xb4\xc3\xd4\xe5\x31\xc7\xb5\xea\x44\x29\x66\x6c\x1e\x8d\xe2\xa5\x98\x5f\x34\x4c\x8f\xb2\xc1\xa8\xa0\x0a\xf5\xd2\x60\x31\x80\x7d\xba\x1f\x01\x6f\xd2\xd4\x7b\xb2\x34\xa7\xe9\x2a\x8a\xab\xb5\x2d\x8d\xe1\xa2\xa8\x5d\x43\xec\x56\xd4\x26\x33\x85\xdd\x43\xd8\xad\x98\x02\x11\xb3\xe9\x2a\x09\x94\xd8\x77\xe9\xf3\x19\xe2\x80\x3b\x57\x4d\xa2\x43\xb9\x45\xb5\x6c\x5d\xdd\x09\x31\x3b\x6c\x63\x5e\xf0\xa0\xd8\x31\x5d\x03\xaf\xe0\x69\x41\x8b\x25\xf5\x30\xd4\xf5\x37\x9a\x26\x8d\xa1\x81\x3b\x84\x22\xc1\x46\x43\x4e\x23\x21\xa7\xfc\x1e\x47\x15\x23\xab\x26\xf2\xd4\x8b\x96\x9d\x6d\x2c\x69\x5c\x47\xbf\xd9\xdc\xde\xde\x92\xc6\x55\x93\x0d\xf2\x35\xd5\x84\x4d\x70\x19\x48\xc1\x96\x96\x04\xa1\x39\x6f\x2b\x65\x0b\x0b\xb5\x18\x45\x19\x5e\x79\x2c\xac\x42\xe1\xd8\x5c\xd1\x54\x6d\xd4\x58\x8b\x92\x1d\x54\x8e\xbe\xbf\x93\xe1\xe4\xce\xff\xe5\x8a\x99\xf9\xca\xe0\xb3\x6e\x0a\x73\xae\xb7\xa8\xcc\x32\x3c\xe0\x76\x55\x29\x6a\x14\xef\xb2\xde\x53\x0f\x32\xfb\xfb\xf0\x5a\x2c\x38\x3e\xd1\xa9\xd8\xe3\x72\x55\x4f\x3b\xaa\xa0\xb8\x2b\x57\xfb\xc5\x87\xcf\x25\xc4\x9c\xf1\x72\xb9\x54\x33\xec\xc7\x62\xed\xb6\x8d\x4b\x53\xef\x8a\x55\xd9\x2e\x94\xfe\x77\x7b\x17\x4a\x0d\x9d\x33\x81\x90\x09\x8a\x29\x4e\xcf\x80\xd0\x31\x77\x12\xc0\xcf\xf5\xd3\xc2\xd3\xd4\x8b\x33\xf4\xd6\x98\xc3\xa7\x2d\x46\x8b\xa4\x09\x85\x03\xad\xb7\x86\xa2\x46\xc4\x6a\x5c\x63\xe8\x37\x4f\x00\x55\x0c\x55\x2e\x4f\xe0\x82\xe6\x7c\xdf\x3f\x9e\x63\xa3\x7c\x11\xa3\x08\x33\x07\x09\x9d\xcf\xa3\x00\x57\xd2\x44\xc2\x25\x55\x0b\x11\x4e\xe9\x29\xd7\x56\xf8\xb6\xdc\x5e\xaa\x99\xcb\xcb\x36\x32\x62\xa6\xb8\x2a\xaf\xaf\x10\xf1\xb3\xa8\x9d\xf3\x5f\x56\x30\x1a\x32\x42\xf3\x03\x20\x35\x1b\xcf\xad\xb6\x52\x1d\x8a\x4f\x65\xca\xf6\x24\xa4\x8a\xa6\x1f\x76\xb6\x0d\x9c\xc3\x8a\x86\x23\xa3\xde\x4b\x8e\x84\x0e\x86\xc6\xdf\x01\x85\x91\x8c\x3a\xc0\x30\x96\x94\x0d\xee\x69\xc7\x95\xb2\xd5\x2e\xa9\xe6\xf0\xf6\x0e\x91\x08\xb7\x71\xd2\x38\x3d\x1f\x42\xb4\xb7\x87\xe3\x01\xa3\xc2\x8e\xb9\xa3\x9f\x48\xcb\xe4\x53\x7b\xdc\x4a\xa4\x55\x36\x43\xad\xe4\x3d\x0a\xde\xe8\x47\x33\x8c\xf1\x59\x1b\xe9\x86\x37\x6f\x5f\xbf\x39\x7a\x7b\xfa\xf2\xe8\x9d\x54\xa6\x5a\xca\x10\xbb\x58\xe1\xb0\xd8\xcf\xfa\x50\x55\x0a\xe7\x94\xbf\xfe\xf8\xa6\xde\x6a\xf3\x3d\x2e\xe3\x1e\xca\xee\x63\xb3\x04\xee\xfb\x3a\x04\x4b\x5f\x82\xaf\x90\x1e\x82\xad\x2f\x52\x6c\x9c\x3b\x04\xa7\xa7\x90\x40\x68\xdc\x53\x0c\x97\x4e\x0f\x61\xd2\x53\x4c\x20\x3f\xed\x29\x56\xf4\xc0\x55\x95\x13\x4b\xaa\x87\x30\x7b\xa8\x5d\x83\x78\x86\x1b\x4b\x2f\x53\x0a\x51\x3c\x4f\xf1\x9c\x62\xbe\xbc\xd9\xc3\x3d\xa9\xcc\xd5\x11\x87\x33\xf6\xae\xa3\x90\x42\x46\xf3\x3c\x8a\x2f\x32\xdd\x32\xc2\xd3\x20\xa0\x6b\x8c\x06\x8b\x23\x3f\xb8\x94\x51\x46\x36\x60\x19\x65\xb9\x21\xfc\x8c\x18\x77\x45\xac\xbc\xf8\xa6\x30\xb3\xe5\x99\x2b\x10\x99\x71\x23\x9a\x41\x92\xca\x0d\x60\xd6\x57\xe6\x8f\x65\x90\xd2\x6c\x4d\x83\x3c\xba\xa2\xcb\x9b\x03\x0d\x3e\xad\xbd\xab\xd5\x62\x45\xb5\x3c\x51\xac\xd3\x55\xeb\x13\x75\x10\xf5\x10\x87\x1e\x84\xab\x03\xd0\xd8\x80\x57\x2e\xb5\xf0\x7f\xce\xce\x65\x48\x7b\x0c\x91\x26\x3e\x0d\x22\x6c\xf5\x39\x13\xe1\xd4\x12\xa2\x89\xf0\x46\x8d\xfe\x8e\xce\x1b\x9d\xc5\x4d\x67\xd5\x47\x81\xeb\x49\x12\xef\xe1\xce\xb1\xe8\xf7\x47\x7a\x8f\x14\x58\x17\x6f\x48\x17\xf6\xc2\x37\xac\xb0\x17\x47\x5c\x3e\x95\x2c\x13\xdb\x9f\xc4\xbe\x1d\xc2\x44\xd0\xac\xc3\x10\x7b\x7b\xbe\x08\x86\xbc\x30\x0e\x35\x91\x29\x3f\x7c\x3d\x5c\x27\x32\xf5\x75\x66\x3d\x80\x0e\xb1\x15\xeb\xc1\x55\x3f\xb8\x4a\xca\x20\xde\xd1\xee\x75\xe6\x16\xff\x9a\x0b\xc9\x05\x68\x3e\x25\xfc\xdc\x2a\x5f\x5f\x51\xae\x50\xe9\x2e\x1f\xfd\x8d\xd6\xc5\xa2\xe8\x7d\xab\x7c\x7b\xb9\xb9\xbb\xbc\x7a\xdd\x59\x8f\x4f\x6b\x71\x59\x8b\x8f\x5c\x75\x20\xed\xf3\xf7\x32\x36\xc9\xe1\xa1\xe4\x6a\x2f\xbb\xe0\x8d\x30\x92\x92\xb5\xf3\x52\xbe\x9e\x86\x61\x1c\xb1\xfb\x03\xcf\x39\xb3\xa9\xc3\x50\xd3\xde\xd1\xe8\xa2\xb6\x28\xdb\x3c\x35\x30\xb0\x4c\x03\x1c\xdc\x9b\x55\xdb\x46\xd4\x59\xe7\xef\x4d\xd3\x79\x80\xdb\xfe\xeb\xc6\xf0\x00\x1c\xf8\xac\x43\xeb\xe5\x45\xcc\x26\x7b\x55\xef\xf6\x25\xeb\x9d\x51\xdc\xc8\x84\x0b\x7b\x49\x5a\xa5\x2b\xae\x75\xe4\xad\x58\xd8\x2e\x87\x93\xea\x16\x80\x8a\x64\xc1\x65\x9a\x96\x9b\x45\x33\xf5\xd2\x72\xb3\x77\x70\xd8\xc8\x3d\x2a\x4b\x1b\x26\x1e\x33\x60\xdd\x5e\x4c\x8e\xda\x67\x5e\xd8\x27\xc5\x93\xad\xed\xe7\x1e\xe6\x1f\x13\xc7\x9b\xda\xaf\x13\xf6\xfa\xcc\x3c\x6f\xbf\x61\x13\xe5\x43\x48\xd8\x1c\x57\xc4\x9c\x13\xf9\x28\xb1\xc2\x6b\x7c\x52\xef\x0f\x9f\x2b\x24\x8d\xc3\xb4\x83\xb5\xb4\xbe\x33\x80\x2b\xd6\xc6\xd9\xfa\x1c\x86\x70\x4f\x4c\x3b\x1b\x9e\x25\xff\x1c\xa8\x60\x7b\x55\x3c\x35\x6a\x02\xf5\xce\xa2\xdd\xdd\x3a\x58\x45\x54\xa5\x2e\x5d\xa5\x81\xeb\x18\x96\x5b\x9b\x7b\x76\x84\xac\x0e\x9b\xd0\x5a\x4b\xd2\x57\x8a\x25\x69\x5d\xe5\xc6\xaa\x74\xb3\x2a\x76\x7f\xe1\x65\x03\x58\xc3\x21\xec\xd4\x2b\x8b\xf5\x00\x79\x99\xfa\xca\x60\x73\xae\x57\x4f\x7f\xc6\xe5\xea\x35\xa8\xe3\xef\xad\x33\x36\x57\xed\x25\xad\x3a\x73\x52\xc6\xba\xc3\x46\xc5\x36\x9d\xeb\x0a\xab\x21\xb3\xbb\x15\x91\xeb\xa0\x6e\x47\xe3\x7a\xdd\xdb\x91\xb8\x56\x57\x4b\x61\xb7\x93\xbe\xcd\x73\x14\xdb\x92\xb7\x56\x4f\x11\xe4\xad\xbb\x76\x2d\x6f\xa9\x59\xbe\xd7\xcf\xd3\xf9\x6d\xf8\x5e\xa5\x14\xe7\x1d\x0c\x6b\x60\x77\x3b\x8e\x35\x2a\xdf\x8e\x65\xf5\xca\xda\x6d\x19\x3c\xa4\x91\x61\x8a\x8c\xc1\x95\x7e\x65\x4a\x94\x93\x58\xce\xec\x26\x92\x08\x79\x2f\x18\xdf\x94\x8b\x33\x72\xbe\x95\xf2\x15\x9f\xda\xa1\x13\xd6\x84\x7a\x59\xb9\x51\x9c\x9f\xf2\x60\x8d\xe9\x8b\xb7\xed\xaa\x1c\xb1\x6b\x08\x33\xef\xd6\x36\x48\xd7\x4f\xc9\x0c\xea\x18\x31\x63\xcc\x57\xd7\xf6\xae\xe0\x00\xae\x00\x13\xb3\x6d\x11\x4f\x50\xe9\xc1\x99\xe6\x94\x2f\x34\xe3\x78\xe5\xc1\x95\xf6\xcc\xe1\x2e\x13\x07\x0e\x51\x37\x2f\x10\x5a\xa1\x9c\x1b\xf4\x6a\x07\x47\xf3\x96\x66\x0c\xeb\x04\x5e\xcc\xaa\xf9\x14\x17\x02\xb6\xab\x73\x4b\x93\xc7\xea\xfc\xbe\x6a\xb3\x47\xba\xf5\x86\x6c\xaf\x37\xd5\x19\xa0\x7e\xa5\xa9\x8e\xc0\xfc\xa7\x68\x0c\xd6\xbe\xe2\x8a\x20\x9f\x5d\x1a\x48\x88\x6d\xaf\x38\xec\x53\x22\xd5\xdc\xa1\xc7\x10\xd9\x85\x9d\x86\xb4\xec\x18\x0c\xe0\x1d\x75\xb0\x79\x12\x4c\xa5\x7d\x62\x0e\xdc\x9a\xb6\x2a\x26\xad\x5d\x43\x07\x87\xd2\x99\x28\x62\x8b\x61\x00\xa1\x74\xcb\xf1\x15\x2e\x86\xdd\xbb\x77\x05\x9f\x3e\x89\x1f\xa4\xfa\xaa\xdf\xef\xd2\xb5\xb9\xaa\x76\xc6\x68\x50\x9d\x7d\x62\xad\x0c\xe1\x89\xe6\x5c\x11\x1c\x28\x4f\x34\x69\x17\x3f\x64\xa6\x6b\x76\x54\xd4\x44\x41\x64\xe0\xb8\xbb\x00\xf0\xc6\xda\x2c\x17\x21\x8b\x2f\x64\xb9\x80\x72\x5b\x96\xd7\x60\xf0\x53\x56\x70\x19\x97\x07\xa7\x0e\xe0\xef\xfc\x61\xb7\xa4\xf0\xc6\x7f\x1f\x49\x29\x4f\x6b\xdd\xbb\xc7\x80\xdc\xbf\x5f\xa0\x59\xcd\xaf\xc4\x03\x39\x5f\x93\x46\xdd\x05\x26\xf7\xef\xc3\x3d\x01\xb7\x5a\x93\x94\x75\x7f\xa7\x4d\x8a\x9d\x22\x39\x8c\x92\xfd\xff\x49\x32\xc5\x3b\xd1\x96\x29\x39\x84\xa5\x99\x35\xcc\xb6\x9a\x35\xc8\x80\x6e\x37\xd8\xca\x35\x6f\x37\x7c\x4a\x35\xb5\xf3\x85\x59\xe7\x58\x51\x3f\xda\xb2\xed\x6c\x41\xaa\xd5\xa6\x68\x3d\xa6\xf7\x85\x13\xde\x3a\xb0\xdb\xd1\xb5\x5e\xf7\x76\x94\xad\xd5\xbd\xf3\x6c\xb7\x79\x8c\x66\x5b\xfa\xd6\xea\xb5\x29\x2c\xc2\x6a\x45\xa4\x53\x4f\x01\x51\x50\x90\x8d\x17\xef\xef\x3b\xaf\xd5\x6d\xa3\x84\x3d\xb9\xaa\x9b\x12\x8d\x2a\x97\x47\x76\xae\xbe\x9a\x3d\xd8\xa9\x77\xea\x0b\xbc\x0d\x8e\x5c\x83\xc8\xc5\xce\x50\x69\x31\x50\xbf\xb4\xf4\x56\x3e\x97\x52\x6d\x3f\xbd\x5e\x24\x19\xad\xf6\xda\xe6\xd2\x09\x30\xb1\x10\x54\x06\xcd\x74\xeb\x4c\x55\xd2\x20\xed\xb1\x95\x9e\x38\xe0\xca\xdb\x34\x83\x80\x45\xe7\x56\xde\xe6\x75\xfa\x2a\x8a\x07\x52\xf0\x0e\xde\x8c\x96\x39\x0c\x1f\x7e\xa5\xee\x8a\xa3\xfa\xff\xc4\xee\x46\xf1\x2d\xbb\x7b\x71\xd7\xee\x46\xf9\x02\xbc\xe2\x54\x35\xef\x36\xfd\x78\xe9\x2d\x99\x75\x4b\x52\xb8\xc0\x73\x4b\x29\xdf\x03\x64\xe2\xee\xde\x25\xcd\x32\xb1\x27\xc8\xa8\x75\x3b\x16\x3b\xa4\xc3\xb5\xc1\xaa\x36\x62\x64\xd1\x1c\xc2\x35\x23\x69\xb2\x8a\xf2\x9c\x86\x46\x33\xcd\xcd\x00\x77\x41\x66\xb8\x71\xa9\xd8\xba\x25\xc3\xc7\x5d\x5c\x18\x72\x5f\xa7\x49\x78\x19\xd0\x70\xa8\xe3\xc0\x59\xb8\x96\x0e\x3a\x3d\xaf\xb5\x33\xda\xd2\x84\xd7\x00\xee\x70\x02\x0d\x86\x4d\xa4\x5b\xa6\x3c\x5c\xcb\x56\xa9\xa3\x66\xc3\x90\xeb\xeb\x6d\xe9\xa4\x29\x05\x49\xf0\xf5\x10\x06\xdd\x01\xf4\x75\x72\x6d\xfd\x3a\xb6\x31\xfb\x99\x65\xca\x1f\x45\xbc\xa0\x90\xa4\xb1\x0d\x7e\x94\x97\xd3\xf9\xd8\x10\x9b\x75\x4c\x78\x74\x88\x5b\x85\x67\xa6\x39\x25\xb3\x99\x35\x76\xa6\x8e\x39\x9b\x59\xad\x01\xf2\x19\x6e\x7f\x8d\xe6\x3c\x03\x5e\xd9\x63\xc1\x5f\x79\xfb\x99\x6d\xf1\x4b\x9b\x39\xc5\xc2\x64\x15\xd3\xac\x9d\x42\xe2\xe5\x1c\xa2\x1c\xc2\x04\x13\x0e\x65\xd9\xe5\x0a\x13\x88\x2c\xa9\x97\xe5\x02\xdb\xba\x00\x19\xfc\x60\xc0\x75\x94\xd1\x56\x79\xdb\xc4\xf2\xad\x36\xcc\x8d\x23\x48\xc3\x84\xd9\x7a\x6f\x9b\x06\xa6\x84\xae\x9e\x58\x78\x81\x25\xcf\x40\x27\x9e\x60\xbe\xb8\x51\x8b\xec\xbc\x2b\x63\xdb\x8f\x72\x31\xf9\xa9\x13\xe2\x41\xc1\x18\x71\x1b\x03\x82\x6c\x8c\x0e\xcd\xb5\x84\xd2\x4e\x88\xfc\x82\x03\xd0\xc0\x44\x83\xd1\x00\xd6\x5c\x3c\x28\x16\x0a\x5a\x78\x49\x54\xf8\x04\x26\x7f\xe2\x8a\x2b\x13\x54\x7b\xdf\x15\x00\xdc\xaa\x7a\x7b\xc9\xa1\xc8\x5e\x5e\x62\x13\xae\x55\x23\x2a\x5e\xba\x8c\x5b\x8a\xa9\x01\x1f\x0c\xb8\x6a\xaf\xce\x80\x7e\x25\x88\x7d\xf8\xee\x36\xf5\x3b\x86\x6e\xeb\x98\xc6\xeb\x93\x23\xd5\x6e\xac\x10\x73\xfd\xae\xb5\xc7\xdf\x98\x51\x2c\x5c\x2d\xe2\xe0\xb4\xb6\xb5\x62\x17\xae\xd5\x01\x96\x0f\x70\x58\x66\x93\x64\x90\x60\x5f\xda\x96\xa5\xc0\x85\x79\x21\x7c\xa2\xd0\xb5\xa1\x50\xdc\x3f\x96\x41\x76\xb9\x5e\x27\x29\xa6\xaa\xe0\x66\x65\x74\x41\xf3\xb7\xc8\xaa\xbf\x6a\x4e\x6e\x14\xad\x48\x53\x33\x75\xd5\xee\xbd\xfb\x1e\x1c\x6a\xea\xf1\x13\x18\x3f\x46\x71\x6e\x5b\x3c\x70\x06\x1f\xe0\xc1\x21\x58\x5b\x6d\x86\xe3\xbb\xdf\x3e\x3c\xec\x6e\x5d\xd0\x41\x18\x86\x83\xbe\x72\x42\x09\xd6\xc9\xf5\xc0\x32\xc0\xb6\x86\x4c\xa7\x99\x28\xcb\x8f\x2d\x32\x1c\x56\xb7\xe9\x58\xc3\x3e\xa0\x84\x7d\xf8\x5f\xed\x17\xae\x27\x85\x41\x2e\xbf\xdc\x11\x5f\xbc\xfe\x88\xdc\x0a\xc9\x6d\x3e\x1a\xfc\xfb\x40\x8b\xe1\xa6\x30\x93\x6a\x49\x2b\x3e\x62\xb5\xf2\x1c\xcd\x07\xaf\xb7\x0b\x03\xef\x0c\x37\xc2\x9f\x17\x3d\xeb\x90\x0e\x28\x46\x30\xe6\x6c\x33\xb3\x92\x79\xab\xf5\x12\xd3\x46\xf7\xe1\xc9\xc6\xb4\x2b\xc5\x98\xd6\x57\xf1\x4d\x9a\xf8\x9e\x1f\x2d\xa3\xfc\x86\x8d\x64\x39\x5c\xc1\xe3\x43\x98\x51\x32\x36\x5a\x39\x44\xda\xb5\x6b\x4d\xc1\x7e\xab\x75\xf8\xc7\x21\x98\x23\xd3\x34\x5d\x03\xa2\x11\x1d\x01\x81\x28\x06\x62\x8d\xbb\x09\x2f\xa2\x22\x02\x91\xde\x1d\xa2\x20\xce\xed\x6d\xab\xaa\x56\xe7\x5e\xd1\xe2\xe3\xf1\xdb\x30\xfd\x33\xb3\xe3\x4c\xa6\x54\x98\x33\x99\x55\x20\x3d\x15\xf4\x5b\x2c\x9b\x1f\x89\xb3\x87\xe0\xce\xea\x9f\xad\x6b\x0f\xae\xe0\x5b\xcc\x55\x3b\x64\xbf\x6e\x09\xa4\xd8\x3d\x5a\xc0\xd8\x86\x74\xb8\x33\xd7\xea\x21\x82\xf6\xad\xfe\x0d\x1b\x27\x3f\xc0\x3e\x03\xad\x1b\x35\x8a\x44\xe4\xed\x41\x83\x0f\xee\x78\x57\xae\x5a\x8d\xe5\x15\x81\xd6\xb8\x21\xd5\xee\x3d\xef\xe5\x5f\xce\xe7\xcd\x94\x2c\xd2\x47\x1a\x55\x24\xa8\x62\x00\x99\x7e\xed\xe1\x43\x5c\x3f\x67\xd6\x9c\x42\xc7\x35\xea\x2f\xc4\xe3\x5e\xa3\x2d\x55\x12\xee\xa5\x25\x41\x12\x66\xd2\xf9\x1a\xa3\xca\x5d\x0d\xf6\x9d\x0c\xe1\x15\x06\xf6\x07\x5c\xe7\xef\x83\x4d\x80\xfb\x80\x75\xd2\xe1\xf5\x8e\x95\xaa\x37\x0a\x68\x4f\x55\xd6\x3f\x05\x00\xab\x01\xa0\x06\xdd\xae\xbd\xbc\x25\x64\xe7\x1c\x6f\x39\x99\xd4\x20\x8e\xf1\xa1\x8b\xcf\xf8\x93\x89\xee\xcc\x44\xf1\xb9\x83\x15\x56\x88\xf5\x74\x38\x0a\x92\xf5\xcd\x80\xf9\xc1\xad\x03\x5e\xcd\xcf\xed\x2d\xe3\x7f\x8e\x6d\x9b\xfe\x7e\xb6\x4d\x03\x7a\xeb\x00\x1e\x54\x41\x3c\xe2\xdc\x7e\xe1\x40\x8d\xa4\xfa\xd8\xf5\x8f\x19\x95\x27\x6f\x07\xc5\xd2\x48\x91\xa9\x0f\x92\xb4\x68\x29\xca\x64\x0c\x30\x16\xd3\x99\xd6\x0f\x84\xfc\xdd\x8b\xb4\x36\x4e\x61\x0b\x75\xf4\x60\xea\x5d\x9f\xcb\x0e\xba\x4e\x79\xcc\xc5\x9a\xad\x10\xfb\x80\x6f\x40\x3b\x2c\xc5\xe4\x0b\xa8\xc6\xa6\x4a\xc1\xd9\xde\x5e\xa4\x70\x11\xc2\x35\x7c\xdb\x79\x6c\xa7\xba\x1b\xbf\x3a\x3b\x28\x0e\xd3\x89\xf4\x9b\x59\x3d\x01\x5f\xd8\x4c\xb7\x5b\xf4\xee\x03\x1b\xd9\xc2\xb5\x96\x68\x57\x3c\x3a\x8e\x59\xe3\xcf\xa4\x13\x2f\xe1\x5a\xe3\xda\x04\xdc\x59\x92\x66\xf5\x4c\x96\xaf\xd0\x8c\xaa\xc2\xd1\xca\xce\xbd\xa5\xab\xe4\x4a\x3a\x17\x49\x8b\xe4\x6f\x22\x1d\x7b\x4a\x55\xb9\x8e\x25\x51\xe0\x58\x1c\xe2\xc1\xcc\x60\xb4\x4e\xd6\x83\xa1\x01\xd1\xde\x9e\x72\x4c\x15\xc7\x59\x34\x27\xf1\xa2\xf2\xb8\xa9\xb2\xbb\xb8\x7e\xde\x7f\x9c\x4d\xe7\xa5\x88\x9e\x16\x87\x4c\x35\x1d\xe5\xa9\x65\xc3\xdf\x2e\xb3\xbc\xca\x62\x5a\x32\x78\xa9\x39\x37\x56\xe5\x2b\xd9\x23\x48\x13\x53\xa2\x09\x5e\x2e\xca\xa8\x42\xe5\xd3\x58\x3a\x97\x03\x05\xee\x32\xce\x45\x32\x3f\x39\x73\x5a\xeb\x64\x5b\x80\x02\xa7\x3e\x3f\x8b\xe9\xb0\x47\xa3\x2e\x7c\x23\x9e\xf2\xed\x0a\xf5\xc3\x3c\x7f\xc8\x07\x1e\x62\xb2\x2f\x22\xc5\x4a\x84\x37\x38\xeb\x10\x15\x74\xca\xe5\x1c\xbd\xbd\xb4\x2a\x59\x2d\x1d\x23\xab\x51\x06\xf6\x54\x47\x9d\x15\xe2\xcb\xcc\x8b\xee\x9c\x22\xbe\x63\x22\x13\x68\x13\x28\xb1\x22\x8d\x15\x2b\x69\x51\x64\x38\x18\x3e\xac\x9f\x92\x7a\xf3\xf6\xe5\x5f\x9f\x9e\x1e\xc1\x8b\x1f\x4f\x9e\x9d\xbe\x7c\x7d\xf2\xae\x71\x88\x4a\x98\x09\xaf\x4c\xb6\xc5\x43\xfc\x8c\x51\xbe\x97\xd1\x97\x98\x37\x44\xf7\xf6\xf5\xa5\x74\xe8\xb1\xba\xe1\xb6\x75\x5a\x5e\x94\x35\x04\x48\x83\xe7\x7e\x54\xc5\x6f\xc3\x22\x00\x96\x1a\xb0\x31\x60\x13\x18\x70\xa3\xde\x10\x2d\x9f\x97\x87\x9d\xd1\x0e\x0c\xdb\xe5\x30\x96\xd5\xb8\x36\xa2\x4d\xd8\x55\xcf\x7e\x4b\x9e\x06\x85\x13\x03\x33\x5c\xc8\x47\xf2\xf3\xe4\x38\xb9\x2e\xee\x18\x6e\xc7\x98\x4f\x92\x78\x2f\x52\x1d\x39\x17\x02\xf5\x58\xb7\x81\xe0\x43\xcf\xb2\x23\x14\x67\x73\x8b\x14\x82\xe5\xbd\x35\x6d\x01\x6e\x2e\x7b\x6a\x53\xd6\xe8\x72\x0c\x34\x4b\xdf\xb4\x82\x89\x9c\x3c\x8a\xa2\x1b\x38\x84\x1b\x8c\xdd\x48\xa7\x20\xf1\xec\xb3\xa2\x70\x13\xd1\x0f\xdd\x63\x1b\x43\xda\xc3\x65\x96\x6a\xe5\x02\x73\x2c\xc6\x90\xd2\x2c\xe7\x31\x77\x5a\x9e\xa6\x80\xb5\x97\xe6\xe0\xdf\xf0\xb4\xaa\x22\xa1\xad\x0a\xbe\x48\xf6\xe8\xdf\xe0\x35\x15\x78\xcc\x17\x1d\xa5\x90\xeb\xc2\x9a\x31\xbc\x4d\xe5\x1b\xd4\xdc\x3c\xf9\x8e\x0b\xfb\xa0\x48\xfe\xcf\xef\x5e\xe5\x87\x79\x4f\x8b\x58\x15\x1e\x85\x1c\x1a\x78\x12\x72\x28\xd2\x49\xf0\x7a\x4a\x7a\xa3\xc1\xb8\x19\x05\x5b\x66\x27\x28\x07\xff\x05\x2d\x4e\xc2\x33\x3a\xa9\xe4\x70\xd3\x40\xba\xd4\x57\xa6\xa6\x1a\x94\x28\x7a\xa0\x87\xb0\x09\xd4\x07\xfd\x15\x23\xb4\x36\x73\xc1\x43\xd8\x30\x37\xe7\xc3\x39\xf0\x91\x67\x23\x86\xe3\x66\x9b\x3c\x8b\xd4\x06\x07\xa9\x72\xdf\xff\x8e\xd9\xcc\xaf\xd4\x33\x24\xef\xed\x51\x65\xe2\x88\x76\x49\x71\x34\x5e\x61\x88\xcb\x53\xe6\x2a\xd1\x41\xc3\x86\x59\x80\x69\x28\xce\xd1\x60\x62\xe3\x20\x2f\x93\xa2\xaa\x8e\xc5\x66\x22\xc9\xac\x5a\x7f\xc2\xe8\x0a\x13\xe2\xdc\x18\x18\x7d\x4f\x57\x9d\xc2\xb2\xe1\x67\xfa\x55\x43\x08\xbe\x48\x55\x19\x39\x30\x0b\x40\xa7\x58\x85\x98\xb4\x60\x97\xd9\xd4\xdd\x56\xd6\x02\x91\x5d\xb4\xcc\xfb\x8a\x2e\x80\x88\xe4\x95\x2e\x41\x71\x16\x89\xdf\x89\x95\xcc\xe5\x37\x0b\x2f\x2f\xd2\x97\x17\x49\xb0\x9a\x57\x40\x44\xc8\x8f\xb3\xb0\xe1\x46\x31\x41\x2c\xa8\xb1\xdf\x8c\x25\xb1\x1e\xa7\xf0\xe9\x13\x84\x28\x12\x9f\x3e\x21\x04\x3e\x2b\xbf\xa7\xcc\x79\x80\x35\x56\xf0\x08\x1c\x4c\x20\x13\x15\xc5\x58\xdd\x94\xef\x3b\x19\xe0\x90\xc1\x93\x2e\x89\xaf\x03\xe4\x21\xdf\xbc\x69\xc3\x01\x8f\xee\xeb\xe6\x0d\x07\xcc\xee\xc3\x07\x56\x3b\x62\x95\x99\x8f\x5d\xc0\x74\x78\x3b\x25\xe0\x09\x6b\x10\x71\xde\x63\x38\xdf\xc7\x9d\x67\xfa\x29\x65\x1b\x1b\x17\x0e\x60\xaa\x58\x6b\x40\x45\x61\x54\xc1\xad\x6c\xa5\x62\xa9\x4f\x73\x93\xf7\x7b\xe1\x5a\xb1\x8f\x0f\xca\x91\x23\x85\x27\x0d\x7b\xb7\x43\x76\x0c\xd8\xc3\xa9\xc3\x01\x57\x54\xb9\x96\x5e\xef\x0a\x9b\xc2\xe4\x5e\xb3\x24\x94\x76\xad\x06\xbd\x2d\x64\xf0\x72\x8d\x12\xb5\xa2\x5e\x2c\xce\x6e\xd1\xab\x28\xb9\xcc\x84\xc8\x61\x2e\xea\xa4\x2e\x70\xe8\x47\x67\x09\xa8\x06\x51\x28\x4d\xd6\xde\x9e\x90\xb7\x87\xb0\xbb\x8b\xd6\x2b\x3c\x87\xc7\x50\x3e\xec\x9a\x60\xa2\x00\xf3\x21\xb8\x7b\x5a\x79\x2f\xec\x8d\xa3\xec\xee\x76\xa4\x09\xe4\x8d\x8d\x2e\x63\xee\xc8\x93\xce\x9c\x07\xdb\x3d\x55\xcf\xc5\xb6\x4b\x53\x03\x25\xf5\xea\x03\x07\x4a\x1e\x33\xff\x0f\x75\x53\xaf\xa3\xd1\xc5\x08\xce\x1c\x03\xf0\x66\xb1\xf1\x39\xf8\x34\x48\x56\x34\x03\xc7\x9f\xeb\xda\xe0\xcb\xa4\x42\x34\x77\x76\x70\xea\xcf\xbc\x89\x22\x0b\x42\x99\xf4\x2c\x58\x78\xe9\xd3\x7c\xc0\xd8\x22\xce\x8e\x69\xb3\x10\xd5\xa5\x1b\x87\x49\xda\x9f\xfb\xe9\xb4\xba\xff\x0a\x53\xc0\x79\x61\xc8\x33\xa0\x47\x17\x0d\x19\x2b\x6e\xac\xcf\x53\x6d\xc6\x83\x37\x34\xc5\xf4\x24\x65\x8a\x6f\x71\x0f\x94\xc8\xe6\x4c\x43\x94\xc1\x11\x3c\x63\x0d\x86\xc2\xd3\x41\x99\x96\x5c\xf2\xaa\x55\xf6\xb2\xb5\xa1\xa2\xd9\x81\xa7\x7c\x37\x41\x5c\x9c\xa1\xd8\x20\xbc\x0f\x8d\xa1\xbc\x00\xb1\xba\x5c\xe6\xd1\x7a\x79\x83\xc3\xd5\x07\x3e\x4c\x29\xe5\x98\xf9\xfa\x2b\x03\x72\xba\x5a\x1b\xb0\x59\x26\x06\x6c\x16\x91\x66\x61\xdb\x4b\xd3\x1b\xfd\xba\x37\x0e\x0b\x42\x9c\xd4\x25\x3e\x2c\x13\x74\x58\xbe\xad\xee\xa0\xd3\x14\x5c\x14\xb1\xb5\xea\xb2\xba\x4f\x4a\x55\xe5\x62\xb6\xc1\xa6\x45\xf6\x54\x91\x67\x43\x9b\x7b\x0e\x91\xd8\x9c\x45\xe7\x32\x1e\x9a\x4c\x1c\x88\x07\x96\x6d\xa1\xa2\x2a\xcf\x26\x30\x0c\xf7\x07\xd8\xca\x2e\xd6\x7f\xc0\xba\xad\x2e\xce\x88\xce\x6a\x2c\x93\xb2\xc6\x00\x06\xb0\x92\x11\xc3\x78\x8c\xfc\x6b\x97\xf3\x41\x13\xd4\x11\x2c\x1a\x70\xd8\xfb\x9c\xef\xfc\xb0\xc3\x2e\x82\x6e\xf4\x03\x9f\x0b\x94\x17\x8a\x79\x33\x52\x81\x47\x8a\x10\xe2\xb7\x08\x71\xeb\x1c\x80\x88\xcf\x10\x36\xa5\xf9\xe3\x0f\x14\x8c\x14\x5a\xb7\xe9\xd4\x63\x69\x66\xbb\x5a\x7b\x29\x1d\x88\xad\x1a\xde\xb1\x01\xfe\xb1\x56\xbe\x23\x03\x82\xd5\x5a\x33\x86\x81\x77\xcc\x5c\x0b\x4d\x75\x24\x2a\x72\xc9\x3b\x66\x43\xcb\x31\x3c\x01\x02\x07\xb0\xa7\xca\x5a\xd7\x19\x43\xaa\x0c\x22\x87\x67\xf2\x38\xa8\x77\x2c\xf2\x8e\x75\x85\xd0\x39\x9e\x8c\x0d\x0c\x53\xf6\x6f\xdf\x90\x24\x70\x66\x45\x1f\xf3\x1a\x7a\xbc\xe5\x0f\x26\x5b\xff\x1a\x23\x54\xf3\x49\x71\xb3\x37\xe3\x43\xbd\xa4\x9a\xc3\xd9\xa5\x9f\xb3\xe9\x62\x8d\xc5\x5d\x46\x2c\xd2\x0c\xe6\xfb\xfb\xf0\x4e\xc0\x02\x9f\x5f\xd4\xe6\xe9\xe3\x91\xde\x71\x97\xed\xf0\xce\xbc\xe3\x73\xd8\x53\x26\xd3\x03\x61\x02\x79\x99\x47\xe0\xe3\xbf\x9c\xea\x1a\x73\xc1\x8b\x1e\x02\xd3\x3e\xec\xdb\x6e\xd1\x02\xaf\x7d\xcb\x28\x6c\x47\x02\x3c\xb9\x8b\xf7\x3c\xe6\x61\xde\xbf\x2f\x1f\xe1\x26\x0f\xc1\x2b\x22\x8d\xfd\x63\xe9\xe6\xa0\xbc\x10\xc5\x80\x9b\x83\xe2\xd2\x10\xe5\x30\x5a\x0d\x6a\x8a\x89\x93\x96\x99\x01\x1b\x8d\x78\x7e\xf7\x55\x92\x52\x03\x62\x03\xb7\xd8\xf1\xbf\xc7\x06\x7c\x34\xe0\x63\x60\x40\x4a\x57\xf8\xe7\x18\xff\x9a\x06\x6c\x22\x03\x36\xc7\x06\xdc\x04\x9a\x51\xea\x86\xbd\xfc\x9b\xfa\x5d\xc6\x87\x11\xe6\xb9\xdf\x8c\xb2\x52\x63\xd4\x85\x8b\xd9\x9d\xa6\x99\x80\xc7\x09\x34\xae\x54\x84\x59\x90\x4e\xbc\x13\x43\xba\xc4\x2a\x05\x53\x13\xda\xbe\xb7\x09\xa4\xc9\x01\xfb\x76\x13\x88\x7f\xb4\xb3\x05\xd0\xe5\x7a\xd7\x99\x99\x6a\x23\xe6\x89\x77\xc2\xda\xa5\x12\x96\x49\x0a\x7e\x92\x2f\xea\xd8\xea\xf6\xd6\xdc\x63\x44\x44\xf4\xf8\xbf\xcc\xad\x83\x27\x8c\x26\x7c\x0e\x85\xe1\x6d\xe0\xb8\x1f\x60\x5f\x86\xf0\x04\x5b\x3d\xe8\x5c\xa5\x17\xe8\xfd\xbf\xff\x8f\xc9\xd0\xdb\xb0\xe9\x3d\xfb\x9e\xa4\x70\xc3\xbf\x17\xd8\x21\xbe\x69\x51\xba\xca\x24\x9c\x15\x05\xb5\xa8\x23\x5f\x65\x2c\xcd\x82\xdc\x4f\x20\xc3\x24\xbf\x07\x90\xc1\x3e\xa8\x97\xdd\xb7\x4b\x8e\xfb\xb1\x15\xb4\xcb\x14\x15\x3f\x32\x09\xfa\x58\xe6\xca\x6b\xbe\x16\x91\x02\xd8\x83\x1b\x55\x8e\xf9\x8c\xef\x1d\xdc\xe5\xd9\xe8\x74\x43\xdf\x3d\xad\x12\xb2\x0f\xbe\x3c\x04\xbd\x7b\xc4\xde\xfa\x51\xfe\x82\x2f\x1f\x31\x6c\xe4\x6d\x84\xcc\x8a\x95\x2f\x6f\x1a\x2f\xd5\x00\x31\xfa\x22\x97\x53\x7a\x5a\x3a\x23\x88\xb1\xc2\x72\x25\x41\x04\x31\x12\x5c\xd9\xc0\xfd\xe5\x94\x3b\xe9\xb5\x7c\x21\x90\xcc\x41\x9d\xc9\xf2\xb4\x9e\xf7\xaf\x5c\x46\x29\xb9\x96\xf1\xc1\x44\xf2\xe8\xb1\xcd\x85\xd7\x13\x6e\x83\x66\x42\xd2\x1b\xb1\x08\x06\x7c\xfa\x83\x0a\x6e\xc2\xb0\xcc\x47\xaa\x64\x1d\xaf\xf4\xb8\x51\x07\x86\x40\xf7\xf6\x74\xec\xce\x3a\x57\xc8\x3e\x8a\xb5\x75\xdd\x0c\x15\xb7\x4e\xf3\xeb\xe3\x6e\x9b\x0e\xf2\xb8\x1e\xa3\x54\x95\xb9\x61\x65\x6e\xba\xcb\x44\xfa\x03\x9f\x99\xd8\xbf\xa4\x0b\x46\x9c\x24\xe9\xca\x5b\x46\x19\x65\xfa\xcd\x26\x4e\x37\x01\x64\x09\x2c\xa2\x8b\x05\xcd\x72\x48\xd2\x90\xa6\x22\x1e\x91\xcc\xd9\xcb\x28\x83\xc7\x3c\x9e\x05\xfb\x60\x8d\xd4\x80\xe3\xfa\x02\xaa\x28\x3d\x10\xa6\x8d\xa7\x81\xec\x58\x00\x3b\x49\x72\x88\x69\x40\xb3\xcc\x4b\x6f\x0c\xf0\x2f\x31\x32\xb7\xf0\xe2\x70\x49\x21\x09\xf9\x2c\xb2\x48\x58\x79\x53\x58\xa4\xb2\x1d\x0b\x75\x4c\xb3\xc3\x71\x7f\xbf\xb8\x31\xe1\x31\x8f\x2c\xc5\xbb\xbb\x98\x40\x9e\x59\x37\x0e\xeb\x91\x0c\xa8\xe3\xb4\x34\x07\xd1\xe5\x71\xe2\x68\x57\x4d\x39\x6f\x02\x1c\xb0\xb9\x71\xd1\x3b\x93\x9b\x7a\xad\xcd\x76\xb5\xb6\x11\x14\xd8\x52\xe8\x34\xf9\x1a\x37\x4c\xd0\x6e\x8e\xd5\x75\x52\xba\xe2\x80\xab\x7c\x9a\x37\xc7\xfa\x44\xfa\x2b\x86\x46\x4a\x57\xfa\x4c\xbc\x20\xe6\xf7\x61\x28\x36\x04\xe4\x09\xac\xbc\x0f\xf2\x85\x65\x5e\x06\xcb\x24\xbe\x60\xff\x2a\x7d\xad\xe2\x53\xb8\x78\xd8\xec\x23\xd6\x05\xf6\xf5\x8c\xfd\xe4\xfb\x21\xb4\x87\xd8\x6f\xfe\xc6\xa9\x5a\xcc\xa1\x35\x85\xca\x79\x9c\xa9\x2b\x12\x98\x20\x86\xf6\x8e\xe3\xb3\x37\xc1\x19\x39\x97\xf5\x0b\x86\xac\xe6\xee\xae\xba\x8e\x56\x55\xd6\x22\xf5\x79\x9e\x46\xde\x52\xa8\x6f\x2c\x22\x80\x86\x74\x39\x34\x6f\xc7\xd6\x6a\x4a\xb5\x8b\x90\x8f\x79\x87\x60\x73\x35\x31\xb9\xca\x0c\x45\xbf\x08\xd3\x69\xba\x47\xc6\x1a\x36\x86\x49\x87\x92\xc4\x3d\xd1\x46\x5c\x2e\xc2\x69\x6d\x79\x0b\x1f\xbf\xdc\x49\x48\x81\xde\x65\xe1\x93\xbd\x72\x4e\x7c\x53\x38\xc6\x37\xdc\x2d\x3e\xee\xdc\xa0\xc8\x0f\xb9\x14\x2d\x3e\xda\xa6\x3d\xbe\xdf\x72\xb5\xd6\xe7\xf7\x6e\xf6\xab\xb8\x11\x52\xe6\x94\x01\xb1\xc6\xac\x16\x1f\xe6\xd2\x73\xed\xe9\xdd\xd1\xcb\xc5\x0a\x67\xf2\xbc\xc7\x52\x65\xb3\x9a\x5e\x0d\x10\x18\x29\x87\xd8\x5e\xcc\x71\x0d\x69\x91\x5c\xf3\x3c\x95\x79\xb4\xa2\xf5\x7b\x12\x2f\x12\x8a\xeb\x79\x49\xcd\xb5\xd8\x82\x86\xd0\x1e\x3e\x10\xd5\x7d\x14\xb5\x2d\x30\x83\xa7\xcb\x8b\x24\x8d\xf2\xc5\xaa\x77\xab\x39\x90\x91\x38\xa0\x94\xf3\x45\x2c\x44\xfd\x41\x4d\x6d\x06\x71\xff\xa6\x7d\x6b\xc4\xe8\x5c\x40\x7a\x5c\x75\xf3\xa0\x7c\xb8\x57\xc2\x37\x20\xde\xdb\xeb\x05\x69\x8f\x24\x33\xb7\x77\x58\xc0\xe9\xad\xe7\xd4\x50\xb9\xf6\x32\x59\x72\xc1\xcb\xc1\xea\xa7\x0a\xc0\x78\x54\x68\x0d\x3a\xe4\x12\x80\x38\x2c\xfa\xb1\x05\x98\x09\xde\xf2\x5d\xd5\x7e\x5c\xd4\x3d\xa8\x77\xae\xa2\xcc\xee\xee\x16\x1b\x39\xab\x71\xb7\xb3\x2c\x14\x92\x2a\x3c\xde\xc7\xe2\x6e\xad\x78\x79\xc3\x4d\x20\xfe\x8c\x32\x9d\xfd\x6b\xb6\x1b\x17\x86\x79\x88\x02\x8a\xb5\x35\xe9\xd1\xdb\x58\xf4\x88\x59\x3f\x06\x0c\xc0\x5d\x9c\x09\xb9\x3e\x1b\x72\xd9\xbf\xbd\x3e\x42\xf1\xd9\x76\x98\x6e\x74\xb6\x30\xd7\x45\xa7\xb7\x34\xd7\x12\x84\x97\x4a\x75\xda\xaa\xea\x69\x6d\xcc\xcb\x13\xee\xcc\x6e\x55\x15\x8d\x1a\x29\xeb\x80\xe7\x27\x97\x39\x8c\xbf\x2d\x6f\xd5\x8c\x56\xd4\x10\x77\xd2\xe2\x79\x54\x7e\x79\x2d\xfa\xa6\x57\xed\x8d\x1a\x8a\x16\xf0\x16\x6a\x9f\xd2\x58\xce\xf7\x7f\x0b\x24\xaf\x17\xd1\x92\xb2\x41\xa6\x18\xd3\x78\xf0\x07\x47\x35\x11\x01\x12\x66\x5e\x8c\xcf\xfd\x1b\x9d\xd9\x27\x56\xce\x8d\x34\x7d\x28\xa3\x86\x85\x24\xe3\x74\x4f\xb0\xab\xbf\x0b\xec\x53\x05\x31\x39\xfe\x37\xcc\x2b\xe3\x12\xfa\x84\xb9\x5c\x07\x28\xdd\xa2\x43\xdb\x4a\x38\xdc\x55\xca\xa1\x74\x15\x7a\x82\xc0\xd0\xb9\xed\x19\x6e\xbb\xeb\x1b\xc5\x0d\xc3\x34\x04\x03\xf1\xec\xe7\x5e\xcf\xc1\x2c\x28\xf5\x23\xae\xdd\xd8\x8a\x02\x89\x9b\x3a\x98\x38\x16\xc6\xfb\x26\x28\x74\x0f\xbc\x0b\x2f\x8a\xc1\xa7\xcb\xe4\x5a\x1d\x99\x6b\xb4\x90\x25\x10\xf0\xfb\xcc\x19\x66\x79\xc2\x73\x88\x79\x78\x3d\xd5\x36\xf6\x4a\x42\x92\x18\xb0\xa4\x6c\xf6\xcf\x20\x79\x19\x26\xd8\xca\x92\x1a\x72\xfc\x76\x5f\x86\x73\xc8\x31\xdd\xce\x24\xf3\x2b\xa7\xb6\xf0\xb5\x24\xac\x14\x1e\x1d\xa2\x13\xc3\xea\x32\xc3\x6c\x54\xe5\xc1\xe4\x2d\x78\x01\xa5\xec\xc4\xdb\xca\xcf\x9d\x86\x8b\x6d\xc7\x87\xbe\xa9\x4a\xb3\xca\xad\x94\xa5\x07\x77\xe4\x08\x07\xfa\xa8\x30\x43\x08\x5b\x9e\x1c\xf5\xb9\x0d\xa5\x75\x29\x48\x80\xd6\x65\xcb\x21\xa0\xb2\x2b\xa5\x45\x2c\xc2\xe0\xdb\x58\x91\x5b\x0f\x77\xf5\x91\xaa\xe1\x6d\x75\xa3\x5a\xce\x15\x0e\x0f\xf9\x25\x4a\xdb\xd9\x0c\xd5\x4c\xa8\xe6\xa2\x6d\xab\x99\x95\x1a\xd4\xaa\x1b\x25\x0d\xeb\xe6\xfd\x4b\xc7\xe0\x65\x72\x7d\xdb\x21\x78\x99\x5c\x77\x8c\xc0\x57\x34\xbd\x81\xd4\x4b\xe9\xf2\x06\xef\xd1\xdd\xb2\x89\xd6\x00\xaa\x98\x14\xe2\x9e\xa3\xad\x87\x4e\x36\x39\xff\xb2\xa1\xf3\x16\xb4\x85\xb6\x90\xdf\x94\xda\x26\x0d\x9d\xdb\xcb\x7c\xf1\x51\xc8\x7e\x5f\x95\x9e\xa1\x50\xfb\xb6\x76\x3a\x11\x35\xa0\x2b\x49\x59\xf1\x89\x75\x51\x10\xa9\x07\x70\x08\x9d\x33\xe2\xcf\x65\x50\xa3\x68\x97\x70\x0d\x2a\x6f\x3c\x37\x3b\x03\x02\x4f\xc5\xe6\x98\x98\x6e\xf2\x72\xb2\x6e\x94\xdb\x06\x79\xa4\xbd\xe3\x22\x1c\xc0\x70\x72\x71\x08\x27\xee\x8e\x3e\xfc\xb8\x0e\x31\x32\x20\x5f\xd1\xdf\x13\x7b\xe0\x11\x81\x5e\x52\xd6\x63\x5f\x9b\xe0\x6c\x23\x02\xe5\x5d\x94\xeb\xb9\x00\x06\x2a\x0e\x14\x10\x7b\x42\x13\x42\xe2\x3a\xc6\x4c\xcd\xaa\x7a\xa9\xc4\x03\xd8\x44\xbb\xbb\xf0\x08\x36\xc7\xb8\x21\x91\xf7\xbe\xd8\x0f\x89\x5b\x21\x33\xcd\x91\x19\xa8\x02\xf7\xf5\x6a\xfa\x40\xe4\xb1\xb4\x8c\xdc\x5e\x8f\x84\x72\xed\xe8\xa3\x58\x7b\xfc\x58\x9e\x51\xd9\x7a\x5b\x48\x19\x66\x13\x2b\x45\xfa\x4d\x84\xa7\x09\x04\x65\xf0\xe8\xe3\x88\x1a\xe2\x18\x4b\x71\x5d\x93\xd8\x54\x9d\xcc\xa5\xc3\x2e\x88\xd8\x16\x27\x57\x32\x38\xe4\x65\x1f\x42\x56\x1c\x5d\xc9\xa4\xa3\x2b\xda\xa0\x2e\xbf\x16\xf5\xa3\xc1\x57\xd8\x06\x0c\x2f\x5c\xc5\xdf\x05\x0a\x0f\xe4\x83\x28\x04\xb7\xd7\x10\xbe\xe0\x8d\x6c\xd0\xec\xad\x7b\xc6\x77\xa6\x45\x99\x7a\x83\x58\x49\xce\x2e\xe9\xfc\xd8\x75\xe9\xd6\xc7\x51\x0a\x87\xb0\xcb\x70\xd8\xee\x70\x0c\x5f\x3c\xfd\xb8\xfd\x09\x17\x75\x6e\x28\x71\x4c\x25\xa5\xeb\x94\x66\x34\xce\xc5\x66\xff\x6a\xf1\xad\x4a\x1c\x85\xbb\xe8\xe6\xd1\x86\x86\x7b\x78\x41\x23\x9b\x30\x48\xd7\xb7\xca\xe0\xcb\xab\x74\xa5\x7b\x7a\xeb\xfb\xef\x9a\xa9\x91\x52\xc5\x5d\x73\xfa\xbb\xf0\xa3\x4c\xbe\x3a\xbf\x76\x25\x41\x54\xe4\xf0\xc2\x23\x2f\xc5\x78\xbd\x64\x6e\x34\xf7\x03\x52\xfa\xf1\x32\x62\xfe\xfd\xa0\xb9\xe9\x5a\xb9\xb5\xba\x96\x71\x0a\xd2\x55\x01\xbe\xdc\xc1\xbd\x4a\xc2\xfa\x95\xfb\x41\x25\x2b\xe2\x5b\x78\x00\x79\x22\x5f\x37\x49\x66\x46\xb1\x4d\x12\x2f\x6d\x28\xee\xf3\x00\x8b\xb0\x1f\x6f\x8a\x13\x2a\x60\x39\x3d\x57\xf1\xcf\xb1\x1e\xde\x0f\x1f\x71\x31\x16\x8d\x2a\xef\xe4\x37\x71\xd3\x46\x4c\xab\x0b\xf9\x9b\x9b\xba\x57\x7c\x57\x77\x61\xbb\x1a\xc9\x03\x19\x7c\x9e\xc9\x9d\xb7\x62\x94\x64\x78\x95\x84\xb4\xb5\x91\xfb\x09\x03\xf5\x09\xd7\xe4\x7b\x8f\x0d\xdd\xe3\xb7\xac\x17\x3b\x22\xaa\x64\x25\x0d\x25\xc7\x38\x7f\x3c\x6a\x2f\x60\xc4\xe5\x7d\xee\x6d\xe0\x51\x99\xa4\x47\x35\x24\x15\x57\x97\xd6\x8e\x9d\x20\x3a\xba\x2d\xae\x82\xc6\x6c\xdc\x9e\x31\x8b\x5f\xfd\xb6\x1c\xbc\x6e\x98\xc2\xa3\x43\x29\x21\xb7\x42\xe5\x9f\xd4\x45\x42\x6c\x94\x8d\xdb\x44\x04\xdc\x08\xaf\xd8\x54\x1b\xb7\x77\xd5\xea\xcc\x0f\x9b\x13\x0a\xab\x58\xdf\xd8\x10\x0f\x85\xdc\xe8\x0c\x5f\x3c\x92\x56\xcd\xf9\x44\x3c\xc4\x74\x6d\xa5\x8d\x60\xb3\x0d\xdd\x49\x04\x10\x9b\x10\xda\x6c\xb9\x2d\xdd\xb7\xbb\x31\x53\x56\x1d\x2e\x49\x99\xfa\x8a\x6f\xd1\x83\x6a\x74\x6a\x5b\x1f\x15\xfc\xca\x7e\x45\x99\x94\x15\x4f\x39\xd0\x95\xab\x61\xcc\xf8\x95\xf6\x55\x98\x26\x3c\x5f\xa4\x6a\x01\x4f\x5e\x25\x32\x7d\x1b\x46\xb7\xe8\x82\x62\x69\xa6\x71\xa7\x6d\x55\xb2\x59\x90\x7b\xbc\x3d\x32\x3c\xe0\x7b\xc1\x29\x7b\xd7\x10\x67\x5d\x82\x4d\x81\xc4\xd3\xf5\x9a\xc6\x62\xb1\x54\xed\xa0\x14\xeb\xa0\x8c\xab\x8f\x20\x92\x2f\xdd\x43\xd3\xa4\x1f\xdb\x8b\x2d\xe6\x6d\xd5\xd1\x8e\xdd\x2f\x94\xd4\x6b\x16\xec\xbe\x99\x1f\xf6\x0e\x21\xd6\x0c\xdd\xdd\xbb\xde\xef\x4e\x24\x71\xff\xe4\x2e\x10\x78\xbc\xd5\x95\x92\xb0\xb7\x17\x89\x7b\x89\x39\x81\x0b\xaa\x8e\x76\xb6\xbe\xdb\x70\x8b\x0b\x16\x77\xf9\x9d\xac\xda\x4b\x16\x41\x3a\xb4\xb9\xc5\x7c\x4a\xea\xe6\xe1\xa1\xe8\xa7\x84\x78\x67\xdd\x5b\x5e\xdc\x08\x77\xde\x21\xfb\x59\x99\xab\x2e\x16\x87\x87\xee\xdf\x67\xc3\xd2\x13\xd8\xd9\xdb\x81\x5d\xc4\xe3\xa0\xf3\x78\xc2\x0f\x7c\x07\x49\x3d\xd9\x29\x9b\xff\xd5\xf2\x81\x2a\x0e\x0c\xd7\x52\x81\x66\x06\xac\x68\xbe\x48\xda\xe7\x5f\xc4\x99\x81\x58\x73\x41\x92\x72\x84\x14\x97\x15\x20\x60\x3e\x6f\x18\xe2\x77\x7e\x45\x52\xd6\x1a\x6e\x57\xad\x4d\x72\x55\xd5\x46\x03\x05\x97\x76\x77\x71\x43\x75\x7a\x91\x95\x87\x5a\x54\xc2\x11\x6b\x20\x47\x6d\xc8\x50\x86\x91\xbc\xf8\xa6\x30\xc1\x51\xc6\xb7\x44\xa6\xe5\x66\x49\x8d\x05\xbc\xc7\xf8\xa7\x13\xcf\x15\x9f\x18\xab\x5e\x69\xf6\x60\xcb\xe1\x04\xce\x98\x11\xb3\xa9\x03\x64\x45\xc7\x8d\x07\x9a\x96\xb6\x11\xc0\x95\x46\xc4\x54\xbe\x7e\x9e\x5e\x22\x72\xdc\x7b\x2e\x8f\x01\xb3\xf1\x05\x33\x92\xca\x99\x31\xf3\x45\x5a\x0b\x62\x3d\xc0\xc4\x24\x8c\x8f\xe5\x4d\x91\x57\x3c\x0b\x3f\x93\x4a\x5c\xc4\xac\x72\x8f\xb0\x86\x7a\xbc\x56\x75\x7a\x7f\xf4\x62\x57\x11\xfb\xe3\x6d\x2a\x17\x33\xf6\x56\xed\x3d\x90\x22\xea\xfe\x88\x95\xc7\xdd\x53\xf0\x98\xd5\xe2\x5f\xef\xe1\x2e\xb8\x38\xf0\x72\x3a\x88\xd5\x84\x17\xf9\x5c\x8a\x36\x06\xbc\x95\x4f\x9f\x60\xa7\x3e\x33\xd9\xd1\x64\x0a\x52\x36\xfe\x04\x76\x6a\x49\x5e\x77\xe0\xa0\xca\xf7\x2c\xe8\xbd\x03\x43\x83\xdf\x76\xdd\xcf\xde\xfa\x56\x3e\x3d\x87\x99\xef\xb4\x6e\xec\x69\x34\xa4\x79\x79\xf3\xfe\x65\x7e\xd2\x09\x33\xb1\xe2\x22\x47\x96\x97\x37\x6d\xb0\x37\xe2\xee\x8a\x1a\xff\xab\x93\x52\xab\x28\xbe\xcc\x0c\x58\x2f\x2f\x33\x2c\x8d\x7b\x2e\x7a\xf8\x1d\x17\xbb\xfb\x90\xc5\x01\x0e\x8d\x0a\x9b\xc5\xe7\xfd\x2d\x6a\xff\xc6\xbc\x44\x8d\xdf\x77\xbb\x13\xd4\xf7\x82\xb3\xbd\xbd\xdf\xce\xcb\x54\x26\xaa\xdb\xe4\xa5\xbd\x30\xaa\xab\xab\xe1\x45\x6f\x7c\xa3\x1d\xde\xe0\xed\xff\x56\x66\xe2\xf8\xad\x08\x67\xfc\xd6\x08\x67\x34\x91\x51\x5f\x6e\x8e\xc2\xcf\x13\x92\x68\x82\x1a\x3d\x77\x9e\x77\xde\x77\x1e\xe3\x9e\xe6\x58\x77\xd7\xb9\xfe\x9e\xf3\x5b\xdd\x71\xae\xbd\xfa\x38\x16\x57\x1f\xc7\x9a\xab\x8f\xb5\x73\x1c\x5d\x78\x25\x56\x25\x0a\xd1\x0c\xe8\x7d\x43\xb6\xb8\x34\x12\x43\x05\x73\x2f\x5a\x16\x7e\x3a\xde\xff\x08\x39\xcd\x72\x66\x4f\x15\x91\x89\xb5\x97\x66\xf4\x44\xe4\x06\xe9\x4d\xce\xcc\xa4\xee\x4d\x4a\xe7\xd1\x06\x0e\x61\xff\xfd\x60\xef\xc9\xd0\x1c\x9c\x6d\xfc\xe4\x7c\xb8\xaf\x38\xfc\x17\x26\xf9\xd3\x79\x8e\xd7\x36\xef\xbf\x1f\x9c\xbd\x1f\x9d\xef\x0e\x7f\x19\xfd\x79\x5f\x59\xf2\x3b\x3a\xe7\xf1\xc6\xfd\xf7\xbf\x8c\x44\x61\x55\xd1\x28\x2b\x44\xe4\x75\x7a\xe2\x9d\x60\x85\xbd\x27\x83\xe2\xe1\xa7\x13\xef\x44\x59\xef\x7a\x11\xe5\x34\x5b\x7b\x01\x7d\x9d\xbe\x61\x46\x02\x5b\xca\x1e\xfc\xb2\xfb\xe9\xfd\x2f\xd9\xee\xa7\x5f\xb2\xdd\x3f\xef\x5f\xf4\x25\xff\x85\x8d\x21\x66\xb9\x97\x2b\x03\x7c\xed\x41\x14\xdc\x49\xa8\x76\xcb\x51\x7c\x57\xf0\xa4\x72\xc8\xaa\x94\x1d\x4d\x24\x8b\xfc\x1d\x2a\x31\x3d\x49\x80\x6e\x02\xba\x46\xc4\x92\xda\x81\x85\x24\xed\x70\x2f\x1a\x04\x1c\x31\xe9\x18\x64\x7a\x3f\x80\x27\x37\x88\xb2\x13\xef\x84\x15\x7b\xc2\x03\x16\x07\x50\x1c\x50\xdf\x23\x70\xa0\x8a\x52\x77\xcf\x5c\xb8\xa3\x73\xb9\xea\x4f\xb1\xa8\x97\xb9\xc1\x93\xc3\x5f\xae\xcf\x7e\xb9\x1e\x9d\x3f\xf8\xf3\x70\x3f\xd2\x42\xc1\xe3\x01\x15\x91\x2b\x88\x86\xcc\xd9\x95\x01\x6b\x62\xc0\x5a\xbf\xab\xb9\xf8\x88\x03\x0e\x03\x56\xf6\x10\xd6\x56\x3d\x87\x0c\xdf\x5c\xb2\xb3\xd9\x81\x27\x40\x26\x70\x80\xa5\x0e\x61\xc7\x67\x0f\x2c\x38\x90\xaf\xdc\x56\x7d\x84\xcc\xdd\xf3\xd9\x10\xee\xb3\xaa\xd8\xde\x13\x58\x33\x42\xaf\x3a\xa6\x10\x5d\xcb\xc7\x8c\xe0\xfe\x96\x1d\xf3\xfb\x97\xa1\xf1\x50\xf7\x0e\x19\xed\x40\x9e\xf0\x4c\x01\x3b\x23\xc2\x7f\x98\x23\xa2\xba\x69\xb4\xfa\x34\xd8\x51\x58\x09\x03\x76\xfe\x4c\x76\x60\x58\x7b\xc3\xad\x82\xc1\xa0\xe2\xcb\xae\x09\x54\xf7\xac\x8f\x69\xdb\xbd\x43\xc8\xa4\x60\x5e\xdd\x99\xcf\xba\x17\x04\x35\xf0\xf7\xf7\x61\xa7\x0e\x68\x28\x6e\x42\xe2\x43\xf0\x01\xfc\x3d\xfe\xac\xa6\x87\xbe\x2a\xe2\xf1\x77\xff\x73\x3f\x0c\xc5\xfd\x61\x51\x68\xc0\x0e\xc2\xd9\xc1\x55\x06\x1f\xfd\x3f\x04\xc9\x1e\xf8\xcc\xf9\x43\xf7\x91\xf9\x80\x08\x7f\x87\x9f\xb4\xd7\x74\x9c\xeb\x3f\x1f\x71\xb7\x20\x8a\xc8\xbb\x22\x0d\xd3\x2d\x9c\x15\x17\x70\x55\xb3\x0a\x45\x0a\xac\x53\xe6\xf6\xcb\x91\x75\x40\xc7\x5c\x31\x11\x6d\xb8\xcf\xab\xec\xc2\x60\xc3\xa0\xd2\xab\xa3\x0c\x86\x98\xd3\x21\xbc\x01\x9c\xb5\x70\xad\x33\x68\xc7\x28\x50\x6a\x9f\xe3\xda\x09\x56\x6b\xf1\xbe\xfa\xec\xef\x43\x3b\x8f\xa9\xb8\x4e\xa6\x5e\x78\x7f\x1f\xda\x89\x4b\x77\xc2\xe8\x4a\x05\xd3\x56\x96\x3c\x4d\x5e\xc6\xb9\x5c\x7c\x7f\x1f\xda\x09\x5a\x77\xe8\xc7\x16\x48\x4c\x3e\xde\x2e\x79\x91\x2b\x4b\x4e\x54\x25\xa9\x0a\xcf\x69\xbb\xe4\x52\x0d\xd3\x55\x95\x54\xc2\x6c\xe7\xfa\xdc\x41\xd7\xbf\x51\x96\x51\x5e\xc1\xa4\x55\x12\x2a\x99\xa4\xe0\x12\x9b\x49\x34\xcb\xb2\xa2\x0a\x36\x95\xa9\xbb\xa4\xf2\xac\xa8\x82\x4f\x3c\x39\x65\x8b\xf7\x44\xc1\x28\x8c\x5e\x2b\xba\xa5\xe0\x14\x2e\xa4\x2a\x8a\x2a\x58\x85\xf3\x22\x45\x51\x05\xaf\xf2\xe4\x39\x4e\x1e\x1a\x32\x45\x14\xcc\xaa\x45\x3e\x2b\x35\x21\x0a\x6e\x89\x88\x64\x0d\x05\x26\xfd\x0a\x6e\x15\xeb\x4f\x0d\x04\x2c\x05\xb7\xf2\xe4\x85\xc8\x12\x56\x15\x66\x45\x55\xdc\x4a\xae\x55\x32\x60\x29\xb8\x25\x05\xee\xcb\x2a\xac\xa8\x82\x5b\xc5\xc2\x50\x13\x57\x05\xb7\x2a\x7b\x52\x2f\x5a\xe7\xd6\xf9\x19\x37\x63\xe7\xcc\x52\x0f\x86\x68\xbc\x57\xd9\x05\xfb\x75\x80\x3f\xd0\xb0\x35\x86\x6a\x34\x6a\x23\x0c\x1a\x1c\x4a\x0d\x71\x03\xd7\x88\x5a\xaa\xec\x30\x46\x58\x38\x94\xad\x62\x38\x4c\x44\x61\xc3\xc6\xfd\x2c\x54\x2c\x56\x88\x63\x34\xb5\x45\x49\x48\x57\x23\x71\xdf\x0a\x9b\x7f\x26\x57\x34\xdd\xbf\x64\x33\xb7\xbd\xf9\xb2\x11\xdd\x79\x39\x87\x54\x84\x6e\xf2\xc5\x8d\x01\x51\xce\x7e\x89\x5d\xc5\x6c\xae\xc3\x37\x77\x7a\x29\xe5\xab\xe4\xa2\x51\x6f\xce\x2f\x0a\x6a\xe6\xb3\xea\x89\x06\x88\x95\x28\xe6\xe1\x87\x7c\xcd\x52\xbd\x5c\x19\xe2\xda\xd4\x6f\x98\x1f\x25\x36\x20\x8e\x0c\x48\xc3\xb6\xb3\xaf\x3f\xe8\xbd\x4e\xae\x33\x62\x4a\x89\x57\xdb\x53\xd9\xe2\x9c\x32\x1b\xc7\x9b\x6e\xfd\xa8\x9d\x88\x70\x13\xe8\x26\xb3\x69\xd8\x5a\x19\x56\xe7\xf6\xaa\x88\xb6\x7d\x46\x2f\x90\x36\xa5\x09\xaf\x05\x93\x2b\x73\xb7\xc2\xa8\xaf\xd8\x63\xbe\xce\x2a\x8b\x28\x6e\x03\x42\x6f\x21\x48\xe2\xdc\x8b\x62\x14\x94\x50\xdd\x40\x7b\xf5\x3c\xc6\x1b\x9e\xa2\x98\x41\x50\xd6\x29\xfb\xad\x0a\x85\x28\x16\x5a\x18\xd1\x5b\xad\xa4\x61\xd1\x4c\xcc\xaf\x66\x42\x02\xf6\x24\x4c\xd8\xdf\x87\xdf\x0a\x48\x5e\x90\x5f\x7a\x4b\x35\xc0\x41\x34\x67\x53\x28\x43\xf0\xc8\xab\xc1\x1d\xb6\xe1\x26\x97\xf9\x41\xc7\xf2\xd6\xf7\x1d\xa1\x1f\x65\x1e\xd7\x8d\x82\x70\x50\x46\x85\x42\xbe\xd9\x85\x67\x7b\xc2\xe8\xd0\x87\x22\x3a\xf4\xa1\x88\x0e\x85\xfa\x05\x31\xcc\xf0\x19\xc2\x9e\x32\x07\x18\x94\xf1\xf1\xb6\x60\x32\x52\x88\xb4\x48\x2a\x8c\x35\xa9\x65\xb7\xc8\xe4\x0b\xc5\x2a\x51\x95\x77\x59\x57\xec\x37\x44\x5e\xff\x3e\xe6\x44\x61\x72\x29\x42\x41\x5d\x33\xd8\x82\x31\x8d\x7e\x7a\xb9\x10\x8b\xdf\x34\x12\x59\x7c\x52\xbc\xfa\x07\xf6\x85\xdd\x38\x03\x46\xd6\xdf\x30\xa2\x76\x0e\xdf\x02\x31\x3b\x2e\x43\xee\x5b\x36\xc3\x1e\x54\x37\xfa\x0c\x30\x70\x47\x60\xd8\x77\xb1\x4f\xf1\xe1\xf1\x6e\x4c\x83\x5a\x25\x7e\xeb\xdd\xac\xdb\x9d\x03\x4e\xfe\xec\xef\xc3\x09\xcf\xc4\xe8\xdf\x40\xf6\x31\xdd\x62\x67\x7d\x95\x96\xb2\xc0\xe7\xd1\x21\xc4\x11\xcf\x4c\x79\x99\x2d\x06\xe6\x56\x97\x82\xe0\xde\x84\x8e\xab\x82\xe5\x4f\xb8\xdd\xde\xf6\xa8\x9e\xf5\xbb\xaf\xf8\x6f\x18\x47\xdd\xab\x18\xb1\xdb\xd7\xc8\x56\xbb\x10\xa1\x58\x2a\x62\x06\xa5\x6f\x43\xfb\x17\xb5\x14\x97\x69\x46\xcf\xe2\xa8\xef\x0e\x82\x1e\x0b\xd6\x73\xe2\x41\xb2\x59\x1d\x86\x6a\x5b\x04\x54\xe6\xba\x67\xbb\x7a\x4f\x42\xf7\x5b\x34\x64\x88\x04\xd7\x22\xfb\x68\xcf\x60\xd3\x00\x7c\x5a\x23\x5f\xad\x2e\x1f\x35\xa3\x0c\x2e\xa2\x2b\x1a\x33\x7d\x92\xd3\xbd\x77\x43\x56\x88\xa2\xce\xae\x2b\x7a\x79\x57\xc3\x07\x85\xf1\xfb\xff\xb9\xfb\xba\xed\xb6\x91\x24\xcd\xfb\x7a\x8a\x70\xef\xba\x48\x9a\x00\x09\xd2\x52\xd9\x96\x4c\xeb\xd8\xd5\xaa\x6e\xcd\x71\x51\x5a\x5b\x35\x3d\xbb\x2a\x6d\x1f\x90\x48\x49\x90\x48\x80\x06\x40\x89\x94\xe5\x79\xa7\x79\x85\x79\xb2\x3d\x19\x99\x09\xe4\x2f\x08\xaa\xe4\xde\xe9\xd1\x85\x2d\x01\xc8\xc8\xc8\xbf\xc8\xc8\xc8\x88\x2f\xae\xb9\xa9\x31\x80\xbd\x47\x0a\x42\xa8\xb9\x62\xb7\x3e\x2e\x81\x47\x73\x81\x3c\xea\x76\x99\x60\x30\xc5\x54\x11\x4d\xd6\x15\xd0\xde\x06\x65\xd4\xee\x5c\xc1\x87\x90\xac\x16\x19\xc9\xd1\x5f\x08\x12\x78\x6e\x6d\x70\xe9\x49\x14\xce\x66\xf2\x42\x51\x50\x5a\x5d\x95\x28\xe0\xad\x61\x41\xb5\x59\xd2\xbb\xec\x95\x17\xb1\x6f\x82\xd7\xaf\x06\x3b\x78\x91\x86\xba\xcc\xd0\x13\x78\xeb\x82\x2f\x3a\x8b\x72\x78\x35\xd8\x71\x8d\x1f\xae\x7a\x05\xa9\x95\x61\xfa\x88\xc1\x4c\x70\x30\xed\x6d\x73\xad\xd5\x0a\xdc\xd5\x51\xe9\x01\xb4\xe9\x94\x79\x32\xac\xd7\x3d\x4a\xed\x1d\xec\x62\xe9\x88\x96\xde\x95\xa9\xda\xd0\x5e\xeb\x23\xf5\xf1\xdc\x73\x77\x45\x10\x22\xc9\x40\xd6\x9d\x91\x8b\xd2\xcd\xca\x54\x8b\xd2\xa8\x66\x99\xb6\x4b\xcf\x96\x03\xb8\xe6\xff\x9b\x6b\xe5\x1c\xf6\x70\x15\xb1\xc1\x41\x48\xda\x0e\x5b\x3a\x9d\x8d\xd8\xb4\x5b\x80\xd3\x8a\x1f\x66\x79\xb5\xa1\xd4\xba\xea\x90\xe1\x63\x37\x61\xac\x6e\x56\x21\x64\xac\xf1\x88\xa5\x2d\x50\x32\xb0\xd6\xdb\xa9\x23\xf0\x99\x25\xd3\x0e\x85\xa4\x55\x34\xf0\x20\xe8\xe1\x3f\x01\xfb\x57\xfc\x17\x0c\x80\x14\x0e\x5d\xbb\x6a\x36\xa2\xb4\x94\xa3\x95\x47\xf0\xbc\x92\xb6\x1b\x22\x05\x98\xb1\xd5\xcf\xa3\xa6\x41\x0a\x9b\x9a\x62\xbf\x01\xb5\xf1\xcb\xaa\xae\x15\xba\x6e\xbd\xd6\x0a\xdd\xb8\xa1\x60\x75\xb1\x4e\x56\x53\x92\xe7\xa6\x4f\xb6\xf4\x53\x39\xd9\xd6\x1f\x0b\xe4\x49\x97\x38\x30\xfa\x80\x43\x55\xd7\xa8\x60\x49\xec\xfb\x8f\xd4\xc3\x55\x0e\xea\x35\xbd\x1b\x69\x9e\xc8\xd9\x2b\x36\x9d\x43\xf0\xce\x66\xf7\xa7\x57\x41\x50\x42\xf0\xee\xfe\x84\xb9\xbc\x2e\xe0\x95\xdd\x4a\xe0\x9e\x04\x78\xc8\xa5\x52\x66\x4e\xc2\x24\x47\xc9\x53\xa7\x77\xd4\xe1\xa6\x51\xe5\x10\x37\x79\x26\xb4\x24\x64\x0b\x9b\xfc\x2a\x37\x8c\xeb\x73\xc4\x38\xbd\x71\xe3\x24\xd6\x4c\x21\xb4\x5b\x2d\x17\x6e\x0f\xc7\x7a\xd9\x22\xce\x18\xcd\x12\xb3\x1d\x5d\xa8\x92\x5e\x85\xac\x7e\xd4\x79\x57\x66\x15\x0f\x71\x8d\xc3\x7c\xd1\xce\x21\xc2\xb9\xd8\x9e\x83\xf3\x0e\xab\xa3\x8b\x7a\xc2\x2e\xe2\x6f\xd0\x26\x11\x45\x64\x83\x6a\x08\x7a\x78\xcc\x75\x65\x31\x70\xfa\x93\x6c\x22\x58\xd2\xa0\xe7\xf5\x1a\x5c\x51\x95\x01\xb6\x3c\x2d\xb5\xde\x34\x50\xff\xa1\x34\xbc\x21\x64\xfc\x8d\xdc\x37\x57\x98\x7c\x61\x9a\x91\x30\x6f\xd2\x1d\x5c\xec\x20\x95\xa6\x71\x92\xab\x1e\xd9\x14\xc0\xa7\x90\x2f\x81\x06\x79\x28\x94\x10\xc8\x4f\x13\x62\xbd\x01\xce\x15\xb6\x39\x6b\xf2\x05\xde\x6c\x20\x45\xdb\x12\x86\x59\xcb\x1b\xd7\x80\x9d\xb2\x26\xdf\x3f\x6f\x76\x68\xdf\x20\xcc\xe1\x11\xd9\xdd\x36\xee\x59\x9b\xf0\xfd\x40\x59\x4c\x12\xca\xfa\x8a\xa5\x12\x13\xe9\x9d\x5c\x49\x36\x1c\x4c\xc8\x1e\x5b\x35\x1e\x56\xac\xf3\x7b\x44\x73\xd3\xb2\x31\x69\xde\xf2\xda\x2a\xad\x1c\xb2\x1c\x2a\x85\xec\x9a\x45\x89\xa9\xce\x59\xee\x8a\xcf\x84\xe2\x61\xcd\xc9\xf5\x43\x4d\x77\x98\x4a\x87\x8e\xd1\xfe\xe9\xf8\xf4\xf8\xf4\x7f\x9f\x1c\xf6\x8f\xc6\x9f\x4f\xdf\x8f\x7f\x3e\x84\x5f\x0f\x4f\xff\x7a\xfc\xe7\xcf\x9b\xa3\xd6\x94\xcb\x62\xb8\xbb\x4a\xf3\x32\x5a\x82\x9b\x83\x27\x79\x3a\x5b\x16\x8a\x55\x3c\xce\xed\x21\x63\xd5\x0d\xc5\x49\x4f\x94\xc3\x3c\xb7\x30\x62\x4f\x60\x04\xf5\xee\x5a\x2b\xc3\x63\x99\xd6\x66\xcb\xcb\x22\x34\xfa\x0e\xbf\xed\xd7\xd6\x85\xa5\xd3\x1a\xc4\xf0\x6d\xec\x0d\x47\x27\xc8\xd1\x79\x21\x2d\x37\x23\x32\x7d\xe1\x4e\x9d\xf0\x4d\x35\xe3\x19\x94\xd3\x0b\xdb\xd4\x56\xba\x71\x4a\xe2\x59\x6d\xaf\x89\x1c\x5d\xb6\x98\x24\xec\x3b\x0f\x79\x65\x47\x02\x8f\x9e\x1c\xb7\xe8\x12\xf9\xc9\x40\x0d\x56\x32\xfb\x20\xce\xe1\x32\x23\x21\xb3\x1d\xf0\x58\x1e\x33\xf8\xb1\xbd\xf6\x60\x22\xe7\xcd\x7a\x01\x7e\x13\xd2\x6a\x8c\x50\x23\xba\x01\x27\x2b\x90\x4a\xaf\x08\xe4\xe1\x9c\x17\x56\xbe\x4c\x33\x76\xda\xd7\xd9\xe0\xb8\xc0\xcc\x0f\xde\x39\x44\x1c\xe6\xe4\x34\xc5\x69\xce\xb0\x43\x24\x2f\xad\xb5\xcd\xeb\x2e\xb6\x18\x60\x05\x70\xb8\x00\x32\xa0\x9d\xe0\xe9\x3e\x3f\x9c\xda\x36\xa3\xa8\x5b\x28\xb5\x80\xd1\xda\xae\xf7\xac\x7d\xa3\xf4\x9d\x6d\xb4\xea\x3c\xfb\x94\xce\xe3\xcc\x9c\x30\x5e\x68\xff\x45\x8b\x8d\x52\x22\xf1\xe0\xd6\xbc\xa3\xc4\xac\x52\x74\xaa\xeb\x50\xd4\xcc\x73\x4f\x8e\x89\x34\x9c\x7c\x12\x9e\x63\xf7\x56\x72\x90\xe6\x0e\xc0\x32\xb6\x2f\x5f\x49\x0a\xf6\x6f\x47\xf2\x19\x36\x6f\x45\x4b\x7c\x08\x75\x0c\xd4\x5d\x55\x89\xad\x4d\x74\xb1\x5a\x65\xfd\x1c\xc1\xf4\xec\xf6\xbc\x0c\x4a\xda\x67\x49\x3f\x03\x9e\xc6\xaa\xcc\x45\x98\xb0\x08\x79\x83\x40\xc2\x05\xa6\x0d\x9e\xd1\xe2\xb6\xeb\x9e\x56\x78\xca\x09\x60\x04\x47\xc6\xd3\x31\x8c\x60\x6c\x3c\x3d\xa2\x35\x2a\x4f\x03\xe8\x33\x3e\x8c\xa7\x81\x41\x21\xb0\xd2\x0d\xac\x74\xc7\x9c\xee\xd8\x78\x6a\xd2\x1d\x5b\xe9\x8e\x39\x5d\xf5\xe9\x11\xa7\x7b\x64\x3c\x35\xfb\xe1\xc8\x4a\xf7\xc8\x42\xf7\x69\x37\x21\x86\x54\x8f\xf7\x4e\xf2\x67\x72\x25\xba\xb8\x2c\x37\x2e\x25\x35\xab\x9a\xbe\x10\x4d\xaa\x4a\xd4\xb1\x73\x31\x33\x06\x3e\xac\xd9\x42\xc6\x5c\x2f\x8d\x04\xe1\x4b\xab\x20\xc4\x1c\x64\x35\x42\xd0\xd3\xf3\x2c\xaa\x5c\x6e\x27\x23\x1b\xf4\xbb\x88\xf3\x11\x91\xa5\x72\x4e\x3f\x75\x50\xac\x5d\xae\x8f\x8b\x3e\x18\x1b\x7a\x15\x7d\xe5\x68\xfd\x55\xf7\xe2\xa3\xa6\x7d\xbc\xf3\xc8\x3e\x0e\x3c\x2a\x06\xb7\xda\x6e\x78\x7c\xd4\x86\x1d\x9d\x7c\x59\x86\x33\x61\x46\x6e\xb4\xa1\x57\x61\x55\xe2\x22\x41\xcf\xce\xac\x74\x1c\x56\xc0\x36\x15\xf2\xa5\x69\x37\xed\xfe\x81\x3d\x99\x9f\x75\xfe\x8b\xab\x9c\xfe\x26\x9d\x13\x4d\x59\x4f\xa9\x74\xbe\xfc\x2e\xf3\xe7\x71\xca\xe6\x96\x73\x88\x57\x72\x4a\xeb\xa0\x13\xe9\xb2\xf1\x7a\xfb\xe9\x8f\x4c\xa4\x77\xdb\x4d\xa3\xc7\xf4\x58\x9a\xd9\x57\x60\xed\x76\xf1\xf8\xde\x3b\xce\x0e\x69\x6d\x5c\x49\xbe\x2c\x48\xd3\x7e\x7c\x65\xed\xc7\x36\x4c\x64\x20\xe8\xfa\xde\xec\x70\x60\x28\x1e\x9d\xa0\x6a\x3f\x4f\xd6\xbb\x21\xe0\xb2\x22\xa5\x2f\xd9\x96\x9d\x15\xe7\xbf\xb0\xf2\x0d\x56\xde\xb3\x67\x42\xd3\x7d\xfa\x66\x48\x79\x6d\xf5\x16\x6c\x6a\x00\xdf\xa1\x70\x88\xf1\xaf\x6d\xda\x02\x3f\xfe\xb8\x41\xd5\x7e\xc7\xf5\xfb\x4a\x41\x1f\x7e\x87\x0e\x60\x59\x60\xb6\x1d\x3b\x16\xd8\xb5\xb9\xb1\xd8\x82\xfc\x3b\xb0\x9d\x90\xcb\xb0\x88\x6f\xc9\x63\x78\xe7\x45\xf9\xb8\x8d\xc9\x65\x93\xa6\xb0\x96\xd0\x33\xc5\x77\x68\x0d\x82\xa8\xfa\xc1\x23\x1a\xf3\x7f\x48\x96\x6e\x3b\xed\xd8\x6f\x22\x0f\xce\x77\x68\xce\x23\xac\x17\x5b\x36\x9c\xd6\x50\xee\x52\xb3\xc6\xbb\xd4\xeb\x3f\xb2\x4b\x7d\x9f\xa1\xaf\xfa\xea\x1f\xb1\x45\x89\x7e\x53\xf7\xa7\x59\xf3\xfd\xe9\xcd\x53\xed\x4f\xbe\xba\x41\x35\xe8\x57\x48\xc0\xc7\xf3\x67\x62\x3c\xb5\x9d\xc3\x7d\x3c\x7f\xfa\x47\xda\x31\xda\xc7\x83\xad\x9f\x18\x8f\x03\xcb\xf9\xdc\x46\x39\xb0\x53\x1e\x73\xca\xfa\xf1\xda\xb7\x1e\xc5\x6d\x84\xc7\x9c\xb0\x7e\x90\xf6\xad\x47\x71\xdf\x7a\x14\xb7\xd1\x3d\xb2\xd0\x7d\x5a\xe5\x1c\xe3\x7b\x9a\xce\x59\xd7\xd4\x64\x44\xe8\x74\xcc\x97\x93\x06\xd3\x91\x27\x80\xbc\xf6\xa0\xf0\x60\xf5\xf1\x74\x6d\xf1\xf0\xe7\x36\x32\xf3\x4d\xc8\x32\xc2\xe9\xa6\x33\x34\x53\x6a\x57\x53\x66\x2a\x7e\xce\x8f\xfa\xd9\x04\xf3\xc2\xe9\x14\x95\x9c\x70\x96\x60\xfc\x67\x21\xba\xdd\x4c\x5c\x41\x8f\xe3\x70\x6c\x89\xee\xff\x1c\x5f\x26\x39\x44\xf1\xc5\x05\xc9\x2c\x44\x43\xcc\x26\x69\xbd\xa1\x59\xe3\xed\x81\x3f\x31\x2f\x65\xc4\x15\x42\x6f\x31\x5b\xe6\xed\x75\x3d\xce\x04\x5e\x5e\x88\x4c\x65\x95\xd2\x62\xf6\xf3\x9a\xa5\xd5\xaf\xff\xc8\x1d\x88\xe1\xc8\xb6\xc7\x73\xe7\x11\x96\xc2\x8d\x38\x81\x02\x78\xd7\x8b\x13\xe0\x86\x24\x7c\x6b\xc9\x66\x8a\x79\xed\xda\x65\x77\x79\xb0\xc6\x2c\xdb\xfa\x3c\xa0\x5f\xad\x60\x0f\x53\xdc\xb9\xb2\x2b\x33\x1e\xec\xa0\x9b\x72\xce\xfd\x06\x69\xff\xaa\x54\x79\x6b\x5a\x74\xcd\x02\x50\x98\x3b\xa3\x07\x2b\x29\x28\x45\x3c\x4b\x59\xcd\xf4\x0d\xa6\xf9\x0b\x33\x82\x0f\xec\x37\x9b\xbc\xf1\x8c\x8b\x06\xed\x5f\xf1\x0f\x57\xee\xfc\x7e\xfd\x3e\x1c\x1d\x1e\x1e\xc2\xab\xdd\x1d\x68\x0f\x83\xe0\x75\x07\x7e\xea\xbd\xdc\x43\xf9\x8c\x82\x38\x60\x30\x30\xa5\x5b\x4b\x91\x56\x47\x76\x07\x4d\xd5\xee\x85\x49\x7d\x0e\x28\xa1\x3d\x7b\x1a\xa4\xda\xeb\xc6\x95\x92\xeb\x6e\x45\xb4\xf2\x6b\xe5\xf5\x5a\x7f\xcd\x66\xae\x04\x59\xae\xaf\xd4\x2a\x77\xf7\xdd\x55\x3c\xbd\x12\x82\x74\x12\x5f\xd2\x83\x83\xd3\xf8\x8d\xe2\x09\x73\x00\x3a\x26\x37\xbb\x14\xfc\x78\x4a\x85\x53\x58\x1b\x55\x41\x49\xf9\xa1\xfd\x1a\xbd\x40\xee\xb7\x44\x06\xc0\x2e\x59\x39\x30\xcd\x0a\x84\x70\x6f\x74\xe7\x5d\xf4\x32\x72\x4b\xb2\xdc\xec\x37\xe0\x17\xbd\x19\xa9\xa0\xce\xe8\xbc\x40\xed\x88\xaa\x3a\x02\x54\xc5\x99\x80\x8f\x0a\xe3\x70\x1f\x26\xbe\xbf\x0f\x45\x5d\x50\x81\xc2\x84\xb5\x0b\xac\x6b\x5a\xd4\xcf\x58\x12\xd1\x72\xcc\x7f\x08\x93\x82\x5b\x5d\xb3\xae\xf1\xda\x85\x8f\x1a\x1f\x64\x29\x26\xe3\x2d\x67\x7c\x2d\x3d\xeb\xc0\x01\x84\xb0\x67\x8d\xf8\x67\x4d\xa5\x54\x26\x2c\xdf\xe0\x04\xde\xc2\xf5\x3e\x4c\xea\xb2\x0e\x0b\xff\x8d\x09\xba\x6f\xac\xf1\x97\x5a\xcf\x3b\xc6\x2d\x2b\xf1\x96\x15\x70\xfb\x64\xd4\xf8\x81\x6c\x89\x94\xd6\xef\xc3\x8a\xd6\x77\x00\x88\x8c\x47\x57\x1a\x57\x8b\x59\x5c\x1a\xbf\x43\xda\xb0\x90\x28\xf7\x1d\x3e\xcd\x3d\xb6\x5a\xd7\x53\x8f\x6d\x2b\x85\x27\xc4\x9b\xb9\x6d\x4f\x70\x80\xae\xb5\xc1\xf0\x75\xb7\x0f\x1b\xf2\x8e\x8c\xcf\x47\x59\x5e\x4d\x29\x27\xf9\x55\x9a\x15\x3a\x87\x0c\x23\x44\xe4\xbc\x08\xe5\x3c\x71\x6b\xb9\x14\x84\x79\x85\x6a\x8f\xe9\x7f\x68\x19\xfc\x2e\x2f\xc2\x0c\xfd\xc3\x4b\x3e\x2d\xd2\x64\xa2\x80\xfb\xf1\x65\xb1\x2a\x61\xbc\x0d\xa1\x39\xe1\xc9\x41\x2d\xd9\x81\xe4\x3b\xbe\xf5\x94\xc1\xbf\xeb\x61\x6a\xa2\x9a\x6b\x78\x47\x17\x61\x8d\xfc\x62\xa8\x4a\x6c\x5a\x5d\xbb\xe7\x61\xe5\x70\x73\xbd\x0f\x31\x3d\xc1\x3e\xe3\xee\x36\xfb\x3c\x49\xe6\xc8\xd4\xc7\xc4\x8f\xef\xe3\x27\x0e\xe8\x04\xac\xb7\xeb\xca\x85\x6a\x43\x4f\xc0\x12\xfe\x88\xb1\x5c\xab\x24\x39\x12\x38\xe3\x05\x13\x8b\x20\x91\x80\xb5\xc4\x85\xd4\x6c\x6d\xef\xcc\x2a\x6f\x2d\x3a\x17\x71\x60\x6e\x0f\x7c\x7f\x6d\xc2\x45\x72\x0f\x61\x9b\xbe\xb9\x72\x6b\x18\xfd\x3e\xfc\x92\xce\x66\xe9\x1d\x65\xd5\xb2\x69\x9b\xea\x19\x86\x96\xb2\x7d\xbc\x1b\x00\x26\xef\x93\x37\x76\x63\x67\xbf\x0b\xb3\x28\xb7\x5a\xe4\xf9\x0f\x5b\x90\xf6\xfd\xdd\x81\x62\xb3\xe6\xfe\x46\x6b\xb7\xbf\x91\x50\x6b\x36\x8d\x96\xb4\x18\xa7\x65\xf8\xb3\x9c\x64\xb8\xbb\x02\x1f\xba\x6b\x2a\x39\xcb\xc7\x3f\xfe\x08\x3e\x7d\xec\x2b\x8f\x75\xd2\x94\x12\xb7\x97\x32\xc4\xc6\xb5\x35\xa9\xb6\x84\x77\xb6\xf6\x50\x66\xad\x49\xc3\xdb\x04\x16\x87\x42\xcf\x84\xda\xf1\x0f\x9f\x8f\x1d\xcf\xe9\xb9\x50\x3b\x4f\x43\x00\xcf\x71\x04\xb5\xd3\xb0\x2f\x9e\xfb\x81\xf9\xbd\xad\xde\xc0\x51\x6f\x20\xea\xd5\xe8\x8c\x45\xbd\x63\xf3\xb9\x8d\xfe\xd8\x41\x7f\x2c\xe8\x6b\xcf\x8f\x1c\xf4\x8f\x1c\xf4\x8f\x1c\xf4\x8f\x6c\xf4\x9f\xf8\x40\x9d\x46\xcb\x59\x63\x2b\x50\x0f\x43\x92\x78\xf6\x86\x08\x95\xa6\x1c\x52\xcd\xf8\xf6\xeb\xf1\x9f\x7f\xfb\x78\x5c\x7b\xa1\xcd\x6b\x1d\xb1\x5f\x1b\x1e\xc1\xbf\x78\x60\x39\x5f\x8b\x93\xb7\xf5\x80\x3d\x68\x7c\xc0\x36\xe5\xa9\x9c\xc7\x1c\xcf\x3a\x9a\xe7\x8d\x57\x66\x0d\xa7\x1f\xf1\xe3\x8f\x65\x4f\x7c\xb6\xea\x4d\xe5\x54\xe6\x6b\x66\x1a\x7d\xb6\xee\x39\x23\x60\xb6\x38\xa0\x73\x3e\x57\xe5\x29\x4d\xe6\x12\xd9\x36\xd9\x92\x5d\x2d\x29\x1b\x94\xab\x15\xe7\x6a\xb5\x25\x57\xab\xfa\xe3\x3b\xd6\x21\x4d\x08\x2a\x63\xdf\xb8\x4f\xd1\xcb\xe9\x2c\x8e\xe2\x30\x61\x59\x5f\xe2\x34\xd9\xc3\x54\xe7\x79\x7c\x99\xb4\xd7\x1d\x78\x01\x2c\x1a\x60\x05\x7d\x08\x27\x79\x7b\xdd\x31\x83\xb5\xfa\x7d\x0c\x0d\xa3\x82\xf2\xcb\x1a\x10\xed\x8d\x64\x84\xca\x82\xb7\x23\xc8\xe0\x2d\x2f\x68\x94\xcb\x85\x55\x45\x7f\xb1\xb6\xb9\x41\x02\x4f\xc2\x8e\xd7\xfc\x2b\x8f\x4e\xa3\x40\xbb\x8f\x55\xcb\x5b\x08\x7f\xe9\xe5\xf0\xc2\x78\xe3\x3c\x11\x99\xd5\xc9\xfd\xda\x08\xad\x73\xc5\x4c\x5f\x6d\xf8\xd2\x43\xec\x17\xda\xa7\x4f\xed\xcc\xe1\x12\x34\x78\x8d\x42\x22\xc5\x14\x8f\xb8\x13\x3c\x4f\x63\xcc\x1c\x6c\x94\xac\x6e\x8a\xcc\xe0\x04\x50\x68\x24\x1b\x6e\x52\x1a\xbb\xbc\x32\x1f\x57\x7f\xc5\x96\xa6\xe9\xbf\xb6\x95\xbb\x2b\x24\xd0\xb5\x9a\x8d\xbb\x56\xb3\x71\x17\x65\xbb\x6e\x35\xee\x32\x74\x61\xe3\xa9\xcd\x68\x6c\xa3\x1b\x58\xe9\x8e\x39\x5d\xdd\x0e\xdc\xb5\xda\x8c\x6d\x74\xc7\x9c\xae\x6e\xf1\xed\x5a\x6d\xc6\x5d\xab\xcd\xd8\x46\xf7\xc8\xc2\xef\xd3\xce\x3c\xc4\x81\xfd\x83\x26\xe3\xc5\x8c\x5b\x8c\xe9\xd9\xa9\xd9\x76\x55\x3c\x95\x95\x78\xf8\x4f\x6c\x25\x7e\x0a\x33\x31\x93\x59\xff\x3d\xec\xc4\x7c\x36\x4b\x6e\xbc\x71\xe9\x0d\x5d\x3d\x74\xa1\x81\x5b\xcc\xc7\x3a\x0c\x39\x3a\x4e\x3e\xc6\x40\xfc\x3d\x2d\xbe\x2e\xe3\xb3\x66\x05\x5e\xd7\xda\x7d\x21\x44\xd7\xf3\xfa\x69\xf0\x9d\x8d\xac\x4d\x0c\x85\xf0\x4b\x98\xa3\x33\x50\x0a\x4b\xbc\x2c\x45\xab\x1f\x15\x40\x09\x44\x29\xf0\x0c\x8f\x79\x03\x5b\xac\xb5\x1b\xc3\xda\x94\x05\x8f\x33\x99\xd6\x19\x61\x1f\x65\xd5\xdd\x60\x83\xd5\x5f\x0a\xd3\x43\xf8\x07\xac\xa8\x6a\x95\x8a\xc5\xd3\x22\x18\x1d\x60\xdd\x74\x88\x35\x23\xe0\x2c\x4d\x2e\x49\xc6\x6c\x81\x2c\x9f\xe2\xa4\xcc\x15\xc5\x8d\x66\x4e\x73\x58\x08\x3e\x9a\x4a\xe9\x78\x15\xb2\x45\xb0\xb4\x11\x16\x1e\xb7\x20\x9b\xb8\xda\xc9\x6c\x2d\x8c\x6e\x11\x5a\x35\x64\xdb\x1b\xfa\xd0\x87\x6c\x5b\xbb\x58\x66\xb8\xae\x2b\xe0\x87\xd5\x14\xa6\x61\x02\x13\x02\xf1\x65\x92\x66\x7a\xa0\x62\x65\xce\x0d\xf6\x61\x62\x4f\x71\x10\x32\x0b\xf2\xf4\xcc\xf7\x27\xe7\xa5\x59\xb6\xcb\xed\xb8\x5d\x08\x11\x18\x08\x6d\x77\xd6\x40\x73\xf6\xfd\x73\x9b\xbd\xcb\x72\x44\x08\x6d\x2c\xac\xa6\x65\x3a\xd4\xd0\x32\x15\xba\xdd\x35\x79\x94\x9d\x85\x49\x2f\x66\x64\xe9\x72\x23\x4b\xc0\xad\x2b\x5d\x6e\x5d\x09\x74\x4a\xb8\xb0\x44\x28\x5c\x17\x06\xb0\x48\xf3\x3c\x9e\xcc\x88\x4d\x5d\xfc\x03\xc6\x15\x6b\x64\x89\x05\x4d\xaf\x3e\xba\xc4\x95\x97\xec\xec\xfe\x1c\xbe\x4e\xd2\x74\x46\xc2\xe4\x81\xd1\xff\x06\x7f\x13\x10\x14\x29\x4c\xd3\x65\x52\x08\x37\x35\x1f\xfd\xb1\xd5\x88\x8a\x3d\x74\x36\xf1\x98\xeb\x87\x07\x03\xba\x09\x04\x4e\xa5\xa9\xcc\x74\x84\x77\xed\xaa\xe2\x74\xdf\x3c\x00\xc5\xad\x36\xf1\x6d\xda\x5c\x3d\x15\x0e\x67\xbb\x53\x65\x84\xe0\x90\xba\xac\xfd\x94\xf5\x49\x9c\x84\x19\xbf\x45\xd9\x83\xaf\xf7\x1a\xb4\x2e\x2e\xe2\x7b\x39\xd5\x18\xfd\x63\x04\xcf\x9e\xdd\x57\x7f\x0c\xaa\x5f\xed\x72\xd9\x02\xcc\x3b\x78\xe9\x41\x4b\xb0\xd5\xa2\x3a\x74\x5a\x7c\x48\xd3\x99\x07\xf7\x36\xa9\x57\xf1\x41\x6b\xee\xc0\xbd\x15\x50\xd7\x76\xf4\xae\x8f\xce\xd1\xa3\x72\xcc\xd8\x9d\x5b\x19\xb8\xdf\xc4\xbe\xd0\xe3\x67\xec\x4a\xcf\xf6\xb1\x3a\x3c\xf0\xdd\x75\xe9\xb6\x21\x40\xc7\xc6\x43\x99\x8f\xb4\x09\x24\x9e\xab\xde\xdb\x32\x3d\xc2\xad\x08\x2c\xaf\xea\x36\xc3\xd9\x6d\x03\x82\x13\x87\x03\x89\xc0\x3b\xcc\xba\x92\x80\x0b\x5a\x64\xab\xe0\xa1\x27\xf6\x7c\x9f\x87\xab\x78\xbe\x9c\x6b\xc7\xa5\x68\xa1\x87\xb9\xd9\x61\x3d\x51\x3b\x2c\x52\x08\xcc\x20\x17\xc8\x48\xbe\x20\xd3\x22\xbe\x25\x33\xaa\x6a\xca\xe4\xd3\x79\x5c\x14\xca\x76\xa5\x8a\xaf\x68\x71\x0e\x5f\x85\xdc\xfa\xb3\x0a\xe0\x02\x47\xc2\xbb\x36\xa0\x35\xff\xfa\xfe\xdf\x18\x4e\x63\x1e\xdf\xaa\xd9\x0f\xcf\xb2\xb9\x44\xe5\x93\x92\x25\x51\x23\xf2\xda\x4e\x42\xa6\xc6\xb0\x79\xdb\x1d\x23\xfc\x4f\xca\xb2\xb2\x07\x5f\xa3\x85\x2c\x5b\xdc\xc5\xd4\x54\x2c\x75\x05\xd5\x2e\x37\xca\x65\xf3\x46\xe5\x34\x36\xb5\x52\xb2\x34\xc7\x72\xea\xd9\x37\x5a\xb0\xc4\x7c\x36\x49\xee\xb2\xbe\x98\x4b\x22\x5a\x94\xb9\x0f\x1f\x1e\x94\x64\x8e\x94\x7e\xe0\xd1\xa1\xf4\x60\xb0\xeb\x48\x50\x24\x82\x25\x3c\xf8\xf7\x7f\xc7\x6c\xaa\x72\x84\x04\xc3\x29\xe2\xb4\x2d\x3a\xec\x33\x7b\xee\xc8\xc1\xae\x9e\x37\x12\x0e\xb4\x59\xbc\x27\x32\x47\x36\xb2\xbc\xfd\xa3\x96\x30\xaa\x4b\xcc\x92\x76\xc3\xa7\x94\x5c\x41\x7b\x91\xde\x91\x0c\x85\xde\x20\xe8\xf4\xe0\x33\xfd\x5c\x41\x09\x63\xb0\x5f\xef\x68\x3f\x60\xea\x1c\x09\x8c\x0a\xdf\xbc\x55\xb7\x7b\x99\xf8\x4d\xb5\xa8\xca\x55\xe4\x53\x95\xe9\xf3\xfb\x5f\x0e\xff\x7e\x34\x3e\x3d\xfc\xcb\xe1\x27\xbe\x34\xd5\x67\x1b\x17\xd9\xd1\x05\x03\x21\x91\x67\x2b\xf2\x57\xe5\x74\xe2\x1a\x89\x94\x5d\x5a\x20\x9b\xfc\xe7\x7f\x60\xc0\xf2\x0d\x43\x58\x4d\xe5\x83\xb6\x22\x7b\x84\x7f\xab\x73\xa5\xf3\xab\x50\x4d\x9f\x90\x17\xdd\x8d\xb6\xe6\x8c\x12\xda\x72\xbb\x71\xae\x36\x2c\xa9\xac\xb6\x1b\xd7\x32\x63\xb7\x1f\x96\x49\x27\xcf\xed\x1b\xcb\x58\x78\xc6\x48\x78\x30\xf8\x49\xd1\x4c\x3a\xfa\x66\xda\xef\x63\x47\x0e\x48\x77\x38\x60\x42\x5e\xa4\xb1\xba\xe9\xb0\x1e\x67\x39\xfe\x89\x35\xab\xa5\xbe\xb1\x1e\x40\xc2\x2d\xd1\xd0\x1a\x10\xaa\x08\xc9\xe4\x74\x23\xbd\x61\x1d\x48\xd8\xa5\x05\xcb\xb5\xca\xc0\xd8\x28\x73\xe6\xa4\x7b\x78\x80\x1b\x0e\x65\xa1\x3c\x37\xaf\x01\x0e\x30\x65\xde\x0b\x4e\x49\x20\x0d\x0e\x98\x59\xc5\xf8\x7a\x4f\xcd\x93\x55\x67\x1b\xce\xbf\x64\x45\xdb\x4f\x3a\xe6\x35\x1f\xbe\x81\xb1\xeb\x8d\x7f\xe4\x2c\xc3\xde\x1c\x59\xde\x04\x1d\xf3\xda\x93\x51\xc3\x37\xca\xc5\xea\xe3\x24\x50\xfe\x65\x19\x66\x04\xb2\x34\x2d\x36\x85\xba\xcb\x15\x3c\x69\x5c\x2c\xe3\xe1\x13\x65\x01\x4f\x18\x5f\xb2\xfa\xc0\x98\x32\xeb\x20\x64\x1e\x64\x64\xe1\x6d\x67\xa4\x75\x1a\x05\x73\x66\xbd\x35\x5f\x70\x83\xa4\x25\xcb\xd1\x02\x46\x7a\xb3\xbb\xb0\x63\x7e\x78\x15\xce\x2e\x8c\xad\xb4\x15\xf4\x76\x5b\x16\xf3\x94\x88\x37\xe9\x8f\xc3\x71\x5f\xc8\xb8\xbe\x69\xef\x63\x58\x7c\xfc\xf4\xf2\xf0\x40\x4f\x09\xf8\xef\x56\x37\x7f\xf0\x0c\xef\x4c\xca\xfc\x92\x6d\x4e\x86\x53\x39\xc0\x6b\xd1\x3d\x10\x8e\xab\x03\x61\x99\x94\x09\x9b\x27\xf6\xa3\x24\x46\x89\x41\xf2\x22\x9e\x87\x85\x96\xc1\x9c\x76\xf4\xaf\x61\x71\xd5\x63\xb3\xbc\xbb\xb2\x5d\xdd\x96\x1f\xc0\x52\x80\xce\xf4\x53\x6b\x96\xb2\x7e\x1f\x4e\xc2\x3c\x67\xa8\xf5\x55\x31\x84\x78\xe2\x1b\x18\x9a\xed\xb8\x0f\x0d\x87\xbd\x64\x7e\x34\x02\x9a\x11\xf7\x1a\x8b\xed\x27\x2f\xa1\x26\xf1\x37\xde\x7c\x47\x32\x49\x35\xc3\xf0\xd4\x75\x04\xa4\x12\x8f\x9f\xd6\xba\x98\xa0\xee\x39\x0c\x05\xde\x57\xc2\x33\x8b\x9a\x45\xd5\x4e\x4b\x2c\xc4\x15\xab\x68\x99\xeb\xb4\x03\x7d\x04\xc4\xf4\x79\xb2\xb4\x80\xe5\xd9\x7d\xce\xb0\x4e\xec\x1c\x6e\x68\xab\x68\x2f\x17\xf6\xb6\x44\xf2\x75\xb6\x48\x4c\xb0\xdc\x53\x53\xeb\x3a\x9c\xb1\x50\xff\xe4\x86\x5c\xba\xed\x27\x3d\x04\x9a\x3d\xbe\x68\xb7\x48\xab\xc3\xdb\x67\xe7\xc0\x6c\x5a\x66\xac\x40\xbd\x17\x9d\x6c\x9b\x45\x21\x87\x2e\xcf\xe5\x55\x53\x6d\x09\x10\x7a\x61\xf5\x2c\xc0\x5b\xee\x69\xba\x9c\x45\x54\xc3\x11\x66\x78\x81\x98\x14\xe7\x65\x22\xec\x0a\x73\x16\x85\x72\x95\x10\x7b\x8a\x21\xa4\x91\x41\xf6\x94\x7e\x76\x87\x94\xa7\xe1\x32\x27\x10\x96\x97\xf1\x54\xab\xc4\xaa\xda\xab\x7e\xd1\x41\x31\x7d\x45\x92\x29\xa9\x7c\x0e\x26\x64\x96\xde\x79\xdc\x03\x59\x22\xa2\x57\xa2\xcc\x77\xa6\x64\xaa\xe9\x3c\xc5\x7c\xca\xdc\xee\x08\x74\xd2\x66\x3d\xcb\x00\xd2\xf9\x4e\x67\x70\xb4\x70\x2c\x23\x2a\xb2\x5e\x42\x07\x3f\xb4\x01\x8b\xa2\x24\xbd\x2b\xd2\xc4\xff\x14\x2e\xae\xf2\x34\x81\xb8\x20\x99\x23\x2b\xb3\x8a\xff\xa7\xbf\x05\x6e\x25\xcf\xec\xb3\x94\xce\x0e\x2a\xe1\x85\x12\x54\xb0\x98\x88\xf2\x9e\xbf\xf0\xf0\x0c\x34\x60\xd1\x4c\x75\xc8\xaa\x5a\x8e\xf2\xa2\x37\x05\x80\x8e\xb4\x00\x72\x1e\x0d\xd5\xa6\x4b\xc3\x4a\x07\x7f\x34\x3a\x19\xa6\xbc\xd7\xe9\x6c\x4a\xd4\x76\xaa\x09\xca\x8c\x25\x68\x27\x19\xa1\xb3\x35\x4d\x88\x16\xb7\x77\x11\x27\xe1\x4c\xa8\xed\xa2\xa0\x3d\x67\x1e\xaf\x81\xf4\x2e\x19\xa0\xea\x9b\x37\x6f\xde\x40\x9b\xf8\x3b\x1d\xf0\xfd\x77\x0c\x6b\x95\xfe\xfd\xb2\xe3\x41\x9e\x0a\xc9\x9d\xd3\xdf\x4d\x4c\x4b\x33\x83\xba\x54\x05\xd5\x6e\x50\x66\x90\x08\xa6\x69\x96\x91\x69\xa1\xbb\x4c\x1a\xa3\x90\x21\x70\x19\x95\xcc\xbe\x6f\xf1\xf8\x10\x3f\x8a\x70\xca\xc1\x87\x97\x1e\x4a\x85\x41\x2d\x34\x21\xef\xd8\x9d\xe2\x4a\x07\x04\xe6\xb9\x39\xe2\x84\x67\xb2\x42\x3f\x0a\xda\x64\x1e\x14\xb8\xb3\x6d\xbb\xb1\x57\xd3\x0c\x76\xb0\x77\xd1\x4d\x23\x5c\x2c\xb2\x34\x9c\x5e\xe1\x4d\x44\x45\x6f\x42\x7f\x09\xb3\x75\x07\x73\x77\xc4\xc9\x12\x6f\xba\xea\xe8\xd7\xac\x25\xa5\x2f\x13\x4c\x95\x47\x39\x69\xa1\x76\x92\x91\x05\x2a\xfb\xf8\x78\x07\x1f\x37\x41\xdc\x3c\x96\x01\x35\xcb\xba\xd1\xb9\xd9\xe3\x97\x02\x45\x0a\x39\x41\x7f\xa8\xb2\x59\xcb\x05\x47\xb5\xae\x6b\x0c\xaf\x81\xac\xc2\x69\x21\x66\x2f\xbf\x93\x49\xe2\x84\xe4\x38\x2e\x31\x93\x8d\x64\xb6\xa6\x1a\x27\x09\x37\xa4\x2d\x60\x56\x5b\xda\xd6\x26\x70\x91\xdc\xf6\x51\x78\x50\xa0\xc5\xc3\xd0\x28\x87\x9e\xe3\x3a\xd8\x5a\x6f\xc1\xe5\x50\xd1\xe9\x91\x2f\xed\x95\x3b\x11\xa4\xc1\x07\xd5\x99\x9b\x41\x56\x36\x04\x70\x74\xe3\x2d\xc2\x66\xdc\xca\x68\x41\x95\xa1\x9d\xfa\x5a\xf2\x06\xdf\xd0\x71\xa8\x85\x86\x6c\x8c\xa3\x7c\x74\xa1\xaf\x41\x5c\x68\xc9\x72\x36\xf3\x20\xf8\x1a\x78\x3b\xdf\xe8\x82\xdb\xa5\xbf\xbe\xfc\xe6\x49\xd7\x55\x38\xbd\x36\x91\xe7\x6a\x28\xad\x26\x49\x0b\xae\xb6\x56\x29\x91\xb4\x2b\x42\xba\x73\xcf\x2b\xe4\x57\x4c\xa9\xd4\x64\x5a\x76\x31\x97\xf4\xb3\xae\x90\x5d\x83\x0e\x3f\x7e\x5f\x85\xd9\xfb\xa2\x1d\xb0\x74\x97\xbb\x0d\x16\x26\x67\xfb\x94\x9f\xf6\x85\x9d\x89\xad\xd2\xa6\xc0\xc3\xe2\x87\xaf\x02\x7a\xa6\x73\xae\x82\x41\x13\xac\xd9\x39\x8c\xe0\x59\xc6\x17\x41\xc6\x17\xc1\x26\x5c\xd0\xda\xd7\x1b\x66\xfb\x53\xa6\xfa\xdf\xd8\x0b\x03\x0d\xc7\xc9\x83\x79\x53\xe3\x45\x82\xae\x17\xba\x03\x1a\x7d\x6a\x73\x6c\x7b\x61\x75\x6c\x7b\x61\xc5\x25\xb3\xd1\x0d\xac\x74\x03\x4e\x57\x77\x4b\x7b\x61\x75\x6c\x7b\x61\x75\x6c\xb3\xd1\x1d\x5b\xe9\x1e\x71\xba\xba\x0b\x9b\x8d\xee\x91\x95\xee\x91\xa5\x1f\x1e\x67\x6a\x71\x19\x7b\x71\x9e\xfe\x51\xcf\x36\x46\x04\x3d\xb1\x97\xb3\x86\xae\x6d\x53\x0f\x88\x94\xf9\x6c\xee\xc1\x6a\xfa\xd1\x83\xd5\x2c\xf5\x60\x75\x15\x7b\xb0\xa6\x7f\xae\xe9\x9f\x6b\xfa\xe7\xbd\xc5\x66\x82\x69\x91\xd1\x26\xf5\xc1\x9a\x20\xd9\x6d\x86\xd9\xe0\x9c\xd5\xe6\x6e\x73\xaf\x3c\xb7\xab\x1c\x74\x6c\x97\xc6\x95\x67\x9c\xa7\x01\x2d\xfe\xe7\x7f\x04\xf6\x10\x17\xe1\x8f\x55\x65\x34\xd8\x10\x5c\x6b\xb8\x96\x2b\x50\x98\x68\x51\xa5\xfa\x31\x22\x75\xa0\x01\xfe\x8a\x30\xcb\xb4\xec\xdb\xed\xf4\xb0\x62\x6e\xac\xc2\xd3\x7c\x35\x15\x11\x4c\xcc\x3a\xca\x19\x5d\x73\xff\xf3\xf2\xf1\x6a\xea\xf6\x27\xea\x4d\xb9\xbb\xdc\x88\xbb\xea\x39\xb2\xbf\xd6\xc6\x71\x32\x47\x67\xd3\xbf\xd1\xec\x14\xab\x63\x9c\x82\x7b\x59\x03\xef\xaf\xf8\xc7\xb9\x15\x17\xb9\x4d\x0e\xc0\x62\x9d\xa9\x40\xe7\x26\xb0\xb3\xb1\x11\x09\x9b\xc7\x10\x05\x35\x91\x8d\xeb\xba\x3c\x0a\xb6\xad\xc1\x65\xae\xab\x8f\x42\x52\x6d\x3e\x2b\x1d\x12\xa8\x2b\xbd\x5c\x6b\x2f\x35\x9f\x3a\x69\x74\xe5\xe7\xab\xe9\x47\xb7\x13\xd6\x1a\x5f\xd6\xb8\x61\x1d\x26\xf9\x32\x23\x74\x0a\x2f\xd2\x38\x29\xd0\xd9\x4e\x76\xc5\xc2\xc5\x41\xab\x28\x52\xa0\x2a\x8d\xd3\x07\x8b\x7e\xf3\x16\xeb\xeb\xc0\xfd\xd4\x1a\x9f\x79\x3f\xf5\x78\xb4\xe5\x47\x8f\xb3\xcd\x04\x18\xfe\x1a\x9b\xcc\x71\x23\x65\xcc\xdc\xfa\x4a\xd5\x1f\xf9\xba\x8b\x8b\x2b\x1b\xa6\xb7\x8c\xe5\xfd\x11\x1d\xa9\x3e\x7a\x8c\xa1\xb3\xf3\x7d\x88\x7d\x7f\x1f\xee\x95\xac\x64\x4a\x69\x9e\x8e\xdb\x74\xa6\x12\x02\x14\x46\xf0\xf9\x7f\x7d\x3a\xb5\xa1\xa5\x56\x35\xaf\xa7\x1f\xf7\xc1\xf7\x31\x47\x5b\x60\x37\x58\x4c\xed\x73\x6f\x8d\xd1\x3a\x6b\x0c\x81\x7c\x5e\x56\x6a\xf9\xee\x2a\x2e\xbf\xeb\x57\xcc\x3d\x58\xed\x2c\x15\x54\x3f\xf6\x3c\xcb\x2c\xd5\x85\x1b\x16\xd0\x19\xbb\x2d\x2a\x2b\xe4\x06\x9d\xd3\x6e\xea\xf9\xc1\xaf\xaf\x58\xaf\x9f\xdd\x98\x3c\xd9\xbe\xa7\x5a\x20\x6d\xc7\x0b\xac\xa7\x8b\xe5\x5f\xd0\x1e\x70\x90\x67\x5d\x33\x4b\xcb\x02\x6d\x68\xc3\x5c\x62\x0b\xa1\x6c\xa5\x3f\xba\x70\xcf\xa2\x41\xc1\xe2\x3b\x29\x06\xa1\x8d\xc4\x58\xd2\x7b\x76\xcf\x8c\x94\xe7\x5a\x13\xf0\x31\xe7\xf6\xca\x91\xaf\x84\xd6\xc6\xb0\xf0\x29\xc9\xe7\x48\xb2\x91\xdd\x93\xb1\x39\xd2\xd9\xb4\xf8\xb5\x4c\x6d\x43\xd5\xed\xea\x0e\x7a\x2e\xf1\x78\x5f\xc6\x99\x36\xba\x4c\x57\xdc\xeb\xe8\xea\xdd\xd2\xbb\xee\xfb\xfa\xc8\x6c\x93\xfe\x16\x37\x7c\xd5\xb1\x20\xbe\x80\x6c\x8e\x97\xdd\x1b\x9c\x61\xf2\x48\x72\x63\xf9\x6c\xd4\x28\xf9\xb2\x0c\xfe\xa1\x0e\x31\x22\x57\x74\xbb\x03\x95\x07\xa0\x76\xf1\x9d\x47\xda\x4d\xb9\xb5\x90\x71\xbf\x5e\x57\x6c\x5b\x7f\x18\x67\xd1\xe6\x2e\x31\x82\x84\xaa\x36\xb3\x94\xc1\xdb\x79\xc5\xc8\x1f\xa2\xa3\x64\x1e\xc9\x4e\x31\x8a\x9b\x0a\xa5\x3f\x10\x5e\x31\xaf\x3d\x39\xe7\x38\xde\xbb\x61\xa1\x3d\x4a\xc1\x10\x71\xd9\x9c\x65\x4d\x73\x91\x96\x3c\x60\x5e\x37\xf6\x80\xb1\xfa\x1e\xe4\x11\x1c\x48\xae\x39\x65\x9f\xec\x6d\xeb\x0a\x93\xb3\x3b\x82\x8c\x2c\x32\x92\x93\xa4\xb0\xe2\x02\xcb\x40\x67\x89\xd5\xf3\x80\xea\x0b\x32\xfd\x32\xeb\x0e\x2e\x4b\xb5\x61\x45\x0a\xd1\x02\x2e\xe2\x15\x89\xdc\x59\xc2\xfe\xeb\x3b\xa6\x69\xf7\x64\xdb\x7b\x9a\x6d\x20\xb0\xc9\xc3\x4d\x2f\xbe\xfd\x02\xad\x2b\xbf\xcd\x2a\x95\xe8\x34\x72\x60\x13\xa0\x9c\x98\x71\xbe\x6d\x3d\x86\x46\x0b\xd9\x2d\xd8\xe9\xb4\xf6\x06\xd7\x0d\x77\x4c\x1b\xd0\xd9\x8f\x06\x3f\xba\xce\xe8\xbb\xef\xbe\x14\x70\x12\xfb\xa8\x42\x57\x4b\x41\x74\xa4\x5c\x89\x7b\xce\x3f\xfd\xce\x35\x4e\x0b\xb2\x07\x61\xce\x74\xe5\x7f\x09\x6f\xc3\xcf\xd3\x2c\x5e\x14\xad\x5c\xb8\xe7\x16\xeb\x05\xf1\xa0\xed\x07\x9d\x5e\x91\xfe\x42\x99\xa2\x4a\x71\x9c\x43\x2b\x68\x29\xee\x24\x93\x65\xc1\xb2\x55\xb6\x7d\xbc\x0e\x0a\x06\x46\x09\x3f\x68\xfd\x93\x2d\x5b\xc6\xfe\xa3\x16\xac\xa3\xe8\xe6\xa5\x2a\x0a\x6e\xbf\x48\xed\x25\xb7\x59\x9e\x48\xe1\xd1\x0b\xb3\xe1\x52\x1c\x9a\xfe\x5b\x07\xa6\xc7\xa8\xb2\x42\x87\xc1\xff\xd7\x15\x4a\x94\x0d\x8b\xaf\xc2\xb9\xb9\xec\xd8\xd2\x55\x47\x9c\x79\x6f\xb2\x7e\x2a\x74\x77\x2b\xca\xd1\x22\x4b\x17\x24\x2b\x62\xd5\x3f\x94\x3b\xb5\xfc\x72\xfc\xe9\xd7\xf7\xa7\x90\x4e\xae\xc9\xb4\x80\x76\x4e\x88\x14\x5a\x32\x4d\x93\x8b\xf8\xb2\xe3\x9a\xbf\xbc\xec\x48\x1e\xb9\x17\xec\x3f\xce\xe2\x67\xb2\x08\xb3\xb0\x48\x33\xd8\x83\x56\x4f\x5d\xcf\xf8\x73\x99\xa5\xcb\x85\xf2\x95\xe7\xfc\x2a\xbe\x27\xb0\x07\x2f\xcd\xd7\x39\x99\xa6\x78\x33\xf9\x17\xe9\xbb\xc0\xfc\xee\x22\x0b\x71\xd2\xfd\xc5\xa8\xf4\xf7\xd5\xfb\xa0\xe5\x01\x47\x9f\x49\x13\x1f\x8d\xf9\xb4\x0f\xf3\x45\x38\x25\x1b\x28\xf1\x0a\xe5\xaf\xbe\xed\xff\x93\xc9\x21\xb6\xcc\x1e\x27\x88\x1c\x65\x1b\x48\x22\x51\xf2\x11\xa2\xc8\x5e\x74\x2b\x59\x84\x24\x1a\xbb\xb9\xe7\x05\x02\xfa\x3f\x46\x1e\x0d\xb6\x97\x47\xa6\x7f\x00\xbb\xb6\x65\x78\xcb\xb6\x23\x38\x83\x2e\xb5\x5a\x05\xc2\x8c\xb2\x9e\x17\x59\x2f\x5f\xcc\xe2\xa2\xdd\xea\xb5\x3a\xf6\x2f\x2f\x07\x30\x82\x2e\x5b\xd8\xbd\x72\xd9\x39\xbe\x1d\x4a\xdf\x9a\x6b\xd0\x51\x48\x5d\x7b\x23\x50\xea\x12\xcf\xed\x65\xe3\xa4\x38\x09\xd1\xef\x33\xcc\xb2\xb3\xe0\xdc\xfe\x95\x58\x9b\xd2\xa7\x03\xc7\xa7\x02\xa7\xbb\x82\xe1\x76\x56\x5c\x9e\xfe\x58\x99\x03\xc1\x4c\x75\x3d\xba\x27\x1e\xd9\x69\xcc\x08\x3d\x11\x96\x94\xec\xd6\x50\xe0\xe3\x7c\x39\xec\xa0\x15\xef\x72\xe0\xb1\x21\xb9\x1c\x7a\xac\xbf\x63\x0f\x29\xf9\xa6\xb1\x52\x94\xa5\x05\xde\x31\x3f\x4d\xfa\x65\x5d\x08\x31\xad\x82\x7e\xf3\x9c\x96\x79\x78\x80\x4b\xc7\xf5\x77\xd5\xf1\x15\xff\xf9\x72\x92\x17\x19\xfa\x09\xc5\x4e\xb7\x03\xe1\x31\x15\xc3\x5b\x5a\x11\xfd\xa5\x4b\x5b\x55\x6b\xb4\x17\xb5\xd1\x2f\xd5\xd9\xd2\xb5\xd4\x1f\x63\x0f\x39\xae\x6e\x1d\x57\xb6\xac\x9b\x86\xbc\x6f\x1a\xd6\x87\xe3\x1c\x3b\x2a\xa2\x14\x71\x66\x74\xa4\xce\x6a\xf9\x2d\x46\x82\xfe\xdd\xc8\x0a\xc7\x65\x8c\x34\x83\x2d\xb5\x1d\x54\x1c\x8b\xd5\x63\x6c\xb7\xcc\x32\xa9\xac\x50\x73\xcf\xb2\xa7\x3f\x3f\x50\xea\xef\x65\x04\xc5\x39\x4b\x51\xf2\x89\x5c\x1e\xae\x16\x6d\x68\xfd\xfe\x7b\xf4\x95\x36\xee\x72\x08\x5d\x68\x7d\xfb\xfd\xf7\x0f\x2d\x0f\x5a\x97\x2d\x70\xc8\x15\x80\xd6\xff\xfc\xb1\x55\x31\xec\xd8\x8a\xed\x1c\xed\xa9\x6b\xda\xf6\xd1\x9e\xbd\x9b\xed\x46\xc5\xbc\xc8\x1e\xa5\xeb\x31\xab\x7f\x63\x8d\x2f\xcc\x69\xd1\x78\xbe\x98\x91\xb2\x01\x78\x0e\x92\xeb\xa8\xf6\x39\x7a\x20\x22\xac\x1b\x10\xcc\xaf\x7a\x11\x91\x24\x9d\xc7\x09\x7d\xc5\x50\xb9\xa4\x07\xa5\x6b\x47\x08\x8b\x34\x8f\x8b\xf8\x56\xcd\x61\xc3\x21\x1c\x38\x93\x6e\x5c\xf8\x7c\x41\xa6\xf1\x45\x4c\xa2\xd2\xd2\xa9\xd4\x7a\x74\x51\xd9\x40\x65\xfa\x32\x27\x31\x53\x17\x4a\x4a\x2c\x42\xc7\xc6\x2b\x0b\xb6\xbf\x23\x79\xc1\xf9\x4a\xc8\x94\xe4\x79\x98\xad\xa1\x48\x15\xd3\x8d\xe8\x6b\x39\xa0\x13\xbd\x64\x14\xff\x3c\x55\xc3\x9a\x57\xc6\xd2\x07\x36\x72\x0f\xe5\xa0\x94\xf1\x4a\x18\xd4\x89\x1d\xfd\xb6\xba\x6b\xc5\xce\xb5\xb5\xbf\x46\x71\xe2\x03\xdb\xee\xd0\x82\x4a\x6b\x0d\x35\x66\x6e\x9a\x34\x6b\x8a\x6b\xaa\x8c\x56\x58\x53\x65\xc4\xf4\x92\x95\x99\x79\x64\x53\x63\xc2\x2c\xf3\x20\x0a\x3c\x88\x86\x78\xb5\x4f\x56\x0b\x0c\x93\x48\x02\xcf\x01\xbb\x76\x03\x23\x1e\x7c\xf5\x34\x57\xf7\x91\x61\x19\x3d\x1e\x1f\x5a\xe4\x46\x42\x37\xbe\x28\x68\xf8\x75\x44\xbf\x4e\xec\x5f\xdb\x34\xa9\x79\x54\xaa\x6e\xb6\xcd\x88\x47\x9b\x8d\x58\xb0\x99\x29\xbc\x4d\xf3\xee\x3c\xb2\xec\x0d\x25\x99\x1b\xd7\x6e\xfd\x8c\x5d\x8b\x25\x2c\xd9\x4b\xbb\x03\x1d\x84\xa7\xea\xcd\x0a\x64\xbd\x1e\x74\x57\xc4\x9a\xbb\x37\x53\x1e\x85\x3e\x1c\xba\x7d\x6c\x01\x5a\xfa\xdc\x6b\xe1\x06\x72\x03\x07\xd0\x92\xa7\x61\x8b\x9e\x95\xd4\x69\x4d\x25\x3e\xed\xcb\xed\x36\xe0\x7e\x5f\x0f\xe7\xdb\x73\x7d\x77\x74\x41\xc9\x2b\xb9\x81\xd2\xc4\x8f\xa5\x55\xcc\xad\xd7\xc0\xd2\xac\x4b\x72\x93\xae\xee\x65\x4e\xc0\xe5\x58\x36\xa7\x33\xf1\xd9\x0d\x77\x6c\xa3\xff\x55\x56\xec\x44\x84\x95\x0e\xa0\xd3\xbb\x2c\x08\x1b\x8c\x03\x48\xb8\x9a\xbe\x25\x22\x78\xe9\xb4\x50\x81\xc1\xf7\x0a\xe1\x7a\xad\x5f\x0a\x18\x51\x22\xab\x69\x2d\x0a\x78\xcc\x03\x69\xec\x12\x8b\x7d\xcd\xbb\x10\x83\x42\x59\x4c\x68\xe9\x73\x32\x8f\x13\x14\x78\xfa\x24\x28\xae\xc2\x4a\x9a\xcb\x57\x65\xa6\x00\xe6\x4e\x06\x11\xfa\x33\xe4\x15\xcc\xc0\xaa\x47\x4c\xb0\x81\x88\xa7\x89\x81\x93\xe3\xbf\x7d\xfe\xfb\xe9\xe1\xf8\x0c\xda\x54\x0c\xa1\x2f\xff\x73\xd9\x33\x81\x45\xe5\x49\xa0\x04\xf4\xab\x3d\xfc\x57\xf3\xaa\x60\x43\x39\x8f\xd8\xda\x99\xce\x17\xed\x08\x33\x80\x21\xe0\x3c\xe1\xbf\x45\x74\xec\x06\xe2\x66\x42\xe5\x1e\xab\xe7\xa0\x1f\x2a\x69\x81\x04\xc2\x83\x5d\x4c\xe0\x04\x55\x0c\x18\x81\xcf\xfd\x3e\x13\x4b\x28\xa0\x54\xb0\x91\x24\x10\x5d\xa1\xdf\x99\xcb\xa1\x06\x75\x00\x81\x89\x07\x91\x99\x5f\xb0\xec\xe9\x21\x4a\x50\x1e\x69\x20\x90\x00\xa3\x81\x15\x6f\x87\x05\x68\x0f\xb1\xf3\xe8\xd6\x81\xd1\x3d\xce\x2c\xec\x11\x6b\x92\xe5\x05\x4a\xed\xa1\x45\x62\x32\x01\xad\x31\xc3\x78\xc4\x51\xb1\xf0\xc4\x3a\xce\x42\x0c\xf7\x10\x1d\xe2\x90\xb7\xd7\x41\xca\x42\x49\x5b\xa4\xac\x38\xed\xd6\x79\xc4\x69\x47\x41\xc7\x83\x68\x60\xef\x62\xb6\xdb\x88\x16\x45\x43\xce\x46\x62\xf6\x2f\xeb\x2d\xe3\x4b\xcb\x48\x24\x01\x73\xbd\x1a\xf4\x72\xb0\x78\xda\x10\x78\x31\x82\xe1\xe6\x94\x00\xa5\xbe\x19\xe7\x30\x9d\xa5\x39\xc3\x7c\x59\xd1\x6d\xbe\x1f\x61\x62\xa8\x64\xd0\x8f\x06\x0a\x19\x66\x25\x60\xd3\x6a\xc0\x5a\x4d\x8c\x7c\xa0\xbc\x5f\x56\x9d\x5e\x38\xc9\xdb\x1d\x9c\x2d\x16\xe1\xca\xa8\x04\x4c\xd3\xd8\x48\x05\x97\xfa\xc0\x71\x1a\x39\xa3\x9d\x51\xc9\x4a\xca\x98\xf4\x27\x9c\x3b\x8e\x0c\x67\xb4\x2b\x95\x62\x81\x52\x4c\xeb\xc3\x6a\x95\x93\xd5\xc2\x7a\xcd\x19\x66\x5b\x9d\x1a\xea\x4e\x06\xd3\x34\xb9\x25\x59\x21\x7c\x0b\xb8\x5e\xbb\xc8\xe2\x39\x2a\xf0\x4e\xff\xcd\x94\x97\x6f\x82\x87\x69\x01\xca\xad\x7c\xad\xf0\x48\x70\x15\xe6\x22\xda\x05\xbd\x18\xac\xe0\xd1\xdd\x15\x15\xa9\x2c\x57\xfc\x01\xfe\xfb\x02\xc3\xa4\x79\x72\x92\xe6\xfd\x11\x3e\xd2\x09\x83\xea\x2f\x25\x38\x01\xdb\xbe\x12\xc5\x16\x7a\x74\x01\x89\x9c\xbc\x8d\x6b\x03\x8f\x8e\x3a\xa6\x04\x4f\x8e\xff\xf6\xf7\x93\x4f\x87\x3f\x1f\x7d\x3e\x3a\x1e\x8b\x83\x4d\x20\x14\x8d\x22\xd5\x3e\xb0\xdc\x2c\xbb\x8e\x0c\x89\x0d\x39\xe1\x4d\x10\xbc\x1a\xbc\x79\x33\xdc\xdd\x79\xb5\x13\xbc\x79\x33\xa4\x35\x18\xcf\xec\x96\xe0\xf6\x09\xc9\x2e\xd2\x6c\x9e\xc3\xee\x0e\xcc\xd2\x74\x51\x05\xbe\xe4\xb8\x8b\x60\xbe\x52\x9d\x58\xaf\xe3\x3a\xd1\x2c\xd2\xbb\x76\xa7\x8a\xe8\x32\xce\x30\x89\x76\x84\xd1\xbe\xd7\x0e\x2d\x49\xcd\x99\xe5\x04\xc7\x72\x04\x27\xbd\x45\x7a\xa7\x4c\xe9\xc4\x36\xa7\x6f\x3c\xb0\x24\x63\x8a\x61\x04\xf3\xb0\xb8\x62\x60\xc1\x3c\x3d\xf7\x01\xf8\x54\x4d\xeb\x26\x36\x6b\x84\x7b\x6d\x60\x7c\xb0\xe4\x95\x2a\x02\x85\x29\x7b\xf1\x45\xd5\x46\x0d\x9c\xc2\x86\x03\x2d\x5b\x82\x93\x86\x70\x0c\xc3\x97\x1e\xb4\x44\x25\x2d\xe8\xc0\x8f\x3f\x6a\xcc\x23\x61\x96\xe0\x92\xf6\xd1\xc3\x03\xc4\x36\xa4\x03\x0c\xd0\x4e\xa0\xcf\x82\x85\x2d\x58\x28\x8b\x30\xcb\xc9\x2f\xb3\x34\x2c\x28\x19\x7a\x0a\x42\xdf\xe0\x36\xf3\xae\xa7\x0b\xdb\x85\xbf\x62\x0d\x0e\x17\x9d\xd4\x86\x2e\xdd\x60\xcc\xed\xd7\x8c\x77\xe5\xc1\x20\x74\xd5\x90\x70\x7a\xc5\xd4\xdd\x78\x1a\x63\xd6\x02\xb4\xb2\xa0\x60\xe4\x7a\x64\x7a\x01\x37\x3c\xba\x15\xbf\x16\x30\xc2\x53\x76\x83\x46\xbe\x2c\xc3\x82\xe4\x7a\x1d\x54\x64\x54\xd5\x58\xdc\xb4\x8c\x65\xdc\x85\xb3\xe1\x6b\x0f\x76\x06\xe7\x1e\xc3\x2b\x66\x51\x35\xa5\x85\x45\xaf\x41\x28\xce\xe9\x05\x0c\x5f\xc3\xe5\x32\xcc\x22\x41\x3b\x23\x45\x18\x27\x24\xea\x41\xfb\x37\x14\x0e\x5d\x18\xf4\x76\x79\x9c\xec\x25\x95\x52\x67\x6f\x3c\x18\x0e\xce\x95\x62\x3d\xd5\xb4\x75\xc3\x74\x64\x89\xc3\x03\x9c\xec\x53\x12\xcf\xda\xda\x9b\xbe\xac\x26\x0f\x51\xc7\xdd\x98\x72\xcc\x72\x34\x56\x43\x5c\xed\x3a\x62\xcc\xe2\xc2\x5d\x1e\xe0\xe8\x70\xcd\xf4\x1b\x57\x44\x4d\x05\x47\xee\xd4\x2f\xcb\xcf\xf0\x78\xb6\xae\x12\x96\xbe\x83\x1b\xe8\xc8\x0f\xf0\x6c\xad\x17\xb5\x9c\x3b\x35\x51\x11\xb3\x90\x77\x87\x1e\xfc\x2c\xae\x58\xb3\x8a\x90\x55\x4d\x13\x2b\xbe\x39\xd4\xfa\x4a\x67\x7f\x55\xc3\xbe\xed\xe4\x98\x70\x64\x49\xda\xb9\xc7\xe3\xc3\x1e\x55\xaf\x74\x94\x5c\xbe\x38\x6f\x2a\x67\xac\xb5\xa7\x4e\x12\x43\x0d\x83\x3d\xd9\x73\xfc\x7b\xdc\x7a\x4b\x3e\x94\x56\x5f\x49\xb9\x12\xbb\xf3\x89\x71\x09\x8e\xc6\xc8\x3c\x32\x53\x82\xea\x78\x6f\xca\xb6\x2b\x19\x18\x35\xab\xa2\x9e\x92\xbe\x6a\x8e\xe3\xca\x9e\x87\xdc\x29\xb1\xee\x2f\x36\x61\xe0\xfc\xb3\xf8\x73\x9e\x48\x60\x8a\xdb\x79\x67\xda\x4b\x6e\x76\x06\x95\xcb\x6d\x7f\x0f\xec\x2e\xbd\xcd\x55\xf0\x89\x04\x5f\xb9\xd9\xbd\xd3\xea\x9a\x92\x47\xae\xab\x60\xd9\x89\x73\xb8\xa3\x39\x71\x6a\xc2\xe3\x80\xfb\x72\xaa\x97\xc1\x3b\xff\x00\xe7\x14\x74\x3e\x9f\xa0\xab\x17\xfe\x3a\xc0\x40\x98\x09\xc4\xaa\xd7\x08\x77\xf7\x62\x17\x02\xf8\x61\x9c\xcb\x26\x7f\x9c\x63\x2c\x5c\x9c\x51\xf1\x9a\xe9\xe3\x4a\x33\x8c\xe5\x5e\x55\xa5\xdd\x30\x30\x1b\x96\xd2\x96\xab\x30\x97\x2e\x43\xca\x75\x29\x57\x80\x96\xad\x38\xaf\x6e\x40\xd2\x4c\x4d\xec\x7e\x7a\x4c\x0f\x83\x7f\x3f\x39\xfe\x8c\x1d\x12\x56\x87\x8b\x52\x0b\x94\xcb\x96\x72\x48\xae\x84\xd3\x18\x1f\xfe\xc5\x13\x33\x66\x2b\x19\x31\x39\xb7\x1c\x15\xf0\x68\xf0\xd3\x4e\xa3\xa5\x5c\x9e\x75\xb1\xef\x8c\xc5\x34\x31\xd6\x92\x5a\x40\x5b\x3f\x93\x9a\xe5\xc3\xc1\x3d\xe4\xb5\x33\x71\xb8\x50\x58\xcc\xfc\xce\x2b\x84\x9c\x61\x27\xd8\xb1\x96\x92\x1e\xb1\x45\xeb\x28\x79\x5b\x2c\x81\x7c\x04\x91\x31\x4a\xb3\xbf\x75\xef\xce\x5d\xba\x0d\xbb\x9e\x6d\x89\x5a\x2c\x00\x3c\x20\x03\x8f\xd0\x1d\x9b\x17\xc1\x9b\x60\xe5\xde\x51\xfc\xd4\xc6\x91\xf1\xd2\xe3\x70\x6c\xa9\x4b\x33\x38\xbb\xe8\x30\x1a\x1a\xd8\x47\x42\x75\x2f\xd7\x95\xc4\xc4\xe9\x34\x3e\xf1\x60\xe8\xc1\x4f\x3b\x1e\x0c\x77\x3d\x68\xd1\x79\xd2\x72\x9c\x15\xaa\xaa\x09\xbc\x1d\x49\xab\x81\x41\x0b\xbd\x1b\x49\x8b\xcc\x5a\x98\x0a\x43\xd5\x2f\x18\xe7\x0f\xb8\xee\xad\x01\xf6\x80\x3b\x18\x22\xb0\x77\xf5\xf9\xa3\x3a\x9d\xdb\x68\x3e\x84\x39\x69\x3b\xe8\x7a\x30\xa1\xb2\xda\x43\x29\x97\xdb\xb3\x84\xda\x7b\xb8\x44\xd2\x4a\x04\xe8\x4d\xed\x3c\x79\xa2\x6b\xec\xc7\x47\x1f\xf3\xd8\x7d\x6e\xaf\xba\xbb\x4a\x67\xea\x2d\xb3\x81\x44\xad\xc8\x87\xb2\xf4\x48\xfc\xd5\x24\xb9\xbc\xb8\x8b\x31\x63\x28\x3c\x05\xf7\x73\x60\x6c\x8e\x1b\xfa\x81\x9e\xfc\xd8\x3a\xf0\xd0\xa9\x38\x4a\x99\x70\x9c\x4e\xc9\xa2\x10\x5b\x8d\xc0\x45\x74\x35\x0a\xbb\xea\xf8\x82\x35\x29\xfd\x97\xcf\xc7\xe3\xc6\xf9\xfe\x6d\xf7\x3e\xea\xf0\xf5\xe1\xfd\x2c\x0e\x73\xc2\x2c\x38\x1f\xe2\x4b\xe1\x27\x38\x27\xc5\x55\x1a\x49\xb1\x09\xfd\xbe\xc8\x53\xc2\x12\x97\xec\x83\x44\x84\xbd\x62\x3b\x32\x89\x20\x9c\xa4\x92\x73\x00\x2d\x59\xe6\x7f\x1c\x89\x54\xd9\xfb\xa2\x64\xbe\x9c\xd4\x95\xe4\x47\xf0\x35\x6b\x3f\x3d\x09\x95\x25\xe7\xcb\x59\x5d\xc9\x28\xbe\x8d\x23\x82\xe5\xa2\xf8\x76\x5f\x79\x97\x91\x79\x18\x27\x11\x37\x0b\xcd\xd3\x48\x7d\xcd\x53\xc1\xf3\xfc\xf2\xd3\xf9\x42\x7d\xcd\xb2\x06\x89\xa4\x41\x72\x87\x72\xd8\xa4\xe4\x22\xbe\x3c\x9e\x5c\x4b\xf7\xbe\xba\xab\x6b\xbb\xfc\x48\x16\x8e\x7c\xf0\xca\x8f\x59\xb5\xdf\x78\x05\xb4\xd1\x9f\x8e\xfe\xf5\xfd\xe9\x21\xfc\xf5\xf0\xe3\xc9\xe1\x27\xf8\xe5\xb7\xf1\xcf\xa7\x47\xc7\xe3\xcf\xfc\x8b\x72\x5a\x94\x71\xb6\x8a\x85\x0b\x1d\xf7\xe8\x8e\xa6\x46\xd8\x08\x63\x0b\x5e\x5e\x3d\x3c\x20\x1a\xce\x08\x62\x38\x80\x18\xf6\x20\xae\xee\xd5\x24\x46\xca\xa5\x6e\x1a\x54\x98\x37\x0a\xdb\xa8\xd3\x8b\x52\xc7\xe3\x07\x0e\x95\x4f\x75\xb3\x08\x75\x66\x73\x0f\xee\xd5\x4d\x99\xb2\x3f\x50\x1f\x5d\xc3\x08\x42\x7e\xc8\x55\xdf\xd0\xd1\x0d\xa9\xd4\xeb\x42\xab\x25\x75\xb3\xec\x2c\x76\x6d\x46\x84\xe6\x58\x0c\xd3\x8b\xb2\x82\xf2\xcb\x7b\x18\x55\x06\x10\x1f\x72\x6b\x24\xb2\xa8\xe0\xde\xf7\xf7\x91\x5c\x2b\x40\x71\xab\x4b\xee\x0c\xba\x4a\xae\xae\x6f\xca\xd2\xac\xae\x5a\x54\x54\xf3\x9e\xd6\x90\x6b\x04\x2d\xe3\x7c\x40\x86\xc8\x29\x3f\xa7\x11\x79\x5f\xb4\x7d\xff\x9a\x21\x74\xed\xbc\xde\x97\x2b\x17\x92\x4f\xc2\xe0\xba\x46\xd7\xd0\x87\x87\x4a\xcc\x49\xc3\xfd\x33\x5b\x10\xaa\xec\x2e\xa7\x69\xae\x66\x85\x94\x46\x17\x4b\xb1\xec\x62\xa0\x0f\x6e\xe8\xc1\x44\x1d\x2f\xbb\x27\x87\xc8\x8e\x63\x4e\x04\x03\x1e\xf3\x9a\x21\x0a\x78\x86\x71\xcb\xc0\xcb\x9c\xb1\x68\xfd\x7d\xa5\xc3\x6d\x59\x8c\x84\x91\x86\x2a\x28\xd7\x3a\xee\x7d\xf9\x15\x4b\x0d\x52\x21\x23\x54\x3d\xcd\x32\x83\x54\xe0\x08\xd6\x1a\x55\x34\x4d\x9e\xe6\xe3\xe1\x01\xa4\x94\x49\x21\x1c\xc0\x84\x23\xc7\xfa\xd7\x74\x5d\xaa\x94\xec\xe9\x92\xb8\x19\xed\xd9\x08\x24\xde\x63\x8d\x71\xba\x0c\x02\x95\xe3\x1b\xaa\x98\xcd\xac\xbc\x9a\xe9\xe8\x9d\x79\x84\x04\xbf\xf4\xdd\xff\xc5\x16\x0c\x28\xf7\x03\x95\xae\x98\x5b\x96\xb4\xd8\x8c\xb2\xd4\x0b\x37\xf0\x0e\x66\x2e\x5a\x2c\x41\xf5\x8d\x25\x2f\xf5\x4c\x4b\x85\x7c\x00\x37\xb0\xa7\xb7\x4f\xf0\xe1\xca\x83\x5d\x85\xbc\x07\xa5\xe8\x88\x31\x59\xb5\x48\x07\x1c\x8b\xac\xd4\xf1\xb9\x9c\x8b\x9f\xfe\xf9\x8e\x3f\xde\xdc\x0d\x8c\x49\xa9\x13\xca\xa6\xd3\x21\xe1\x3d\x6a\xeb\x07\x90\x97\x2c\xd7\x47\xaa\x4b\xc2\x6c\x49\x18\xd8\x36\x7a\x67\xdc\x52\x45\x5b\xd8\xb1\xe2\x84\x9d\xbd\xbc\x0a\xae\x9a\xb9\xca\xf4\x04\x91\xdf\xe8\x13\x7a\x3c\x15\x90\xd3\x58\x9e\x19\xc5\x31\x4b\xae\xe6\x63\x53\x16\x64\x51\x59\x78\x0d\x40\xd5\xfa\xd6\x80\x74\x07\x2d\x7e\xe3\x4f\x35\x22\xe9\x82\x40\x7e\x27\x90\x30\xb8\x22\x54\x0a\x94\x38\x29\xfe\x95\xd5\x9c\x66\xe3\xf4\x30\xcb\xd2\x2c\xc7\x7b\x8f\x79\x4c\xff\x09\x57\x8a\x90\xe1\x1d\xc7\x6e\x1b\x4a\x0c\xe8\x84\x9e\x22\xde\x8d\x68\x11\x06\xfd\xf6\x76\x44\x4b\xaa\xfd\x57\xd5\x98\xbf\xa7\x9b\x5a\x3b\x9d\x5c\x5b\x48\x1f\x63\x30\x4b\x6f\x91\xa5\x45\x5a\xac\x17\xa4\xd4\xb8\x7a\xd3\x70\x36\x63\x85\x46\x23\x68\x9d\xf1\xa8\x17\xa4\x75\xde\x72\x8d\xd5\xcf\xec\x24\xa0\x6d\x9e\x47\x09\xf7\x36\x2a\x53\x87\x27\x5c\xea\xf2\x0f\x8e\x97\x45\xd9\xe1\x87\x97\x3d\xe5\x40\xd1\x1a\xee\xee\xb6\xd8\xb9\x61\xf0\x93\x98\x93\x39\x9c\x0d\x76\x3d\x18\xec\x9e\xbb\xcb\x5d\x5c\xb4\x18\x70\xf7\x20\x90\x8a\x0d\x3d\xd8\xf5\xa0\x2a\xa7\x8d\x4f\x91\x7e\x60\xfc\xf0\xa3\x0b\x63\xdf\x13\x5c\x1a\x5b\xc0\xb5\x2a\x94\x99\x5f\x80\xe1\x6f\x1f\x66\xd9\x47\x53\xf8\x6b\x1e\xf4\xcc\xeb\x3d\x2f\x32\xd3\xdf\xdd\xf0\x0d\xd7\x37\x7c\x9e\xbb\x28\xcb\x3e\x32\x37\xfe\x72\x2f\xa5\x8f\xe8\x16\x1e\x66\xd9\x19\xfd\xfd\x1c\x5e\x8c\xc4\x98\x68\x5b\x39\xfd\x04\x25\x50\x00\x98\x92\xfb\xfd\xc7\x93\xbf\xbe\xff\x70\x78\x5a\x42\xc4\x22\x6f\x1c\xd4\x8c\xcb\x0d\xd7\x9d\xc8\x35\xbc\x55\xd8\xb8\x76\xa5\xc4\x67\x3b\x45\x96\x9d\x5d\x53\x09\x23\x7a\xd9\x07\xb7\xdb\x7b\x55\x82\x6e\xf7\xe7\x50\x99\x28\xe4\x87\x2e\x14\x0b\xe9\x9b\xee\x48\x54\xdc\x2f\x2b\x76\xa2\x5f\xf0\x2f\x9f\x8f\xc4\xa7\x9b\x9d\xda\xaa\xdf\xf4\x45\x47\x7b\x46\x4b\xd8\x65\x2c\x5b\xc7\x71\xde\x26\x1c\xaa\x29\x03\xef\x60\x00\x07\xf2\x38\x05\x1d\xaa\x01\xf6\xf8\x51\x59\x8e\xc0\xa0\xa7\xe8\x0e\x74\x25\xa6\x05\x9e\xf1\x01\xb4\x98\xfb\x22\xe9\xb6\x64\x38\x60\x0b\x8f\xb6\xa3\xbe\xb6\x42\x66\x24\xf1\xe0\x5e\xdd\x29\xc6\xba\x89\x50\xdb\x8a\x09\xb7\x08\x7d\xad\x4f\x35\x67\x83\x92\xb9\x47\x5d\xb5\xd7\xda\x47\x9c\x0d\xb8\xe7\xf8\xcf\xfa\x64\x67\x36\x84\x7b\x61\x41\x90\x99\x3b\x71\x9a\x43\xad\xa6\x90\x9a\x65\xcb\x09\xbe\x5f\xb8\x58\xc6\xc6\x76\xbb\x84\xee\x85\x24\xb1\x4e\x79\xb9\x55\x2d\xda\xbf\xfe\x88\x89\x00\xdf\xaf\x69\x9e\x68\x62\x77\x44\xbb\x5e\x7e\x2a\x67\x39\x26\x4c\x9c\x58\xeb\x65\x1d\x54\xcd\x19\xaa\x60\x33\x94\x16\x7d\x36\xe9\xe9\x02\xeb\x66\x7e\x69\x87\x31\xe7\x92\xb4\xbb\x55\xdc\xd0\xae\x55\xae\xe0\x2d\x67\x3e\x36\x65\xcb\xcb\xde\x84\x4e\xee\xea\xf2\x32\x31\x8f\x02\x87\xff\x76\x72\xfc\xe9\x94\xff\x5d\x59\x6e\x46\x10\x26\xa8\x3e\x94\x29\x0e\xe9\xd8\xfd\xfa\x67\x36\x64\x2c\xa4\x6c\xbd\x20\xe9\x05\x44\xe4\x82\x9e\x69\xe8\xbe\x28\xf8\x6f\xd1\x9d\x98\x3d\xef\x85\xf3\x48\xe9\x52\xf6\xb8\xad\x9a\x3c\xcc\x93\x32\x7c\x03\xa9\xe2\x71\x1a\xb1\x5c\x1e\x0c\xe6\x8c\x24\xb7\x71\x96\x26\x54\x75\xc9\xb9\xb7\xe9\x72\xb1\x48\xb3\x82\xa5\x2a\x27\x3d\x3a\x59\x33\xa1\x79\xca\x83\xcc\x79\x66\x9f\x51\xed\xae\xb5\x4c\x18\x47\x11\x32\xad\x96\x57\x18\xd7\x5e\x8d\xf4\x63\x3d\x54\xf9\xb4\xb2\xf5\xa2\x48\xa1\x03\x45\xb6\x86\xaf\xc0\xff\x1c\x41\x46\xbe\x2c\xe3\x8c\xb4\x5b\xec\x49\xab\x43\x5b\x39\x0d\x8b\xe9\x15\xb4\x49\x07\xbe\x7e\x2b\xdb\xfb\x21\x4b\xef\x72\x61\x18\x33\x16\xda\xe5\x2c\x9d\x84\xb3\x9e\x3c\x58\x86\x89\xe1\x5b\xa7\x4c\xa6\xf3\xcd\xfb\xfa\x27\x56\xe3\x9f\xf6\x76\x83\x6f\xe7\xde\x9f\xee\xc8\xe4\xe5\x9f\xf6\xce\xc4\x10\xb4\x39\x63\x1e\x6b\xa2\xc7\x9b\xd8\xf9\xfa\x03\x15\x59\x7f\x23\x93\x97\x32\xf3\xbd\xfe\x2c\x9e\xf4\x29\x09\x4c\x2f\xd0\xef\x43\x94\x26\x05\xa4\xb7\x24\xcb\xe2\x88\x70\xee\xa8\xb4\x8b\xc3\xc9\x8c\xfc\x40\xfb\x84\x77\xfb\x5d\x9c\x44\xe9\x1d\xe6\x14\xd0\xfa\x5d\xf9\xa0\xc7\xaa\x54\xbf\x12\x43\xa1\x7c\x82\xcc\xed\xff\xf0\xed\x87\x1f\x8c\xd1\x61\x6f\xb0\xf1\x15\xc7\x7f\xda\x1b\x0e\xbf\x9d\x7f\xf3\xbe\x7e\xf3\xce\x58\x2f\x9c\x77\x7e\xe8\xf7\xff\x07\xe4\xe9\x32\x9b\x92\x5f\xc3\xc5\x22\x4e\x2e\x7f\xfb\xf4\x71\x44\x5f\xf6\xae\xf3\xde\x3c\x5c\xfc\xf0\xff\x02\x00\x00\xff\xff\xd2\x48\xd8\x13\xdc\x80\x07\x00") + +func web3JsBytes() ([]byte, error) { + return bindataRead( + _web3Js, + "web3.js", + ) +} + +func web3Js() (*asset, error) { + bytes, err := web3JsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "web3.js", size: 491740, mode: os.FileMode(420), modTime: time.Unix(1484232456, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "bignumber.js": bignumberJs, + "web3.js": web3Js, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{nil, map[string]*bintree{ + "bignumber.js": &bintree{bignumberJs, map[string]*bintree{}}, + "web3.js": &bintree{web3Js, map[string]*bintree{}}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} diff --git a/pow/dagger/dagger_test.go b/internal/jsre/deps/deps.go similarity index 62% rename from pow/dagger/dagger_test.go rename to internal/jsre/deps/deps.go index 449419957b..8d0e1a4000 100644 --- a/pow/dagger/dagger_test.go +++ b/internal/jsre/deps/deps.go @@ -1,4 +1,4 @@ -// Copyright 2014 The go-ethereum Authors +// Copyright 2017 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 @@ -14,22 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package dagger +// Package deps contains the console JavaScript dependencies Go embedded. +package deps -import ( - "math/big" - "testing" - - "github.com/ubiq/go-ubiq/common" -) - -func BenchmarkDaggerSearch(b *testing.B) { - hash := big.NewInt(0) - diff := common.BigPow(2, 36) - o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity - - // Reset timer so the big generation isn't included in the benchmark - b.ResetTimer() - // Validate - DaggerVerify(hash, diff, o) -} +//go:generate go-bindata -o bindata.go bignumber.js web3.js diff --git a/internal/jsre/ethereum_js.go b/internal/jsre/deps/web3.js similarity index 96% rename from internal/jsre/ethereum_js.go rename to internal/jsre/deps/web3.js index 9970776b99..ce76500891 100644 --- a/internal/jsre/ethereum_js.go +++ b/internal/jsre/deps/web3.js @@ -1,22 +1,3 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package jsre - -const Web3_JS = ` require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o. */ -/** +/** * @file param.js * @author Marek Kotewicz * @date 2015 @@ -1251,7 +1211,7 @@ var SolidityParam = function (value, offset) { /** * This method should be used to get length of params's dynamic part - * + * * @method dynamicPartLength * @returns {Number} length of dynamic part (in bytes) */ @@ -1279,7 +1239,7 @@ SolidityParam.prototype.withOffset = function (offset) { * @param {SolidityParam} result of combination */ SolidityParam.prototype.combine = function (param) { - return new SolidityParam(this.value + param.value); + return new SolidityParam(this.value + param.value); }; /** @@ -1311,8 +1271,8 @@ SolidityParam.prototype.offsetAsBytes = function () { */ SolidityParam.prototype.staticPart = function () { if (!this.isDynamic()) { - return this.value; - } + return this.value; + } return this.offsetAsBytes(); }; @@ -1344,7 +1304,7 @@ SolidityParam.prototype.encode = function () { * @returns {String} */ SolidityParam.encodeList = function (params) { - + // updating offsets var totalOffset = params.length * 32; var offsetParams = params.map(function (param) { @@ -1401,10 +1361,6 @@ SolidityTypeReal.prototype.isType = function (name) { return !!name.match(/real([0-9]*)?(\[([0-9]*)\])?/); }; -SolidityTypeReal.prototype.staticPartLength = function (name) { - return 32 * this.staticArrayLength(name); -}; - module.exports = SolidityTypeReal; },{"./formatters":9,"./type":14}],13:[function(require,module,exports){ @@ -1423,17 +1379,12 @@ SolidityTypeString.prototype.isType = function (name) { return !!name.match(/^string(\[([0-9]*)\])*$/); }; -SolidityTypeString.prototype.staticPartLength = function (name) { - return 32 * this.staticArrayLength(name); -}; - SolidityTypeString.prototype.isDynamicType = function () { return true; }; module.exports = SolidityTypeString; - },{"./formatters":9,"./type":14}],14:[function(require,module,exports){ var f = require('./formatters'); var SolidityParam = require('./param'); @@ -1465,7 +1416,16 @@ SolidityType.prototype.isType = function (name) { * @return {Number} length of static part in bytes */ SolidityType.prototype.staticPartLength = function (name) { - throw "this method should be overrwritten for type: " + name; + // If name isn't an array then treat it like a single element array. + return (this.nestedTypes(name) || ['[1]']) + .map(function (type) { + // the length of the nested array + return parseInt(type.slice(1, -1), 10) || 1; + }) + .reduce(function (previous, current) { + return previous * current; + // all basic types are 32 bytes long + }, 32); }; /** @@ -1670,13 +1630,14 @@ SolidityType.prototype.decode = function (bytes, offset, name) { var dynamicOffset = parseInt('0x' + bytes.substr(offset * 2, 64)); // in bytes var length = parseInt('0x' + bytes.substr(dynamicOffset * 2, 64)); // in bytes var roundedLength = Math.floor((length + 31) / 32); // in int - - return self._outputFormatter(new SolidityParam(bytes.substr(dynamicOffset * 2, ( 1 + roundedLength) * 64), 0)); + var param = new SolidityParam(bytes.substr(dynamicOffset * 2, ( 1 + roundedLength) * 64), 0); + return self._outputFormatter(param, name); })(); } var length = this.staticPartLength(name); - return this._outputFormatter(new SolidityParam(bytes.substr(offset * 2, length * 2))); + var param = new SolidityParam(bytes.substr(offset * 2, length * 2)); + return this._outputFormatter(param, name); }; module.exports = SolidityType; @@ -1713,10 +1674,6 @@ SolidityTypeUInt.prototype.isType = function (name) { return !!name.match(/^uint([0-9]*)?(\[([0-9]*)\])*$/); }; -SolidityTypeUInt.prototype.staticPartLength = function (name) { - return 32 * this.staticArrayLength(name); -}; - module.exports = SolidityTypeUInt; },{"./formatters":9,"./type":14}],16:[function(require,module,exports){ @@ -1751,10 +1708,6 @@ SolidityTypeUReal.prototype.isType = function (name) { return !!name.match(/^ureal([0-9]*)?(\[([0-9]*)\])*$/); }; -SolidityTypeUReal.prototype.staticPartLength = function (name) { - return 32 * this.staticArrayLength(name); -}; - module.exports = SolidityTypeUReal; },{"./formatters":9,"./type":14}],17:[function(require,module,exports){ @@ -1793,13 +1746,13 @@ if (typeof XMLHttpRequest === 'undefined') { /** * Utils - * + * * @module utils */ /** * Utility functions - * + * * @class [utils] config * @constructor */ @@ -1866,7 +1819,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file sha3.js * @author Marek Kotewicz * @date 2015 @@ -1889,7 +1842,7 @@ module.exports = function (value, options) { }; -},{"crypto-js":58,"crypto-js/sha3":79}],20:[function(require,module,exports){ +},{"crypto-js":59,"crypto-js/sha3":80}],20:[function(require,module,exports){ /* This file is part of web3.js. @@ -1931,7 +1884,7 @@ var sha3 = require('./sha3.js'); var utf8 = require('utf8'); var unitMap = { - 'noether': '0', + 'noether': '0', 'wei': '1', 'kwei': '1000', 'Kwei': '1000', @@ -1987,7 +1940,7 @@ var padRight = function (string, chars, sign) { }; /** - * Should be called to get utf8 from its hex representation + * Should be called to get utf8 from it's hex representation * * @method toUtf8 * @param {String} string in hex @@ -2011,7 +1964,7 @@ var toUtf8 = function(hex) { }; /** - * Should be called to get ascii from its hex representation + * Should be called to get ascii from it's hex representation * * @method toAscii * @param {String} string in hex @@ -2109,7 +2062,7 @@ var extractTypeName = function (name) { }; /** - * Converts value to its decimal representation in string + * Converts value to it's decimal representation in string * * @method toDecimal * @param {String|Number|BigNumber} @@ -2120,7 +2073,7 @@ var toDecimal = function (value) { }; /** - * Converts value to its hex representation + * Converts value to it's hex representation * * @method fromDecimal * @param {String|Number|BigNumber} @@ -2134,7 +2087,7 @@ var fromDecimal = function (value) { }; /** - * Auto converts any given value into its hex representation. + * Auto converts any given value into it's hex representation. * * And even stringifys objects before. * @@ -2267,7 +2220,7 @@ var toBigNumber = function(number) { * @return {BigNumber} */ var toTwosComplement = function (number) { - var bigNumber = toBigNumber(number); + var bigNumber = toBigNumber(number).round(); if (bigNumber.lessThan(0)) { return new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(bigNumber).plus(1); } @@ -2314,18 +2267,18 @@ var isAddress = function (address) { * @param {String} address the given HEX adress * @return {Boolean} */ -var isChecksumAddress = function (address) { +var isChecksumAddress = function (address) { // Check each case address = address.replace('0x',''); var addressHash = sha3(address.toLowerCase()); - for (var i = 0; i < 40; i++ ) { + for (var i = 0; i < 40; i++ ) { // the nth letter should be uppercase if the nth digit of casemap is 1 if ((parseInt(addressHash[i], 16) > 7 && address[i].toUpperCase() !== address[i]) || (parseInt(addressHash[i], 16) <= 7 && address[i].toLowerCase() !== address[i])) { return false; } } - return true; + return true; }; @@ -2337,15 +2290,15 @@ var isChecksumAddress = function (address) { * @param {String} address the given HEX adress * @return {String} */ -var toChecksumAddress = function (address) { +var toChecksumAddress = function (address) { if (typeof address === 'undefined') return ''; address = address.toLowerCase().replace('0x',''); var addressHash = sha3(address); var checksumAddress = '0x'; - for (var i = 0; i < address.length; i++ ) { - // If ith character is 9 to f then make it uppercase + for (var i = 0; i < address.length; i++ ) { + // If ith character is 9 to f then make it uppercase if (parseInt(addressHash[i], 16) > 7) { checksumAddress += address[i].toUpperCase(); } else { @@ -2488,9 +2441,9 @@ module.exports = { isJson: isJson }; -},{"./sha3.js":19,"bignumber.js":"bignumber.js","utf8":84}],21:[function(require,module,exports){ +},{"./sha3.js":19,"bignumber.js":"bignumber.js","utf8":85}],21:[function(require,module,exports){ module.exports={ - "version": "0.15.3" + "version": "0.18.1" } },{}],22:[function(require,module,exports){ @@ -2528,6 +2481,7 @@ var DB = require('./web3/methods/db'); var Shh = require('./web3/methods/shh'); var Net = require('./web3/methods/net'); var Personal = require('./web3/methods/personal'); +var Swarm = require('./web3/methods/swarm'); var Settings = require('./web3/settings'); var version = require('./version.json'); var utils = require('./utils/utils'); @@ -2537,6 +2491,7 @@ var Batch = require('./web3/batch'); var Property = require('./web3/property'); var HttpProvider = require('./web3/httpprovider'); var IpcProvider = require('./web3/ipcprovider'); +var BigNumber = require('bignumber.js'); @@ -2548,6 +2503,7 @@ function Web3 (provider) { this.shh = new Shh(this); this.net = new Net(this); this.personal = new Personal(this); + this.bzz = new Swarm(this); this.settings = new Settings(); this.version = { api: version.version @@ -2578,6 +2534,7 @@ Web3.prototype.reset = function (keepIsSyncing) { this.settings = new Settings(); }; +Web3.prototype.BigNumber = BigNumber; Web3.prototype.toHex = utils.toHex; Web3.prototype.toAscii = utils.toAscii; Web3.prototype.toUtf8 = utils.toUtf8; @@ -2641,7 +2598,7 @@ Web3.prototype.createBatch = function () { module.exports = Web3; -},{"./utils/sha3":19,"./utils/utils":20,"./version.json":21,"./web3/batch":24,"./web3/extend":28,"./web3/httpprovider":32,"./web3/iban":33,"./web3/ipcprovider":34,"./web3/methods/db":37,"./web3/methods/eth":38,"./web3/methods/net":39,"./web3/methods/personal":40,"./web3/methods/shh":41,"./web3/property":44,"./web3/requestmanager":45,"./web3/settings":46}],23:[function(require,module,exports){ +},{"./utils/sha3":19,"./utils/utils":20,"./version.json":21,"./web3/batch":24,"./web3/extend":28,"./web3/httpprovider":32,"./web3/iban":33,"./web3/ipcprovider":34,"./web3/methods/db":37,"./web3/methods/eth":38,"./web3/methods/net":39,"./web3/methods/personal":40,"./web3/methods/shh":41,"./web3/methods/swarm":42,"./web3/property":45,"./web3/requestmanager":46,"./web3/settings":47,"bignumber.js":"bignumber.js"}],23:[function(require,module,exports){ /* This file is part of web3.js. @@ -2658,7 +2615,7 @@ module.exports = Web3; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file allevents.js * @author Marek Kotewicz * @date 2014 @@ -2731,7 +2688,7 @@ AllSolidityEvents.prototype.attachToContract = function (contract) { module.exports = AllSolidityEvents; -},{"../utils/sha3":19,"../utils/utils":20,"./event":27,"./filter":29,"./formatters":30,"./methods/watches":42}],24:[function(require,module,exports){ +},{"../utils/sha3":19,"../utils/utils":20,"./event":27,"./filter":29,"./formatters":30,"./methods/watches":43}],24:[function(require,module,exports){ /* This file is part of web3.js. @@ -2748,7 +2705,7 @@ module.exports = AllSolidityEvents; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file batch.js * @author Marek Kotewicz * @date 2015 @@ -2786,14 +2743,14 @@ Batch.prototype.execute = function () { }).forEach(function (result, index) { if (requests[index].callback) { - if (!Jsonrpc.getInstance().isValidResponse(result)) { + if (!Jsonrpc.isValidResponse(result)) { return requests[index].callback(errors.InvalidResponse(result)); } requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result)); } }); - }); + }); }; module.exports = Batch; @@ -2907,7 +2864,7 @@ var checkForContractAddress = function(contract, callback){ // stop watching after 50 blocks (timeout) if (count > 50) { - filter.stopWatching(); + filter.stopWatching(function() {}); callbackFired = true; if (callback) @@ -2927,10 +2884,10 @@ var checkForContractAddress = function(contract, callback){ if(callbackFired || !code) return; - filter.stopWatching(); + filter.stopWatching(function() {}); callbackFired = true; - if(code.length > 2) { + if(code.length > 3) { // console.log('Contract code deployed!'); @@ -2995,6 +2952,16 @@ var ContractFactory = function (eth, abi) { options = args.pop(); } + if (options.value > 0) { + var constructorAbi = abi.filter(function (json) { + return json.type === 'constructor' && json.inputs.length === args.length; + })[0] || {}; + + if (!constructorAbi.payable) { + throw new Error('Cannot send value to non-payable constructor'); + } + } + var bytes = encodeConstructorParams(this.abi, args); options.data += bytes; @@ -3116,7 +3083,7 @@ module.exports = ContractFactory; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file errors.js * @author Marek Kotewicz * @date 2015 @@ -3135,10 +3102,12 @@ module.exports = { InvalidResponse: function (result){ var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: ' + JSON.stringify(result); return new Error(message); + }, + ConnectionTimeout: function (ms){ + return new Error('CONNECTION TIMEOUT: timeout of ' + ms + ' ms achived'); } }; - },{}],27:[function(require,module,exports){ /* This file is part of web3.js. @@ -3156,7 +3125,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file event.js * @author Marek Kotewicz * @date 2014 @@ -3227,7 +3196,7 @@ SolidityEvent.prototype.signature = function () { /** * Should be used to encode indexed params and options to one final object - * + * * @method encode * @param {Object} indexed * @param {Object} options @@ -3258,7 +3227,7 @@ SolidityEvent.prototype.encode = function (indexed, options) { if (value === undefined || value === null) { return null; } - + if (utils.isArray(value)) { return value.map(function (v) { return '0x' + coder.encodeParam(i.type, v); @@ -3280,17 +3249,17 @@ SolidityEvent.prototype.encode = function (indexed, options) { * @return {Object} result object with decoded indexed && not indexed params */ SolidityEvent.prototype.decode = function (data) { - + data.data = data.data || ''; data.topics = data.topics || []; var argTopics = this._anonymous ? data.topics : data.topics.slice(1); var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(""); - var indexedParams = coder.decodeParams(this.types(true), indexedData); + var indexedParams = coder.decodeParams(this.types(true), indexedData); var notIndexedData = data.data.slice(2); var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData); - + var result = formatters.outputLogFormatter(data); result.event = this.displayName(); result.address = data.address; @@ -3325,7 +3294,7 @@ SolidityEvent.prototype.execute = function (indexed, options, callback) { indexed = {}; } } - + var o = this.encode(indexed, options); var formatter = this.decode.bind(this); return new Filter(this._requestManager, o, watches.eth(), formatter, callback); @@ -3349,7 +3318,7 @@ SolidityEvent.prototype.attachToContract = function (contract) { module.exports = SolidityEvent; -},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"./filter":29,"./formatters":30,"./methods/watches":42}],28:[function(require,module,exports){ +},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"./filter":29,"./formatters":30,"./methods/watches":43}],28:[function(require,module,exports){ var formatters = require('./formatters'); var utils = require('./../utils/utils'); var Method = require('./method'); @@ -3386,7 +3355,7 @@ var extend = function (web3) { } }; - ex.formatters = formatters; + ex.formatters = formatters; ex.utils = utils; ex.Method = Method; ex.Property = Property; @@ -3399,7 +3368,7 @@ var extend = function (web3) { module.exports = extend; -},{"./../utils/utils":20,"./formatters":30,"./method":36,"./property":44}],29:[function(require,module,exports){ +},{"./../utils/utils":20,"./formatters":30,"./method":36,"./property":45}],29:[function(require,module,exports){ /* This file is part of web3.js. @@ -3532,7 +3501,7 @@ var pollFilter = function(self) { }; -var Filter = function (requestManager, options, methods, formatter, callback) { +var Filter = function (requestManager, options, methods, formatter, callback, filterCreationErrorCallback) { var self = this; var implementation = {}; methods.forEach(function (method) { @@ -3552,6 +3521,7 @@ var Filter = function (requestManager, options, methods, formatter, callback) { self.callbacks.forEach(function(cb){ cb(error); }); + filterCreationErrorCallback(error); } else { self.filterId = id; @@ -3590,11 +3560,15 @@ Filter.prototype.watch = function (callback) { return this; }; -Filter.prototype.stopWatching = function () { +Filter.prototype.stopWatching = function (callback) { this.requestManager.stopPolling(this.filterId); - // remove filter async - this.implementation.uninstallFilter(this.filterId, function(){}); this.callbacks = []; + // remove filter async + if (callback) { + this.implementation.uninstallFilter(this.filterId, callback); + } else { + return this.implementation.uninstallFilter(this.filterId); + } }; Filter.prototype.get = function (callback) { @@ -3911,12 +3885,11 @@ var outputSyncingFormatter = function(result) { result.startingBlock = utils.toDecimal(result.startingBlock); result.currentBlock = utils.toDecimal(result.currentBlock); result.highestBlock = utils.toDecimal(result.highestBlock); - if (result.knownStates !== undefined) { - result.knownStates = utils.toDecimal(result.knownStates); - } - if (result.pulledStates !== undefined) { - result.pulledStates = utils.toDecimal(result.pulledStates); + if (result.knownStates) { + result.knownStates = utils.toDecimal(result.knownStates); + result.pulledStates = utils.toDecimal(result.pulledStates); } + return result; }; @@ -3977,6 +3950,7 @@ var SolidityFunction = function (eth, json, address) { return i.type; }); this._constant = json.constant; + this._payable = json.payable; this._name = utils.transformToFullName(json); this._address = address; }; @@ -4055,7 +4029,17 @@ SolidityFunction.prototype.call = function () { var self = this; this._eth.call(payload, defaultBlock, function (error, output) { - callback(error, self.unpackOutput(output)); + if (error) return callback(error, null); + + var unpacked = null; + try { + unpacked = self.unpackOutput(output); + } + catch (e) { + error = e; + } + + callback(error, unpacked); }); }; @@ -4069,6 +4053,10 @@ SolidityFunction.prototype.sendTransaction = function () { var callback = this.extractCallback(args); var payload = this.toPayload(args); + if (payload.value > 0 && !this._payable) { + throw new Error('Cannot send value to non-payable function'); + } + if (!callback) { return this._eth.sendTransaction(payload); } @@ -4216,26 +4204,24 @@ module.exports = SolidityFunction; var errors = require('./errors'); // workaround to use httpprovider in different envs -var XMLHttpRequest; // jshint ignore: line - -// meteor server environment -if (typeof Meteor !== 'undefined' && Meteor.isServer) { // jshint ignore: line - XMLHttpRequest = Npm.require('xmlhttprequest').XMLHttpRequest; // jshint ignore: line +// var XMLHttpRequest; // jshint ignore: line // browser -} else if (typeof window !== 'undefined' && window.XMLHttpRequest) { +if (typeof window !== 'undefined' && window.XMLHttpRequest) { XMLHttpRequest = window.XMLHttpRequest; // jshint ignore: line - // node } else { XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore: line } +var XHR2 = require('xhr2'); // jshint ignore: line + /** * HttpProvider should be used to send rpc calls over http */ -var HttpProvider = function (host) { +var HttpProvider = function (host, timeout) { this.host = host || 'http://localhost:8588'; + this.timeout = timeout || 0; }; /** @@ -4246,7 +4232,15 @@ var HttpProvider = function (host) { * @return {XMLHttpRequest} object */ HttpProvider.prototype.prepareRequest = function (async) { - var request = new XMLHttpRequest(); + var request; + + if (async) { + request = new XHR2(); + request.timeout = this.timeout; + }else { + request = new XMLHttpRequest(); + } + request.open('POST', this.host, async); request.setRequestHeader('Content-Type','application/json'); return request; @@ -4290,7 +4284,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { var request = this.prepareRequest(true); request.onreadystatechange = function() { - if (request.readyState === 4) { + if (request.readyState === 4 && request.timeout !== 1) { var result = request.responseText; var error = null; @@ -4304,6 +4298,10 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { } }; + request.ontimeout = function() { + callback(errors.ConnectionTimeout(this.timeout)); + }; + try { request.send(JSON.stringify(payload)); } catch(error) { @@ -4333,8 +4331,7 @@ HttpProvider.prototype.isConnected = function() { module.exports = HttpProvider; - -},{"./errors":26,"xmlhttprequest":17}],33:[function(require,module,exports){ +},{"./errors":26,"xhr2":86,"xmlhttprequest":17}],33:[function(require,module,exports){ /* This file is part of web3.js. @@ -4351,7 +4348,7 @@ module.exports = HttpProvider; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file iban.js * @author Marek Kotewicz * @date 2015 @@ -4362,7 +4359,7 @@ var BigNumber = require('bignumber.js'); var padLeft = function (string, bytes) { var result = string; while (result.length < bytes * 2) { - result = '00' + result; + result = '0' + result; } return result; }; @@ -4551,7 +4548,7 @@ Iban.prototype.address = function () { var base36 = this._iban.substr(4); var asBn = new BigNumber(base36, 36); return padLeft(asBn.toString(16), 20); - } + } return ''; }; @@ -4596,7 +4593,7 @@ var IpcProvider = function (path, net) { var _this = this; this.responseCallbacks = {}; this.path = path; - + this.connection = net.connect({path: this.path}); this.connection.on('error', function(e){ @@ -4606,7 +4603,7 @@ var IpcProvider = function (path, net) { this.connection.on('end', function(){ _this._timeout(); - }); + }); // LISTEN FOR CONNECTION RESPONSES @@ -4645,7 +4642,7 @@ Will parse the response and make an array out of it. IpcProvider.prototype._parseResponse = function(data) { var _this = this, returnValues = []; - + // DE-CHUNKER var dechunkedData = data .replace(/\}[\n\r]?\{/g,'}|--|{') // }{ @@ -4749,7 +4746,7 @@ IpcProvider.prototype.send = function (payload) { try { result = JSON.parse(data); } catch(e) { - throw errors.InvalidResponse(data); + throw errors.InvalidResponse(data); } return result; @@ -4792,25 +4789,13 @@ module.exports = IpcProvider; /** @file jsonrpc.js * @authors: * Marek Kotewicz + * Aaron Kumavis * @date 2015 */ -var Jsonrpc = function () { - // singleton pattern - if (arguments.callee._singletonInstance) { - return arguments.callee._singletonInstance; - } - arguments.callee._singletonInstance = this; - - this.messageId = 1; -}; - -/** - * @return {Jsonrpc} singleton - */ -Jsonrpc.getInstance = function () { - var instance = new Jsonrpc(); - return instance; +// Initialize Jsonrpc as a simple object with utility functions. +var Jsonrpc = { + messageId: 0 }; /** @@ -4821,15 +4806,18 @@ Jsonrpc.getInstance = function () { * @param {Array} params, an array of method params, optional * @returns {Object} valid jsonrpc payload object */ -Jsonrpc.prototype.toPayload = function (method, params) { +Jsonrpc.toPayload = function (method, params) { if (!method) console.error('jsonrpc method should be specified!'); + // advance message ID + Jsonrpc.messageId++; + return { jsonrpc: '2.0', + id: Jsonrpc.messageId, method: method, - params: params || [], - id: this.messageId++ + params: params || [] }; }; @@ -4840,12 +4828,16 @@ Jsonrpc.prototype.toPayload = function (method, params) { * @param {Object} * @returns {Boolean} true if response is valid, otherwise false */ -Jsonrpc.prototype.isValidResponse = function (response) { - return !!response && - !response.error && - response.jsonrpc === '2.0' && - typeof response.id === 'number' && - response.result !== undefined; // only undefined is not valid json object +Jsonrpc.isValidResponse = function (response) { + return Array.isArray(response) ? response.every(validateSingleMessage) : validateSingleMessage(response); + + function validateSingleMessage(message){ + return !!message && + !message.error && + message.jsonrpc === '2.0' && + typeof message.id === 'number' && + message.result !== undefined; // only undefined is not valid json object + } }; /** @@ -4855,10 +4847,9 @@ Jsonrpc.prototype.isValidResponse = function (response) { * @param {Array} messages, an array of objects with method (required) and params (optional) fields * @returns {Array} batch payload */ -Jsonrpc.prototype.toBatchPayload = function (messages) { - var self = this; +Jsonrpc.toBatchPayload = function (messages) { return messages.map(function (message) { - return self.toPayload(message.method, message.params); + return Jsonrpc.toPayload(message.method, message.params); }); }; @@ -4930,7 +4921,7 @@ Method.prototype.extractCallback = function (args) { /** * Should be called to check if the number of arguments is correct - * + * * @method validateArgs * @param {Array} arguments * @throws {Error} if it is not @@ -4943,7 +4934,7 @@ Method.prototype.validateArgs = function (args) { /** * Should be called to format input args of method - * + * * @method formatInput * @param {Array} * @return {Array} @@ -4997,7 +4988,7 @@ Method.prototype.attachToObject = function (obj) { obj[name[0]] = obj[name[0]] || {}; obj[name[0]][name[1]] = func; } else { - obj[name[0]] = func; + obj[name[0]] = func; } }; @@ -5061,8 +5052,8 @@ var DB = function (web3) { this._requestManager = web3._requestManager; var self = this; - - methods().forEach(function(method) { + + methods().forEach(function(method) { method.attachToObject(self); method.setRequestManager(web3._requestManager); }); @@ -5164,12 +5155,12 @@ function Eth(web3) { var self = this; - methods().forEach(function(method) { + methods().forEach(function(method) { method.attachToObject(self); method.setRequestManager(self._requestManager); }); - properties().forEach(function(p) { + properties().forEach(function(p) { p.attachToObject(self); p.setRequestManager(self._requestManager); }); @@ -5417,6 +5408,10 @@ var properties = function () { name: 'blockNumber', getter: 'eth_blockNumber', outputFormatter: utils.toDecimal + }), + new Property({ + name: 'protocolVersion', + getter: 'eth_protocolVersion' }) ]; }; @@ -5445,7 +5440,7 @@ Eth.prototype.isSyncing = function (callback) { module.exports = Eth; -},{"../../utils/config":18,"../../utils/utils":20,"../contract":25,"../filter":29,"../formatters":30,"../iban":33,"../method":36,"../namereg":43,"../property":44,"../syncing":47,"../transfer":48,"./watches":42}],39:[function(require,module,exports){ +},{"../../utils/config":18,"../../utils/utils":20,"../contract":25,"../filter":29,"../formatters":30,"../iban":33,"../method":36,"../namereg":44,"../property":45,"../syncing":48,"../transfer":49,"./watches":43}],39:[function(require,module,exports){ /* This file is part of web3.js. @@ -5476,7 +5471,7 @@ var Net = function (web3) { var self = this; - properties().forEach(function(p) { + properties().forEach(function(p) { p.attachToObject(self); p.setRequestManager(web3._requestManager); }); @@ -5499,7 +5494,7 @@ var properties = function () { module.exports = Net; -},{"../../utils/utils":20,"../property":44}],40:[function(require,module,exports){ +},{"../../utils/utils":20,"../property":45}],40:[function(require,module,exports){ /* This file is part of web3.js. @@ -5560,6 +5555,13 @@ var methods = function () { inputFormatter: [formatters.inputAddressFormatter, null, null] }); + var sendTransaction = new Method({ + name: 'sendTransaction', + call: 'personal_sendTransaction', + params: 2, + inputFormatter: [formatters.inputTransactionFormatter, null] + }); + var lockAccount = new Method({ name: 'lockAccount', call: 'personal_lockAccount', @@ -5570,6 +5572,7 @@ var methods = function () { return [ newAccount, unlockAccount, + sendTransaction, lockAccount ]; }; @@ -5586,7 +5589,7 @@ var properties = function () { module.exports = Personal; -},{"../formatters":30,"../method":36,"../property":44}],41:[function(require,module,exports){ +},{"../formatters":30,"../method":36,"../property":45}],41:[function(require,module,exports){ /* This file is part of web3.js. @@ -5619,7 +5622,7 @@ var Shh = function (web3) { var self = this; - methods().forEach(function(method) { + methods().forEach(function(method) { method.attachToObject(self); method.setRequestManager(self._requestManager); }); @@ -5629,11 +5632,11 @@ Shh.prototype.filter = function (fil, callback) { return new Filter(this._requestManager, fil, watches.shh(), formatters.outputPostFormatter, callback); }; -var methods = function () { +var methods = function () { var post = new Method({ - name: 'post', - call: 'shh_post', + name: 'post', + call: 'shh_post', params: 1, inputFormatter: [formatters.inputPostFormatter] }); @@ -5674,7 +5677,154 @@ var methods = function () { module.exports = Shh; -},{"../filter":29,"../formatters":30,"../method":36,"./watches":42}],42:[function(require,module,exports){ +},{"../filter":29,"../formatters":30,"../method":36,"./watches":43}],42:[function(require,module,exports){ +/* + This file is part of web3.js. + + web3.js 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. + + web3.js 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 web3.js. If not, see . +*/ +/** + * @file bzz.js + * @author Alex Beregszaszi + * @date 2016 + * + * Reference: https://github.com/ubiq/go-ubiq/blob/swarm/internal/web3ext/web3ext.go#L33 + */ + +"use strict"; + +var Method = require('../method'); +var Property = require('../property'); + +function Swarm(web3) { + this._requestManager = web3._requestManager; + + var self = this; + + methods().forEach(function(method) { + method.attachToObject(self); + method.setRequestManager(self._requestManager); + }); + + properties().forEach(function(p) { + p.attachToObject(self); + p.setRequestManager(self._requestManager); + }); +} + +var methods = function () { + var blockNetworkRead = new Method({ + name: 'blockNetworkRead', + call: 'bzz_blockNetworkRead', + params: 1, + inputFormatter: [null] + }); + + var syncEnabled = new Method({ + name: 'syncEnabled', + call: 'bzz_syncEnabled', + params: 1, + inputFormatter: [null] + }); + + var swapEnabled = new Method({ + name: 'swapEnabled', + call: 'bzz_swapEnabled', + params: 1, + inputFormatter: [null] + }); + + var download = new Method({ + name: 'download', + call: 'bzz_download', + params: 2, + inputFormatter: [null, null] + }); + + var upload = new Method({ + name: 'upload', + call: 'bzz_upload', + params: 2, + inputFormatter: [null, null] + }); + + var retrieve = new Method({ + name: 'retrieve', + call: 'bzz_retrieve', + params: 1, + inputFormatter: [null] + }); + + var store = new Method({ + name: 'store', + call: 'bzz_store', + params: 2, + inputFormatter: [null, null] + }); + + var get = new Method({ + name: 'get', + call: 'bzz_get', + params: 1, + inputFormatter: [null] + }); + + var put = new Method({ + name: 'put', + call: 'bzz_put', + params: 2, + inputFormatter: [null, null] + }); + + var modify = new Method({ + name: 'modify', + call: 'bzz_modify', + params: 4, + inputFormatter: [null, null, null, null] + }); + + return [ + blockNetworkRead, + syncEnabled, + swapEnabled, + download, + upload, + retrieve, + store, + get, + put, + modify + ]; +}; + +var properties = function () { + return [ + new Property({ + name: 'hive', + getter: 'bzz_hive' + }), + new Property({ + name: 'info', + getter: 'bzz_info' + }) + ]; +}; + + +module.exports = Swarm; + +},{"../method":36,"../property":45}],43:[function(require,module,exports){ /* This file is part of web3.js. @@ -5790,7 +5940,7 @@ module.exports = { }; -},{"../method":36}],43:[function(require,module,exports){ +},{"../method":36}],44:[function(require,module,exports){ /* This file is part of web3.js. @@ -5807,7 +5957,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file namereg.js * @author Marek Kotewicz * @date 2015 @@ -5831,7 +5981,7 @@ module.exports = { }; -},{"../contracts/GlobalRegistrar.json":1,"../contracts/ICAPRegistrar.json":2}],44:[function(require,module,exports){ +},{"../contracts/GlobalRegistrar.json":1,"../contracts/ICAPRegistrar.json":2}],45:[function(require,module,exports){ /* This file is part of web3.js. @@ -5889,7 +6039,7 @@ Property.prototype.formatInput = function (arg) { * @return {Object} */ Property.prototype.formatOutput = function (result) { - return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; + return this.outputFormatter && result !== null && result !== undefined ? this.outputFormatter(result) : result; }; /** @@ -5977,7 +6127,7 @@ Property.prototype.request = function () { module.exports = Property; -},{"../utils/utils":20}],45:[function(require,module,exports){ +},{"../utils/utils":20}],46:[function(require,module,exports){ /* This file is part of web3.js. @@ -5994,7 +6144,7 @@ module.exports = Property; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file requestmanager.js * @author Jeffrey Wilcke * @author Marek Kotewicz @@ -6034,10 +6184,10 @@ RequestManager.prototype.send = function (data) { return null; } - var payload = Jsonrpc.getInstance().toPayload(data.method, data.params); + var payload = Jsonrpc.toPayload(data.method, data.params); var result = this.provider.send(payload); - if (!Jsonrpc.getInstance().isValidResponse(result)) { + if (!Jsonrpc.isValidResponse(result)) { throw errors.InvalidResponse(result); } @@ -6056,13 +6206,13 @@ RequestManager.prototype.sendAsync = function (data, callback) { return callback(errors.InvalidProvider()); } - var payload = Jsonrpc.getInstance().toPayload(data.method, data.params); + var payload = Jsonrpc.toPayload(data.method, data.params); this.provider.sendAsync(payload, function (err, result) { if (err) { return callback(err); } - - if (!Jsonrpc.getInstance().isValidResponse(result)) { + + if (!Jsonrpc.isValidResponse(result)) { return callback(errors.InvalidResponse(result)); } @@ -6082,7 +6232,7 @@ RequestManager.prototype.sendBatch = function (data, callback) { return callback(errors.InvalidProvider()); } - var payload = Jsonrpc.getInstance().toBatchPayload(data); + var payload = Jsonrpc.toBatchPayload(data); this.provider.sendAsync(payload, function (err, results) { if (err) { @@ -6094,7 +6244,7 @@ RequestManager.prototype.sendBatch = function (data, callback) { } callback(err, results); - }); + }); }; /** @@ -6197,8 +6347,8 @@ RequestManager.prototype.poll = function () { return; } - var payload = Jsonrpc.getInstance().toBatchPayload(pollsData); - + var payload = Jsonrpc.toBatchPayload(pollsData); + // map the request id to they poll id var pollsIdMap = {}; payload.forEach(function(load, index){ @@ -6228,9 +6378,9 @@ RequestManager.prototype.poll = function () { } else return false; }).filter(function (result) { - return !!result; + return !!result; }).filter(function (result) { - var valid = Jsonrpc.getInstance().isValidResponse(result); + var valid = Jsonrpc.isValidResponse(result); if (!valid) { result.callback(errors.InvalidResponse(result)); } @@ -6244,7 +6394,7 @@ RequestManager.prototype.poll = function () { module.exports = RequestManager; -},{"../utils/config":18,"../utils/utils":20,"./errors":26,"./jsonrpc":35}],46:[function(require,module,exports){ +},{"../utils/config":18,"../utils/utils":20,"./errors":26,"./jsonrpc":35}],47:[function(require,module,exports){ var Settings = function () { @@ -6255,7 +6405,7 @@ var Settings = function () { module.exports = Settings; -},{}],47:[function(require,module,exports){ +},{}],48:[function(require,module,exports){ /* This file is part of web3.js. @@ -6303,16 +6453,16 @@ var pollSyncing = function(self) { self.callbacks.forEach(function (callback) { if (self.lastSyncState !== sync) { - + // call the callback with true first so the app can stop anything, before receiving the sync data if(!self.lastSyncState && utils.isObject(sync)) callback(null, true); - + // call on the next CPU cycle, so the actions of the sync stop can be processes first setTimeout(function() { callback(null, sync); }, 0); - + self.lastSyncState = sync; } }); @@ -6350,7 +6500,7 @@ IsSyncing.prototype.stopWatching = function () { module.exports = IsSyncing; -},{"../utils/utils":20,"./formatters":30}],48:[function(require,module,exports){ +},{"../utils/utils":20,"./formatters":30}],49:[function(require,module,exports){ /* This file is part of web3.js. @@ -6367,7 +6517,7 @@ module.exports = IsSyncing; You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/** +/** * @file transfer.js * @author Marek Kotewicz * @date 2015 @@ -6386,7 +6536,7 @@ var exchangeAbi = require('../contracts/SmartExchange.json'); * @param {Function} callback, callback */ var transfer = function (eth, from, to, value, callback) { - var iban = new Iban(to); + var iban = new Iban(to); if (!iban.isValid()) { throw new Error('invalid iban address'); } @@ -6394,7 +6544,7 @@ var transfer = function (eth, from, to, value, callback) { if (iban.isDirect()) { return transferToAddress(eth, from, iban.address(), value, callback); } - + if (!callback) { var address = eth.icapNamereg().addr(iban.institution()); return deposit(eth, from, address, value, iban.client()); @@ -6403,7 +6553,7 @@ var transfer = function (eth, from, to, value, callback) { eth.icapNamereg().addr(iban.institution(), function (err, address) { return deposit(eth, from, address, value, iban.client(), callback); }); - + }; /** @@ -6444,9 +6594,9 @@ var deposit = function (eth, from, to, value, client, callback) { module.exports = transfer; -},{"../contracts/SmartExchange.json":3,"./iban":33}],49:[function(require,module,exports){ +},{"../contracts/SmartExchange.json":3,"./iban":33}],50:[function(require,module,exports){ -},{}],50:[function(require,module,exports){ +},{}],51:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -6540,13 +6690,18 @@ module.exports = transfer; */ var AES = C_algo.AES = BlockCipher.extend({ _doReset: function () { + // Skip reset of nRounds has been set before and key did not change + if (this._nRounds && this._keyPriorReset === this._key) { + return; + } + // Shortcuts - var key = this._key; + var key = this._keyPriorReset = this._key; var keyWords = key.words; var keySize = key.sigBytes / 4; // Compute number of rounds - var nRounds = this._nRounds = keySize + 6 + var nRounds = this._nRounds = keySize + 6; // Compute number of key schedule rows var ksRows = (nRounds + 1) * 4; @@ -6674,7 +6829,7 @@ module.exports = transfer; return CryptoJS.AES; })); -},{"./cipher-core":51,"./core":52,"./enc-base64":53,"./evpkdf":55,"./md5":60}],51:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53,"./enc-base64":54,"./evpkdf":56,"./md5":61}],52:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -7550,7 +7705,7 @@ module.exports = transfer; })); -},{"./core":52}],52:[function(require,module,exports){ +},{"./core":53}],53:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -7570,6 +7725,25 @@ module.exports = transfer; * CryptoJS core components. */ var CryptoJS = CryptoJS || (function (Math, undefined) { + /* + * Local polyfil of Object.create + */ + var create = Object.create || (function () { + function F() {}; + + return function (obj) { + var subtype; + + F.prototype = obj; + + subtype = new F(); + + F.prototype = null; + + return subtype; + }; + }()) + /** * CryptoJS namespace. */ @@ -7584,7 +7758,7 @@ module.exports = transfer; * Base object for prototypal inheritance. */ var Base = C_lib.Base = (function () { - function F() {} + return { /** @@ -7607,8 +7781,7 @@ module.exports = transfer; */ extend: function (overrides) { // Spawn - F.prototype = this; - var subtype = new F(); + var subtype = create(this); // Augment if (overrides) { @@ -7616,7 +7789,7 @@ module.exports = transfer; } // Create default initializer - if (!subtype.hasOwnProperty('init')) { + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { subtype.init = function () { subtype.$super.init.apply(this, arguments); }; @@ -8293,7 +8466,7 @@ module.exports = transfer; return CryptoJS; })); -},{}],53:[function(require,module,exports){ +},{}],54:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -8384,40 +8557,52 @@ module.exports = transfer; // Shortcuts var base64StrLength = base64Str.length; var map = this._map; + var reverseMap = this._reverseMap; + + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } // Ignore padding var paddingChar = map.charAt(64); if (paddingChar) { var paddingIndex = base64Str.indexOf(paddingChar); - if (paddingIndex != -1) { + if (paddingIndex !== -1) { base64StrLength = paddingIndex; } } // Convert - var words = []; - var nBytes = 0; - for (var i = 0; i < base64StrLength; i++) { - if (i % 4) { - var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); - var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); - words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); - nBytes++; - } - } + return parseLoop(base64Str, base64StrLength, reverseMap); - return WordArray.create(words, nBytes); }, _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' }; + + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } }()); return CryptoJS.enc.Base64; })); -},{"./core":52}],54:[function(require,module,exports){ +},{"./core":53}],55:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -8567,7 +8752,7 @@ module.exports = transfer; return CryptoJS.enc.Utf16; })); -},{"./core":52}],55:[function(require,module,exports){ +},{"./core":53}],56:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -8700,7 +8885,7 @@ module.exports = transfer; return CryptoJS.EvpKDF; })); -},{"./core":52,"./hmac":57,"./sha1":76}],56:[function(require,module,exports){ +},{"./core":53,"./hmac":58,"./sha1":77}],57:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -8767,7 +8952,7 @@ module.exports = transfer; return CryptoJS.format.Hex; })); -},{"./cipher-core":51,"./core":52}],57:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],58:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -8911,7 +9096,7 @@ module.exports = transfer; })); -},{"./core":52}],58:[function(require,module,exports){ +},{"./core":53}],59:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -8930,7 +9115,7 @@ module.exports = transfer; return CryptoJS; })); -},{"./aes":50,"./cipher-core":51,"./core":52,"./enc-base64":53,"./enc-utf16":54,"./evpkdf":55,"./format-hex":56,"./hmac":57,"./lib-typedarrays":59,"./md5":60,"./mode-cfb":61,"./mode-ctr":63,"./mode-ctr-gladman":62,"./mode-ecb":64,"./mode-ofb":65,"./pad-ansix923":66,"./pad-iso10126":67,"./pad-iso97971":68,"./pad-nopadding":69,"./pad-zeropadding":70,"./pbkdf2":71,"./rabbit":73,"./rabbit-legacy":72,"./rc4":74,"./ripemd160":75,"./sha1":76,"./sha224":77,"./sha256":78,"./sha3":79,"./sha384":80,"./sha512":81,"./tripledes":82,"./x64-core":83}],59:[function(require,module,exports){ +},{"./aes":51,"./cipher-core":52,"./core":53,"./enc-base64":54,"./enc-utf16":55,"./evpkdf":56,"./format-hex":57,"./hmac":58,"./lib-typedarrays":60,"./md5":61,"./mode-cfb":62,"./mode-ctr":64,"./mode-ctr-gladman":63,"./mode-ecb":65,"./mode-ofb":66,"./pad-ansix923":67,"./pad-iso10126":68,"./pad-iso97971":69,"./pad-nopadding":70,"./pad-zeropadding":71,"./pbkdf2":72,"./rabbit":74,"./rabbit-legacy":73,"./rc4":75,"./ripemd160":76,"./sha1":77,"./sha224":78,"./sha256":79,"./sha3":80,"./sha384":81,"./sha512":82,"./tripledes":83,"./x64-core":84}],60:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -9007,7 +9192,7 @@ module.exports = transfer; return CryptoJS.lib.WordArray; })); -},{"./core":52}],60:[function(require,module,exports){ +},{"./core":53}],61:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -9276,7 +9461,7 @@ module.exports = transfer; return CryptoJS.MD5; })); -},{"./core":52}],61:[function(require,module,exports){ +},{"./core":53}],62:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9355,7 +9540,7 @@ module.exports = transfer; return CryptoJS.mode.CFB; })); -},{"./cipher-core":51,"./core":52}],62:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],63:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9472,7 +9657,7 @@ module.exports = transfer; return CryptoJS.mode.CTRGladman; })); -},{"./cipher-core":51,"./core":52}],63:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],64:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9531,7 +9716,7 @@ module.exports = transfer; return CryptoJS.mode.CTR; })); -},{"./cipher-core":51,"./core":52}],64:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],65:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9572,7 +9757,7 @@ module.exports = transfer; return CryptoJS.mode.ECB; })); -},{"./cipher-core":51,"./core":52}],65:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],66:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9627,7 +9812,7 @@ module.exports = transfer; return CryptoJS.mode.OFB; })); -},{"./cipher-core":51,"./core":52}],66:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],67:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9677,7 +9862,7 @@ module.exports = transfer; return CryptoJS.pad.Ansix923; })); -},{"./cipher-core":51,"./core":52}],67:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],68:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9722,7 +9907,7 @@ module.exports = transfer; return CryptoJS.pad.Iso10126; })); -},{"./cipher-core":51,"./core":52}],68:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],69:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9763,7 +9948,7 @@ module.exports = transfer; return CryptoJS.pad.Iso97971; })); -},{"./cipher-core":51,"./core":52}],69:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],70:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9794,7 +9979,7 @@ module.exports = transfer; return CryptoJS.pad.NoPadding; })); -},{"./cipher-core":51,"./core":52}],70:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],71:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9840,7 +10025,7 @@ module.exports = transfer; return CryptoJS.pad.ZeroPadding; })); -},{"./cipher-core":51,"./core":52}],71:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53}],72:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -9986,7 +10171,7 @@ module.exports = transfer; return CryptoJS.PBKDF2; })); -},{"./core":52,"./hmac":57,"./sha1":76}],72:[function(require,module,exports){ +},{"./core":53,"./hmac":58,"./sha1":77}],73:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -10177,7 +10362,7 @@ module.exports = transfer; return CryptoJS.RabbitLegacy; })); -},{"./cipher-core":51,"./core":52,"./enc-base64":53,"./evpkdf":55,"./md5":60}],73:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53,"./enc-base64":54,"./evpkdf":56,"./md5":61}],74:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -10370,7 +10555,7 @@ module.exports = transfer; return CryptoJS.Rabbit; })); -},{"./cipher-core":51,"./core":52,"./enc-base64":53,"./evpkdf":55,"./md5":60}],74:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53,"./enc-base64":54,"./evpkdf":56,"./md5":61}],75:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -10510,7 +10695,7 @@ module.exports = transfer; return CryptoJS.RC4; })); -},{"./cipher-core":51,"./core":52,"./enc-base64":53,"./evpkdf":55,"./md5":60}],75:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53,"./enc-base64":54,"./evpkdf":56,"./md5":61}],76:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -10778,7 +10963,7 @@ module.exports = transfer; return CryptoJS.RIPEMD160; })); -},{"./core":52}],76:[function(require,module,exports){ +},{"./core":53}],77:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -10929,7 +11114,7 @@ module.exports = transfer; return CryptoJS.SHA1; })); -},{"./core":52}],77:[function(require,module,exports){ +},{"./core":53}],78:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -11010,7 +11195,7 @@ module.exports = transfer; return CryptoJS.SHA224; })); -},{"./core":52,"./sha256":78}],78:[function(require,module,exports){ +},{"./core":53,"./sha256":79}],79:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -11210,7 +11395,7 @@ module.exports = transfer; return CryptoJS.SHA256; })); -},{"./core":52}],79:[function(require,module,exports){ +},{"./core":53}],80:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -11534,7 +11719,7 @@ module.exports = transfer; return CryptoJS.SHA3; })); -},{"./core":52,"./x64-core":83}],80:[function(require,module,exports){ +},{"./core":53,"./x64-core":84}],81:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -11618,7 +11803,7 @@ module.exports = transfer; return CryptoJS.SHA384; })); -},{"./core":52,"./sha512":81,"./x64-core":83}],81:[function(require,module,exports){ +},{"./core":53,"./sha512":82,"./x64-core":84}],82:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -11942,7 +12127,7 @@ module.exports = transfer; return CryptoJS.SHA512; })); -},{"./core":52,"./x64-core":83}],82:[function(require,module,exports){ +},{"./core":53,"./x64-core":84}],83:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -12713,7 +12898,7 @@ module.exports = transfer; return CryptoJS.TripleDES; })); -},{"./cipher-core":51,"./core":52,"./enc-base64":53,"./evpkdf":55,"./md5":60}],83:[function(require,module,exports){ +},{"./cipher-core":52,"./core":53,"./enc-base64":54,"./evpkdf":56,"./md5":61}],84:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -13018,19 +13203,19 @@ module.exports = transfer; return CryptoJS; })); -},{"./core":52}],84:[function(require,module,exports){ -/*! https://mths.be/utf8js v2.0.0 by @mathias */ +},{"./core":53}],85:[function(require,module,exports){ +/*! https://mths.be/utf8js v2.1.2 by @mathias */ ;(function(root) { - // Detect free variables exports + // Detect free variables `exports` var freeExports = typeof exports == 'object' && exports; - // Detect free variable module + // Detect free variable `module` var freeModule = typeof module == 'object' && module && module.exports == freeExports && module; - // Detect free variable global, from Node.js or Browserified code, - // and use it as root + // Detect free variable `global`, from Node.js or Browserified code, + // and use it as `root` var freeGlobal = typeof global == 'object' && global; if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { root = freeGlobal; @@ -13178,7 +13363,7 @@ module.exports = transfer; // 2-byte sequence if ((byte1 & 0xE0) == 0xC0) { - var byte2 = readContinuationByte(); + byte2 = readContinuationByte(); codePoint = ((byte1 & 0x1F) << 6) | byte2; if (codePoint >= 0x80) { return codePoint; @@ -13205,7 +13390,7 @@ module.exports = transfer; byte2 = readContinuationByte(); byte3 = readContinuationByte(); byte4 = readContinuationByte(); - codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) | + codePoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0C) | (byte3 << 0x06) | byte4; if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) { return codePoint; @@ -13233,7 +13418,7 @@ module.exports = transfer; /*--------------------------------------------------------------------------*/ var utf8 = { - 'version': '2.0.0', + 'version': '2.1.2', 'encode': utf8encode, 'decode': utf8decode }; @@ -13264,6 +13449,9 @@ module.exports = transfer; }(this)); +},{}],86:[function(require,module,exports){ +module.exports = XMLHttpRequest; + },{}],"bignumber.js":[function(require,module,exports){ /*! bignumber.js v2.0.7 https://github.com/MikeMcl/bignumber.js/LICENCE */ @@ -15949,7 +16137,7 @@ module.exports = transfer; } })(this); -},{"crypto":49}],"web3":[function(require,module,exports){ +},{"crypto":50}],"web3":[function(require,module,exports){ var Web3 = require('./lib/web3'); // dont override global variable @@ -15961,4 +16149,3 @@ module.exports = Web3; },{"./lib/web3":22}]},{},["web3"]) //# sourceMappingURL=web3.js.map -` diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index 70e8ab95e0..3e027c370d 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -26,8 +26,14 @@ import ( "math/rand" "time" - "github.com/ubiq/go-ubiq/common" "github.com/robertkrimen/otto" + "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/internal/jsre/deps" +) + +var ( + BigNumber_JS = deps.MustAsset("bignumber.js") + Web3_JS = deps.MustAsset("web3.js") ) /* @@ -71,7 +77,7 @@ func New(assetPath string, output io.Writer) *JSRE { } go re.runEventLoop() re.Set("loadScript", re.loadScript) - re.Set("inspect", prettyPrintJS) + re.Set("inspect", re.prettyPrintJS) return re } diff --git a/internal/jsre/pretty.go b/internal/jsre/pretty.go index 8fe00cc4c8..e096eec236 100644 --- a/internal/jsre/pretty.go +++ b/internal/jsre/pretty.go @@ -73,10 +73,10 @@ func jsErrorString(err error) string { return err.Error() } -func prettyPrintJS(call otto.FunctionCall, w io.Writer) otto.Value { +func (re *JSRE) prettyPrintJS(call otto.FunctionCall) otto.Value { for _, v := range call.ArgumentList { - prettyPrint(call.Otto, v, w) - fmt.Fprintln(w) + prettyPrint(call.Otto, v, re.output) + fmt.Fprintln(re.output) } return otto.UndefinedValue() } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 83f8a25a20..527bb64826 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -535,12 +535,6 @@ web3._extend({ call: 'personal_importRawKey', params: 2 }), - new web3._extend.Method({ - name: 'sendTransaction', - call: 'personal_sendTransaction', - params: 2, - inputFormatter: [web3._extend.formatters.inputTransactionFormatter, null] - }), new web3._extend.Method({ name: 'sign', call: 'personal_sign', diff --git a/les/api_backend.go b/les/api_backend.go index 8dcaafc6e1..85bf0f6894 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -31,7 +31,7 @@ import ( "github.com/ubiq/go-ubiq/internal/ethapi" "github.com/ubiq/go-ubiq/light" "github.com/ubiq/go-ubiq/params" - rpc "github.com/ubiq/go-ubiq/rpc" + "github.com/ubiq/go-ubiq/rpc" "golang.org/x/net/context" ) @@ -88,7 +88,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int { return b.eth.blockchain.GetTdByHash(blockHash) } -func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) { +func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (*vm.EVM, func() error, error) { stateDb := state.(*light.LightState).Copy() addr := msg.From() from, err := stateDb.GetOrNewStateObject(ctx, addr) @@ -96,8 +96,10 @@ func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state et return nil, nil, err } from.SetBalance(common.MaxBig) - env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}) - return env, env.Error, nil + + vmstate := light.NewVMState(ctx, stateDb) + context := core.NewEVMContext(msg, header, b.eth.blockchain) + return vm.NewEVM(context, vmstate, b.eth.chainConfig, vm.Config{}), vmstate.Error, nil } func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { @@ -108,7 +110,7 @@ func (b *LesApiBackend) RemoveTx(txHash common.Hash) { b.eth.txPool.RemoveTx(txHash) } -func (b *LesApiBackend) GetPoolTransactions() types.Transactions { +func (b *LesApiBackend) GetPoolTransactions() (types.Transactions, error) { return b.eth.txPool.GetTransactions() } diff --git a/les/backend.go b/les/backend.go index f7b862292a..41f093780d 100644 --- a/les/backend.go +++ b/les/backend.go @@ -22,10 +22,10 @@ import ( "fmt" "time" - "github.com/ethereum/ethash" "github.com/ubiq/go-ubiq/accounts" "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/common/compiler" + "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/core" "github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/eth" @@ -41,6 +41,7 @@ import ( "github.com/ubiq/go-ubiq/node" "github.com/ubiq/go-ubiq/p2p" "github.com/ubiq/go-ubiq/params" + "github.com/ubiq/go-ubiq/pow" rpc "github.com/ubiq/go-ubiq/rpc" ) @@ -60,13 +61,12 @@ type LightEthereum struct { ApiBackend *LesApiBackend eventMux *event.TypeMux - pow *ethash.Ethash + pow pow.PoW accountManager *accounts.Manager solcPath string solc *compiler.Solidity NatSpec bool - PowTest bool netVersionId int netRPCService *ethapi.PublicNetAPI } @@ -96,7 +96,6 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { shutdownChan: make(chan bool), netVersionId: config.NetworkId, NatSpec: config.NatSpec, - PowTest: config.PowTest, solcPath: config.SolcPath, } @@ -135,8 +134,8 @@ func (s *LightDummyAPI) Coinbase() (common.Address, error) { } // Hashrate returns the POW hashrate -func (s *LightDummyAPI) Hashrate() *rpc.HexNumber { - return rpc.NewHexNumber(0) +func (s *LightDummyAPI) Hashrate() hexutil.Uint { + return 0 } // Mining returns an indication if this node is currently mining. diff --git a/les/fetcher.go b/les/fetcher.go index 514371dfc2..00eaae0313 100644 --- a/les/fetcher.go +++ b/les/fetcher.go @@ -23,248 +23,148 @@ import ( "time" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/common/mclock" "github.com/ubiq/go-ubiq/core" "github.com/ubiq/go-ubiq/core/types" + "github.com/ubiq/go-ubiq/light" + "github.com/ubiq/go-ubiq/logger" + "github.com/ubiq/go-ubiq/logger/glog" ) +const ( + blockDelayTimeout = time.Second * 10 // timeout for a peer to announce a head that has already been confirmed by others + maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer +) + +// lightFetcher type lightFetcher struct { pm *ProtocolManager odr *LesOdr - chain BlockChain + chain *light.LightChain - headAnnouncedMu sync.Mutex - headAnnouncedBy map[common.Hash][]*peer - currentTd *big.Int - deliverChn chan fetchResponse - reqMu sync.RWMutex - requested map[uint64]fetchRequest - timeoutChn chan uint64 - notifyChn chan bool // true if initiated from outside - syncing bool - syncDone chan struct{} + maxConfirmedTd *big.Int + peers map[*peer]*fetcherPeerInfo + lastUpdateStats *updateStatsEntry + + lock sync.Mutex // qwerqwerqwe + deliverChn chan fetchResponse + reqMu sync.RWMutex + requested map[uint64]fetchRequest + timeoutChn chan uint64 + requestChn chan bool // true if initiated from outside + syncing bool + syncDone chan *peer } +// fetcherPeerInfo holds fetcher-specific information about each active peer +type fetcherPeerInfo struct { + root, lastAnnounced *fetcherTreeNode + nodeCnt int + confirmedTd *big.Int + bestConfirmed *fetcherTreeNode + nodeByHash map[common.Hash]*fetcherTreeNode + firstUpdateStats *updateStatsEntry +} + +// fetcherTreeNode is a node of a tree that holds information about blocks recently +// announced and confirmed by a certain peer. Each new announce message from a peer +// adds nodes to the tree, based on the previous announced head and the reorg depth. +// There are three possible states for a tree node: +// - announced: not downloaded (known) yet, but we know its head, number and td +// - intermediate: not known, hash and td are empty, they are filled out when it becomes known +// - known: both announced by this peer and downloaded (from any peer). +// This structure makes it possible to always know which peer has a certain block, +// which is necessary for selecting a suitable peer for ODR requests and also for +// canonizing new heads. It also helps to always download the minimum necessary +// amount of headers with a single request. +type fetcherTreeNode struct { + hash common.Hash + number uint64 + td *big.Int + known, requested bool + parent *fetcherTreeNode + children []*fetcherTreeNode +} + +// fetchRequest represents a header download request type fetchRequest struct { - hash common.Hash - amount uint64 - peer *peer + hash common.Hash + amount uint64 + peer *peer + sent mclock.AbsTime + timeout bool } +// fetchResponse represents a header download response type fetchResponse struct { reqID uint64 headers []*types.Header + peer *peer } +// newLightFetcher creates a new light fetcher func newLightFetcher(pm *ProtocolManager) *lightFetcher { f := &lightFetcher{ - pm: pm, - chain: pm.blockchain, - odr: pm.odr, - headAnnouncedBy: make(map[common.Hash][]*peer), - deliverChn: make(chan fetchResponse, 100), - requested: make(map[uint64]fetchRequest), - timeoutChn: make(chan uint64), - notifyChn: make(chan bool, 100), - syncDone: make(chan struct{}), - currentTd: big.NewInt(0), + pm: pm, + chain: pm.blockchain.(*light.LightChain), + odr: pm.odr, + peers: make(map[*peer]*fetcherPeerInfo), + deliverChn: make(chan fetchResponse, 100), + requested: make(map[uint64]fetchRequest), + timeoutChn: make(chan uint64), + requestChn: make(chan bool, 100), + syncDone: make(chan *peer), + maxConfirmedTd: big.NewInt(0), } go f.syncLoop() return f } -func (f *lightFetcher) notify(p *peer, head *announceData) { - var headHash common.Hash - if head == nil { - // initial notify - headHash = p.Head() - } else { - if core.GetTd(f.pm.chainDb, head.Hash, head.Number) != nil { - head.haveHeaders = head.Number - } - //fmt.Println("notify", p.id, head.Number, head.ReorgDepth, head.haveHeaders) - if !p.addNotify(head) { - //fmt.Println("addNotify fail") - f.pm.removePeer(p.id) - } - headHash = head.Hash - } - f.headAnnouncedMu.Lock() - f.headAnnouncedBy[headHash] = append(f.headAnnouncedBy[headHash], p) - f.headAnnouncedMu.Unlock() - f.notifyChn <- true -} - -func (f *lightFetcher) gotHeader(header *types.Header) { - f.headAnnouncedMu.Lock() - defer f.headAnnouncedMu.Unlock() - - hash := header.Hash() - peerList := f.headAnnouncedBy[hash] - if peerList == nil { - return - } - number := header.Number.Uint64() - td := core.GetTd(f.pm.chainDb, hash, number) - for _, peer := range peerList { - peer.lock.Lock() - ok := peer.gotHeader(hash, number, td) - peer.lock.Unlock() - if !ok { - //fmt.Println("gotHeader fail") - f.pm.removePeer(peer.id) - } - } - delete(f.headAnnouncedBy, hash) -} - -func (f *lightFetcher) nextRequest() (*peer, *announceData) { - var bestPeer *peer - bestTd := f.currentTd - for _, peer := range f.pm.peers.AllPeers() { - peer.lock.RLock() - if !peer.headInfo.requested && (peer.headInfo.Td.Cmp(bestTd) > 0 || - (bestPeer != nil && peer.headInfo.Td.Cmp(bestTd) == 0 && peer.headInfo.haveHeaders > bestPeer.headInfo.haveHeaders)) { - bestPeer = peer - bestTd = peer.headInfo.Td - } - peer.lock.RUnlock() - } - if bestPeer == nil { - return nil, nil - } - bestPeer.lock.Lock() - res := bestPeer.headInfo - res.requested = true - bestPeer.lock.Unlock() - for _, peer := range f.pm.peers.AllPeers() { - if peer != bestPeer { - peer.lock.Lock() - if peer.headInfo.Hash == bestPeer.headInfo.Hash && peer.headInfo.haveHeaders == bestPeer.headInfo.haveHeaders { - peer.headInfo.requested = true - } - peer.lock.Unlock() - } - } - return bestPeer, res -} - -func (f *lightFetcher) deliverHeaders(reqID uint64, headers []*types.Header) { - f.deliverChn <- fetchResponse{reqID: reqID, headers: headers} -} - -func (f *lightFetcher) requestedID(reqID uint64) bool { - f.reqMu.RLock() - _, ok := f.requested[reqID] - f.reqMu.RUnlock() - return ok -} - -func (f *lightFetcher) request(p *peer, block *announceData) { - //fmt.Println("request", p.id, block.Number, block.haveHeaders) - amount := block.Number - block.haveHeaders - if amount == 0 { - return - } - if amount > 100 { - f.syncing = true - go func() { - //fmt.Println("f.pm.synchronise(p)") - f.pm.synchronise(p) - //fmt.Println("sync done") - f.syncDone <- struct{}{} - }() - return - } - - reqID := f.odr.getNextReqID() - f.reqMu.Lock() - f.requested[reqID] = fetchRequest{hash: block.Hash, amount: amount, peer: p} - f.reqMu.Unlock() - cost := p.GetRequestCost(GetBlockHeadersMsg, int(amount)) - p.fcServer.SendRequest(reqID, cost) - go p.RequestHeadersByHash(reqID, cost, block.Hash, int(amount), 0, true) - go func() { - time.Sleep(hardRequestTimeout) - f.timeoutChn <- reqID - }() -} - -func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) bool { - if uint64(len(resp.headers)) != req.amount || resp.headers[0].Hash() != req.hash { - return false - } - headers := make([]*types.Header, req.amount) - for i, header := range resp.headers { - headers[int(req.amount)-1-i] = header - } - if _, err := f.chain.InsertHeaderChain(headers, 1); err != nil { - return false - } - for _, header := range headers { - td := core.GetTd(f.pm.chainDb, header.Hash(), header.Number.Uint64()) - if td == nil { - return false - } - if td.Cmp(f.currentTd) > 0 { - f.currentTd = td - } - f.gotHeader(header) - } - return true -} - -func (f *lightFetcher) checkSyncedHeaders() { - //fmt.Println("checkSyncedHeaders()") - for _, peer := range f.pm.peers.AllPeers() { - peer.lock.Lock() - h := peer.firstHeadInfo - remove := false - loop: - for h != nil { - if td := core.GetTd(f.pm.chainDb, h.Hash, h.Number); td != nil { - //fmt.Println(" found", h.Number) - ok := peer.gotHeader(h.Hash, h.Number, td) - if !ok { - remove = true - break loop - } - if td.Cmp(f.currentTd) > 0 { - f.currentTd = td - } - } - h = h.next - } - peer.lock.Unlock() - if remove { - //fmt.Println("checkSync fail") - f.pm.removePeer(peer.id) - } - } -} - +// syncLoop is the main event loop of the light fetcher func (f *lightFetcher) syncLoop() { f.pm.wg.Add(1) defer f.pm.wg.Done() - srtoNotify := false + requesting := false for { select { case <-f.pm.quitSync: return - case ext := <-f.notifyChn: - //fmt.Println("<-f.notifyChn", f.syncing, ext, srtoNotify) - s := srtoNotify - srtoNotify = false - if !f.syncing && !(ext && s) { - if p, r := f.nextRequest(); r != nil { - srtoNotify = true - go func() { - time.Sleep(softRequestTimeout) - f.notifyChn <- false - }() - f.request(p, r) + // when a new announce is received, request loop keeps running until + // no further requests are necessary or possible + case newAnnounce := <-f.requestChn: + f.lock.Lock() + s := requesting + requesting = false + if !f.syncing && !(newAnnounce && s) { + reqID := getNextReqID() + if peer, node, amount, retry := f.nextRequest(reqID); node != nil { + requesting = true + if reqID, ok := f.request(peer, reqID, node, amount); ok { + go func() { + time.Sleep(softRequestTimeout) + f.reqMu.Lock() + req, ok := f.requested[reqID] + if ok { + req.timeout = true + f.requested[reqID] = req + } + f.reqMu.Unlock() + // keep starting new requests while possible + f.requestChn <- false + }() + } + } else { + if retry { + requesting = true + go func() { + time.Sleep(time.Millisecond * 100) + f.requestChn <- false + }() + } } } + f.lock.Unlock() case reqID := <-f.timeoutChn: f.reqMu.Lock() req, ok := f.requested[reqID] @@ -273,23 +173,547 @@ func (f *lightFetcher) syncLoop() { } f.reqMu.Unlock() if ok { - //fmt.Println("hard timeout") - f.pm.removePeer(req.peer.id) + f.pm.serverPool.adjustResponseTime(req.peer.poolEntry, time.Duration(mclock.Now()-req.sent), true) + glog.V(logger.Debug).Infof("hard timeout by peer %v", req.peer.id) + go f.pm.removePeer(req.peer.id) } case resp := <-f.deliverChn: - //fmt.Println("<-f.deliverChn", f.syncing) f.reqMu.Lock() req, ok := f.requested[resp.reqID] - delete(f.requested, resp.reqID) - f.reqMu.Unlock() - if !ok || !(f.syncing || f.processResponse(req, resp)) { - //fmt.Println("processResponse fail") - f.pm.removePeer(req.peer.id) + if ok && req.peer != resp.peer { + ok = false } - case <-f.syncDone: - //fmt.Println("<-f.syncDone", f.syncing) - f.checkSyncedHeaders() + if ok { + delete(f.requested, resp.reqID) + } + f.reqMu.Unlock() + if ok { + f.pm.serverPool.adjustResponseTime(req.peer.poolEntry, time.Duration(mclock.Now()-req.sent), req.timeout) + } + f.lock.Lock() + if !ok || !(f.syncing || f.processResponse(req, resp)) { + glog.V(logger.Debug).Infof("failed processing response by peer %v", resp.peer.id) + go f.pm.removePeer(resp.peer.id) + } + f.lock.Unlock() + case p := <-f.syncDone: + f.lock.Lock() + glog.V(logger.Debug).Infof("done synchronising with peer %v", p.id) + f.checkSyncedHeaders(p) f.syncing = false + f.lock.Unlock() + } + } +} + +// addPeer adds a new peer to the fetcher's peer set +func (f *lightFetcher) addPeer(p *peer) { + p.lock.Lock() + p.hasBlock = func(hash common.Hash, number uint64) bool { + return f.peerHasBlock(p, hash, number) + } + p.lock.Unlock() + + f.lock.Lock() + defer f.lock.Unlock() + + f.peers[p] = &fetcherPeerInfo{nodeByHash: make(map[common.Hash]*fetcherTreeNode)} +} + +// removePeer removes a new peer from the fetcher's peer set +func (f *lightFetcher) removePeer(p *peer) { + p.lock.Lock() + p.hasBlock = nil + p.lock.Unlock() + + f.lock.Lock() + defer f.lock.Unlock() + + // check for potential timed out block delay statistics + f.checkUpdateStats(p, nil) + delete(f.peers, p) +} + +// announce processes a new announcement message received from a peer, adding new +// nodes to the peer's block tree and removing old nodes if necessary +func (f *lightFetcher) announce(p *peer, head *announceData) { + f.lock.Lock() + defer f.lock.Unlock() + glog.V(logger.Debug).Infof("received announce from peer %v #%d %016x reorg: %d", p.id, head.Number, head.Hash[:8], head.ReorgDepth) + + fp := f.peers[p] + if fp == nil { + glog.V(logger.Debug).Infof("announce: unknown peer") + return + } + + if fp.lastAnnounced != nil && head.Td.Cmp(fp.lastAnnounced.td) <= 0 { + // announced tds should be strictly monotonic + glog.V(logger.Debug).Infof("non-monotonic Td from peer %v", p.id) + go f.pm.removePeer(p.id) + return + } + + n := fp.lastAnnounced + for i := uint64(0); i < head.ReorgDepth; i++ { + if n == nil { + break + } + n = n.parent + } + if n != nil { + // n is now the reorg common ancestor, add a new branch of nodes + // check if the node count is too high to add new nodes + locked := false + for uint64(fp.nodeCnt)+head.Number-n.number > maxNodeCount && fp.root != nil { + if !locked { + f.chain.LockChain() + defer f.chain.UnlockChain() + locked = true + } + // if one of root's children is canonical, keep it, delete other branches and root itself + var newRoot *fetcherTreeNode + for i, nn := range fp.root.children { + if core.GetCanonicalHash(f.pm.chainDb, nn.number) == nn.hash { + fp.root.children = append(fp.root.children[:i], fp.root.children[i+1:]...) + nn.parent = nil + newRoot = nn + break + } + } + fp.deleteNode(fp.root) + if n == fp.root { + n = newRoot + } + fp.root = newRoot + if newRoot == nil || !f.checkKnownNode(p, newRoot) { + fp.bestConfirmed = nil + fp.confirmedTd = nil + } + + if n == nil { + break + } + } + if n != nil { + for n.number < head.Number { + nn := &fetcherTreeNode{number: n.number + 1, parent: n} + n.children = append(n.children, nn) + n = nn + fp.nodeCnt++ + } + n.hash = head.Hash + n.td = head.Td + fp.nodeByHash[n.hash] = n + } + } + if n == nil { + // could not find reorg common ancestor or had to delete entire tree, a new root and a resync is needed + if fp.root != nil { + fp.deleteNode(fp.root) + } + n = &fetcherTreeNode{hash: head.Hash, number: head.Number, td: head.Td} + fp.root = n + fp.nodeCnt++ + fp.nodeByHash[n.hash] = n + fp.bestConfirmed = nil + fp.confirmedTd = nil + } + + f.checkKnownNode(p, n) + p.lock.Lock() + p.headInfo = head + fp.lastAnnounced = n + p.lock.Unlock() + f.checkUpdateStats(p, nil) + f.requestChn <- true +} + +// peerHasBlock returns true if we can assume the peer knows the given block +// based on its announcements +func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bool { + f.lock.Lock() + defer f.lock.Unlock() + + fp := f.peers[p] + if fp == nil || fp.root == nil { + return false + } + + if number >= fp.root.number { + // it is recent enough that if it is known, is should be in the peer's block tree + return fp.nodeByHash[hash] != nil + } + f.chain.LockChain() + defer f.chain.UnlockChain() + // if it's older than the peer's block tree root but it's in the same canonical chain + // than the root, we can still be sure the peer knows it + return core.GetCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && core.GetCanonicalHash(f.pm.chainDb, number) == hash +} + +// request initiates a header download request from a certain peer +func (f *lightFetcher) request(p *peer, reqID uint64, n *fetcherTreeNode, amount uint64) (uint64, bool) { + fp := f.peers[p] + if fp == nil { + glog.V(logger.Debug).Infof("request: unknown peer") + p.fcServer.DeassignRequest(reqID) + return 0, false + } + if fp.bestConfirmed == nil || fp.root == nil || !f.checkKnownNode(p, fp.root) { + f.syncing = true + go func() { + glog.V(logger.Debug).Infof("synchronising with peer %v", p.id) + f.pm.synchronise(p) + f.syncDone <- p + }() + p.fcServer.DeassignRequest(reqID) + return 0, false + } + + n.requested = true + cost := p.GetRequestCost(GetBlockHeadersMsg, int(amount)) + p.fcServer.SendRequest(reqID, cost) + f.reqMu.Lock() + f.requested[reqID] = fetchRequest{hash: n.hash, amount: amount, peer: p, sent: mclock.Now()} + f.reqMu.Unlock() + go p.RequestHeadersByHash(reqID, cost, n.hash, int(amount), 0, true) + go func() { + time.Sleep(hardRequestTimeout) + f.timeoutChn <- reqID + }() + return reqID, true +} + +// requestAmount calculates the amount of headers to be downloaded starting +// from a certain head backwards +func (f *lightFetcher) requestAmount(p *peer, n *fetcherTreeNode) uint64 { + amount := uint64(0) + nn := n + for nn != nil && !f.checkKnownNode(p, nn) { + nn = nn.parent + amount++ + } + if nn == nil { + amount = n.number + } + return amount +} + +// requestedID tells if a certain reqID has been requested by the fetcher +func (f *lightFetcher) requestedID(reqID uint64) bool { + f.reqMu.RLock() + _, ok := f.requested[reqID] + f.reqMu.RUnlock() + return ok +} + +// nextRequest selects the peer and announced head to be requested next, amount +// to be downloaded starting from the head backwards is also returned +func (f *lightFetcher) nextRequest(reqID uint64) (*peer, *fetcherTreeNode, uint64, bool) { + var ( + bestHash common.Hash + bestAmount uint64 + ) + bestTd := f.maxConfirmedTd + + for p, fp := range f.peers { + for hash, n := range fp.nodeByHash { + if !f.checkKnownNode(p, n) && !n.requested && (bestTd == nil || n.td.Cmp(bestTd) >= 0) { + amount := f.requestAmount(p, n) + if bestTd == nil || n.td.Cmp(bestTd) > 0 || amount < bestAmount { + bestHash = hash + bestAmount = amount + bestTd = n.td + } + } + } + } + if bestTd == f.maxConfirmedTd { + return nil, nil, 0, false + } + + peer, _, locked := f.pm.serverPool.selectPeer(reqID, func(p *peer) (bool, time.Duration) { + fp := f.peers[p] + if fp == nil || fp.nodeByHash[bestHash] == nil { + return false, 0 + } + return true, p.fcServer.CanSend(p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount))) + }) + if !locked { + return nil, nil, 0, true + } + var node *fetcherTreeNode + if peer != nil { + node = f.peers[peer].nodeByHash[bestHash] + } + return peer, node, bestAmount, false +} + +// deliverHeaders delivers header download request responses for processing +func (f *lightFetcher) deliverHeaders(peer *peer, reqID uint64, headers []*types.Header) { + f.deliverChn <- fetchResponse{reqID: reqID, headers: headers, peer: peer} +} + +// processResponse processes header download request responses, returns true if successful +func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) bool { + if uint64(len(resp.headers)) != req.amount || resp.headers[0].Hash() != req.hash { + glog.V(logger.Debug).Infof("response mismatch %v %016x != %v %016x", len(resp.headers), resp.headers[0].Hash().Bytes()[:8], req.amount, req.hash[:8]) + return false + } + headers := make([]*types.Header, req.amount) + for i, header := range resp.headers { + headers[int(req.amount)-1-i] = header + } + if _, err := f.chain.InsertHeaderChain(headers, 1); err != nil { + if err == core.BlockFutureErr { + return true + } + glog.V(logger.Debug).Infof("InsertHeaderChain error: %v", err) + return false + } + tds := make([]*big.Int, len(headers)) + for i, header := range headers { + td := f.chain.GetTd(header.Hash(), header.Number.Uint64()) + if td == nil { + glog.V(logger.Debug).Infof("TD not found for header %v of %v", i+1, len(headers)) + return false + } + tds[i] = td + } + f.newHeaders(headers, tds) + return true +} + +// newHeaders updates the block trees of all active peers according to a newly +// downloaded and validated batch or headers +func (f *lightFetcher) newHeaders(headers []*types.Header, tds []*big.Int) { + var maxTd *big.Int + for p, fp := range f.peers { + if !f.checkAnnouncedHeaders(fp, headers, tds) { + glog.V(logger.Debug).Infof("announce inconsistency by peer %v", p.id) + go f.pm.removePeer(p.id) + } + if fp.confirmedTd != nil && (maxTd == nil || maxTd.Cmp(fp.confirmedTd) > 0) { + maxTd = fp.confirmedTd + } + } + if maxTd != nil { + f.updateMaxConfirmedTd(maxTd) + } +} + +// checkAnnouncedHeaders updates peer's block tree if necessary after validating +// a batch of headers. It searches for the latest header in the batch that has a +// matching tree node (if any), and if it has not been marked as known already, +// sets it and its parents to known (even those which are older than the currently +// validated ones). Return value shows if all hashes, numbers and Tds matched +// correctly to the announced values (otherwise the peer should be dropped). +func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*types.Header, tds []*big.Int) bool { + var ( + n *fetcherTreeNode + header *types.Header + td *big.Int + ) + + for i := len(headers) - 1; ; i-- { + if i < 0 { + if n == nil { + // no more headers and nothing to match + return true + } + // we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching + td = f.chain.GetTd(header.ParentHash, header.Number.Uint64()-1) + header = f.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) + } else { + header = headers[i] + td = tds[i] + } + hash := header.Hash() + number := header.Number.Uint64() + if n == nil { + n = fp.nodeByHash[hash] + } + if n != nil { + if n.td == nil { + // node was unannounced + if nn := fp.nodeByHash[hash]; nn != nil { + // if there was already a node with the same hash, continue there and drop this one + nn.children = append(nn.children, n.children...) + n.children = nil + fp.deleteNode(n) + n = nn + } else { + n.hash = hash + n.td = td + fp.nodeByHash[hash] = n + } + } + // check if it matches the header + if n.hash != hash || n.number != number || n.td.Cmp(td) != 0 { + // peer has previously made an invalid announcement + return false + } + if n.known { + // we reached a known node that matched our expectations, return with success + return true + } + n.known = true + if fp.confirmedTd == nil || td.Cmp(fp.confirmedTd) > 0 { + fp.confirmedTd = td + fp.bestConfirmed = n + } + n = n.parent + if n == nil { + return true + } + } + } +} + +// checkSyncedHeaders updates peer's block tree after synchronisation by marking +// downloaded headers as known. If none of the announced headers are found after +// syncing, the peer is dropped. +func (f *lightFetcher) checkSyncedHeaders(p *peer) { + fp := f.peers[p] + if fp == nil { + glog.V(logger.Debug).Infof("checkSyncedHeaders: unknown peer") + return + } + n := fp.lastAnnounced + var td *big.Int + for n != nil { + if td = f.chain.GetTd(n.hash, n.number); td != nil { + break + } + n = n.parent + } + // now n is the latest downloaded header after syncing + if n == nil { + glog.V(logger.Debug).Infof("synchronisation failed with peer %v", p.id) + go f.pm.removePeer(p.id) + } else { + header := f.chain.GetHeader(n.hash, n.number) + f.newHeaders([]*types.Header{header}, []*big.Int{td}) + } +} + +// checkKnownNode checks if a block tree node is known (downloaded and validated) +// If it was not known previously but found in the database, sets its known flag +func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool { + if n.known { + return true + } + td := f.chain.GetTd(n.hash, n.number) + if td == nil { + return false + } + + fp := f.peers[p] + if fp == nil { + glog.V(logger.Debug).Infof("checkKnownNode: unknown peer") + return false + } + header := f.chain.GetHeader(n.hash, n.number) + if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) { + glog.V(logger.Debug).Infof("announce inconsistency by peer %v", p.id) + go f.pm.removePeer(p.id) + } + if fp.confirmedTd != nil { + f.updateMaxConfirmedTd(fp.confirmedTd) + } + return n.known +} + +// deleteNode deletes a node and its child subtrees from a peer's block tree +func (fp *fetcherPeerInfo) deleteNode(n *fetcherTreeNode) { + if n.parent != nil { + for i, nn := range n.parent.children { + if nn == n { + n.parent.children = append(n.parent.children[:i], n.parent.children[i+1:]...) + break + } + } + } + for { + if n.td != nil { + delete(fp.nodeByHash, n.hash) + } + fp.nodeCnt-- + if len(n.children) == 0 { + return + } + for i, nn := range n.children { + if i == 0 { + n = nn + } else { + fp.deleteNode(nn) + } + } + } +} + +// updateStatsEntry items form a linked list that is expanded with a new item every time a new head with a higher Td +// than the previous one has been downloaded and validated. The list contains a series of maximum confirmed Td values +// and the time these values have been confirmed, both increasing monotonically. A maximum confirmed Td is calculated +// both globally for all peers and also for each individual peer (meaning that the given peer has announced the head +// and it has also been downloaded from any peer, either before or after the given announcement). +// The linked list has a global tail where new confirmed Td entries are added and a separate head for each peer, +// pointing to the next Td entry that is higher than the peer's max confirmed Td (nil if it has already confirmed +// the current global head). +type updateStatsEntry struct { + time mclock.AbsTime + td *big.Int + next *updateStatsEntry +} + +// updateMaxConfirmedTd updates the block delay statistics of active peers. Whenever a new highest Td is confirmed, +// adds it to the end of a linked list together with the time it has been confirmed. Then checks which peers have +// already confirmed a head with the same or higher Td (which counts as zero block delay) and updates their statistics. +// Those who have not confirmed such a head by now will be updated by a subsequent checkUpdateStats call with a +// positive block delay value. +func (f *lightFetcher) updateMaxConfirmedTd(td *big.Int) { + if f.maxConfirmedTd == nil || td.Cmp(f.maxConfirmedTd) > 0 { + f.maxConfirmedTd = td + newEntry := &updateStatsEntry{ + time: mclock.Now(), + td: td, + } + if f.lastUpdateStats != nil { + f.lastUpdateStats.next = newEntry + } + f.lastUpdateStats = newEntry + for p := range f.peers { + f.checkUpdateStats(p, newEntry) + } + } +} + +// checkUpdateStats checks those peers who have not confirmed a certain highest Td (or a larger one) by the time it +// has been confirmed by another peer. If they have confirmed such a head by now, their stats are updated with the +// block delay which is (this peer's confirmation time)-(first confirmation time). After blockDelayTimeout has passed, +// the stats are updated with blockDelayTimeout value. In either case, the confirmed or timed out updateStatsEntry +// items are removed from the head of the linked list. +// If a new entry has been added to the global tail, it is passed as a parameter here even though this function +// assumes that it has already been added, so that if the peer's list is empty (all heads confirmed, head is nil), +// it can set the new head to newEntry. +func (f *lightFetcher) checkUpdateStats(p *peer, newEntry *updateStatsEntry) { + now := mclock.Now() + fp := f.peers[p] + if fp == nil { + glog.V(logger.Debug).Infof("checkUpdateStats: unknown peer") + return + } + if newEntry != nil && fp.firstUpdateStats == nil { + fp.firstUpdateStats = newEntry + } + for fp.firstUpdateStats != nil && fp.firstUpdateStats.time <= now-mclock.AbsTime(blockDelayTimeout) { + f.pm.serverPool.adjustBlockDelay(p.poolEntry, blockDelayTimeout) + fp.firstUpdateStats = fp.firstUpdateStats.next + } + if fp.confirmedTd != nil { + for fp.firstUpdateStats != nil && fp.firstUpdateStats.td.Cmp(fp.confirmedTd) <= 0 { + f.pm.serverPool.adjustBlockDelay(p.poolEntry, time.Duration(now-fp.firstUpdateStats.time)) + fp.firstUpdateStats = fp.firstUpdateStats.next } } } diff --git a/les/flowcontrol/control.go b/les/flowcontrol/control.go index b6c423f617..c7eb3e487f 100644 --- a/les/flowcontrol/control.go +++ b/les/flowcontrol/control.go @@ -24,7 +24,7 @@ import ( "github.com/ubiq/go-ubiq/common/mclock" ) -const fcTimeConst = 1000000 +const fcTimeConst = time.Millisecond type ServerParams struct { BufLimit, MinRecharge uint64 @@ -33,7 +33,7 @@ type ServerParams struct { type ClientNode struct { params *ServerParams bufValue uint64 - lastTime int64 + lastTime mclock.AbsTime lock sync.Mutex cm *ClientManager cmNode *cmNode @@ -44,7 +44,7 @@ func NewClientNode(cm *ClientManager, params *ServerParams) *ClientNode { cm: cm, params: params, bufValue: params.BufLimit, - lastTime: getTime(), + lastTime: mclock.Now(), } node.cmNode = cm.addNode(node) return node @@ -54,12 +54,12 @@ func (peer *ClientNode) Remove(cm *ClientManager) { cm.removeNode(peer.cmNode) } -func (peer *ClientNode) recalcBV(time int64) { +func (peer *ClientNode) recalcBV(time mclock.AbsTime) { dt := uint64(time - peer.lastTime) if time < peer.lastTime { dt = 0 } - peer.bufValue += peer.params.MinRecharge * dt / fcTimeConst + peer.bufValue += peer.params.MinRecharge * dt / uint64(fcTimeConst) if peer.bufValue > peer.params.BufLimit { peer.bufValue = peer.params.BufLimit } @@ -70,7 +70,7 @@ func (peer *ClientNode) AcceptRequest() (uint64, bool) { peer.lock.Lock() defer peer.lock.Unlock() - time := getTime() + time := mclock.Now() peer.recalcBV(time) return peer.bufValue, peer.cm.accept(peer.cmNode, time) } @@ -79,7 +79,7 @@ func (peer *ClientNode) RequestProcessed(cost uint64) (bv, realCost uint64) { peer.lock.Lock() defer peer.lock.Unlock() - time := getTime() + time := mclock.Now() peer.recalcBV(time) peer.bufValue -= cost peer.recalcBV(time) @@ -94,66 +94,127 @@ func (peer *ClientNode) RequestProcessed(cost uint64) (bv, realCost uint64) { } type ServerNode struct { - bufEstimate uint64 - lastTime int64 - params *ServerParams - sumCost uint64 // sum of req costs sent to this server - pending map[uint64]uint64 // value = sumCost after sending the given req - lock sync.RWMutex + bufEstimate uint64 + lastTime mclock.AbsTime + params *ServerParams + sumCost uint64 // sum of req costs sent to this server + pending map[uint64]uint64 // value = sumCost after sending the given req + assignedRequest uint64 // when != 0, only the request with the given ID can be sent to this peer + assignToken chan struct{} // send to this channel before assigning, read from it after deassigning + lock sync.RWMutex } func NewServerNode(params *ServerParams) *ServerNode { return &ServerNode{ bufEstimate: params.BufLimit, - lastTime: getTime(), + lastTime: mclock.Now(), params: params, pending: make(map[uint64]uint64), + assignToken: make(chan struct{}, 1), } } -func getTime() int64 { - return int64(mclock.Now()) -} - -func (peer *ServerNode) recalcBLE(time int64) { +func (peer *ServerNode) recalcBLE(time mclock.AbsTime) { dt := uint64(time - peer.lastTime) if time < peer.lastTime { dt = 0 } - peer.bufEstimate += peer.params.MinRecharge * dt / fcTimeConst + peer.bufEstimate += peer.params.MinRecharge * dt / uint64(fcTimeConst) if peer.bufEstimate > peer.params.BufLimit { peer.bufEstimate = peer.params.BufLimit } peer.lastTime = time } -func (peer *ServerNode) canSend(maxCost uint64) uint64 { +// safetyMargin is added to the flow control waiting time when estimated buffer value is low +const safetyMargin = time.Millisecond * 200 + +func (peer *ServerNode) canSend(maxCost uint64) time.Duration { + maxCost += uint64(safetyMargin) * peer.params.MinRecharge / uint64(fcTimeConst) + if maxCost > peer.params.BufLimit { + maxCost = peer.params.BufLimit + } if peer.bufEstimate >= maxCost { return 0 } - return (maxCost - peer.bufEstimate) * fcTimeConst / peer.params.MinRecharge + return time.Duration((maxCost - peer.bufEstimate) * uint64(fcTimeConst) / peer.params.MinRecharge) } -func (peer *ServerNode) CanSend(maxCost uint64) uint64 { +// CanSend returns the minimum waiting time required before sending a request +// with the given maximum estimated cost +func (peer *ServerNode) CanSend(maxCost uint64) time.Duration { peer.lock.RLock() defer peer.lock.RUnlock() return peer.canSend(maxCost) } +// AssignRequest tries to assign the server node to the given request, guaranteeing +// that once it returns true, no request will be sent to the node before this one +func (peer *ServerNode) AssignRequest(reqID uint64) bool { + select { + case peer.assignToken <- struct{}{}: + default: + return false + } + peer.lock.Lock() + peer.assignedRequest = reqID + peer.lock.Unlock() + return true +} + +// MustAssignRequest waits until the node can be assigned to the given request. +// It is always guaranteed that assignments are released in a short amount of time. +func (peer *ServerNode) MustAssignRequest(reqID uint64) { + peer.assignToken <- struct{}{} + peer.lock.Lock() + peer.assignedRequest = reqID + peer.lock.Unlock() +} + +// DeassignRequest releases a request assignment in case the planned request +// is not being sent. +func (peer *ServerNode) DeassignRequest(reqID uint64) { + peer.lock.Lock() + if peer.assignedRequest == reqID { + peer.assignedRequest = 0 + <-peer.assignToken + } + peer.lock.Unlock() +} + +// IsAssigned returns true if the server node has already been assigned to a request +// (note that this function returning false does not guarantee that you can assign a request +// immediately afterwards, its only purpose is to help peer selection) +func (peer *ServerNode) IsAssigned() bool { + peer.lock.RLock() + locked := peer.assignedRequest != 0 + peer.lock.RUnlock() + return locked +} + // blocks until request can be sent func (peer *ServerNode) SendRequest(reqID, maxCost uint64) { peer.lock.Lock() defer peer.lock.Unlock() - peer.recalcBLE(getTime()) - for peer.bufEstimate < maxCost { - wait := time.Duration(peer.canSend(maxCost)) + if peer.assignedRequest != reqID { + peer.lock.Unlock() + peer.MustAssignRequest(reqID) + peer.lock.Lock() + } + + peer.recalcBLE(mclock.Now()) + wait := peer.canSend(maxCost) + for wait > 0 { peer.lock.Unlock() time.Sleep(wait) peer.lock.Lock() - peer.recalcBLE(getTime()) + peer.recalcBLE(mclock.Now()) + wait = peer.canSend(maxCost) } + peer.assignedRequest = 0 + <-peer.assignToken peer.bufEstimate -= maxCost peer.sumCost += maxCost if reqID >= 0 { @@ -162,14 +223,18 @@ func (peer *ServerNode) SendRequest(reqID, maxCost uint64) { } func (peer *ServerNode) GotReply(reqID, bv uint64) { + peer.lock.Lock() defer peer.lock.Unlock() + if bv > peer.params.BufLimit { + bv = peer.params.BufLimit + } sc, ok := peer.pending[reqID] if !ok { return } delete(peer.pending, reqID) peer.bufEstimate = bv - (peer.sumCost - sc) - peer.lastTime = getTime() + peer.lastTime = mclock.Now() } diff --git a/les/flowcontrol/manager.go b/les/flowcontrol/manager.go index 786884437b..95dba47907 100644 --- a/les/flowcontrol/manager.go +++ b/les/flowcontrol/manager.go @@ -20,22 +20,23 @@ package flowcontrol import ( "sync" "time" + + "github.com/ubiq/go-ubiq/common/mclock" ) const rcConst = 1000000 type cmNode struct { - node *ClientNode - lastUpdate int64 - reqAccepted int64 - serving, recharging bool - rcWeight uint64 - rcValue, rcDelta int64 - finishRecharge, startValue int64 + node *ClientNode + lastUpdate mclock.AbsTime + serving, recharging bool + rcWeight uint64 + rcValue, rcDelta, startValue int64 + finishRecharge mclock.AbsTime } -func (node *cmNode) update(time int64) { - dt := time - node.lastUpdate +func (node *cmNode) update(time mclock.AbsTime) { + dt := int64(time - node.lastUpdate) node.rcValue += node.rcDelta * dt / rcConst node.lastUpdate = time if node.recharging && time >= node.finishRecharge { @@ -62,7 +63,7 @@ func (node *cmNode) set(serving bool, simReqCnt, sumWeight uint64) { } if node.recharging { node.rcDelta = -int64(node.node.cm.rcRecharge * node.rcWeight / sumWeight) - node.finishRecharge = node.lastUpdate + node.rcValue*rcConst/(-node.rcDelta) + node.finishRecharge = node.lastUpdate + mclock.AbsTime(node.rcValue*rcConst/(-node.rcDelta)) } } @@ -73,7 +74,7 @@ type ClientManager struct { maxSimReq, maxRcSum uint64 rcRecharge uint64 resumeQueue chan chan bool - time int64 + time mclock.AbsTime } func NewClientManager(rcTarget, maxSimReq, maxRcSum uint64) *ClientManager { @@ -98,7 +99,7 @@ func (self *ClientManager) Stop() { } func (self *ClientManager) addNode(cnode *ClientNode) *cmNode { - time := getTime() + time := mclock.Now() node := &cmNode{ node: cnode, lastUpdate: time, @@ -109,7 +110,7 @@ func (self *ClientManager) addNode(cnode *ClientNode) *cmNode { defer self.lock.Unlock() self.nodes[node] = struct{}{} - self.update(getTime()) + self.update(mclock.Now()) return node } @@ -117,16 +118,16 @@ func (self *ClientManager) removeNode(node *cmNode) { self.lock.Lock() defer self.lock.Unlock() - time := getTime() + time := mclock.Now() self.stop(node, time) delete(self.nodes, node) self.update(time) } // recalc sumWeight -func (self *ClientManager) updateNodes(time int64) (rce bool) { +func (self *ClientManager) updateNodes(time mclock.AbsTime) (rce bool) { var sumWeight, rcSum uint64 - for node, _ := range self.nodes { + for node := range self.nodes { rc := node.recharging node.update(time) if rc && !node.recharging { @@ -142,16 +143,16 @@ func (self *ClientManager) updateNodes(time int64) (rce bool) { return } -func (self *ClientManager) update(time int64) { +func (self *ClientManager) update(time mclock.AbsTime) { for { firstTime := time - for node, _ := range self.nodes { + for node := range self.nodes { if node.recharging && node.finishRecharge < firstTime { firstTime = node.finishRecharge } } if self.updateNodes(firstTime) { - for node, _ := range self.nodes { + for node := range self.nodes { if node.recharging { node.set(node.serving, self.simReqCnt, self.sumWeight) } @@ -172,7 +173,7 @@ func (self *ClientManager) queueProc() { for { time.Sleep(time.Millisecond * 10) self.lock.Lock() - self.update(getTime()) + self.update(mclock.Now()) cs := self.canStartReq() self.lock.Unlock() if cs { @@ -183,7 +184,7 @@ func (self *ClientManager) queueProc() { } } -func (self *ClientManager) accept(node *cmNode, time int64) bool { +func (self *ClientManager) accept(node *cmNode, time mclock.AbsTime) bool { self.lock.Lock() defer self.lock.Unlock() @@ -205,7 +206,7 @@ func (self *ClientManager) accept(node *cmNode, time int64) bool { return true } -func (self *ClientManager) stop(node *cmNode, time int64) { +func (self *ClientManager) stop(node *cmNode, time mclock.AbsTime) { if node.serving { self.update(time) self.simReqCnt-- @@ -214,7 +215,7 @@ func (self *ClientManager) stop(node *cmNode, time int64) { } } -func (self *ClientManager) processed(node *cmNode, time int64) (rcValue, rcCost uint64) { +func (self *ClientManager) processed(node *cmNode, time mclock.AbsTime) (rcValue, rcCost uint64) { self.lock.Lock() defer self.lock.Unlock() diff --git a/les/handler.go b/les/handler.go index a45206a5d5..f805661aec 100644 --- a/les/handler.go +++ b/les/handler.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "math/big" + "net" "sync" "time" @@ -58,7 +59,7 @@ const ( MaxHeaderProofsFetch = 64 // Amount of merkle proofs to be fetched per retrieval request MaxTxSend = 64 // Amount of transactions to be send per request - disableClientRemovePeer = true + disableClientRemovePeer = false ) // errIncompatibleConfig is returned if the requested protocols and configs are @@ -88,7 +89,7 @@ type BlockChain interface { type txPool interface { // AddTransactions should add the given transactions to the pool. - AddBatch([]*types.Transaction) + AddBatch([]*types.Transaction) error } type ProtocolManager struct { @@ -101,10 +102,7 @@ type ProtocolManager struct { chainDb ethdb.Database odr *LesOdr server *LesServer - - topicDisc *discv5.Network - lesTopic discv5.Topic - p2pServer *p2p.Server + serverPool *serverPool downloader *downloader.Downloader fetcher *lightFetcher @@ -157,13 +155,29 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, network Version: version, Length: ProtocolLengths[i], Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { + var entry *poolEntry peer := manager.newPeer(int(version), networkId, p, rw) + if manager.serverPool != nil { + addr := p.RemoteAddr().(*net.TCPAddr) + entry = manager.serverPool.connect(peer, addr.IP, uint16(addr.Port)) + if entry == nil { + return fmt.Errorf("unwanted connection") + } + } + peer.poolEntry = entry select { case manager.newPeerCh <- peer: manager.wg.Add(1) defer manager.wg.Done() - return manager.handle(peer) + err := manager.handle(peer) + if entry != nil { + manager.serverPool.disconnect(entry) + } + return err case <-manager.quitSync: + if entry != nil { + manager.serverPool.disconnect(entry) + } return p2p.DiscQuitting } }, @@ -192,7 +206,6 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, network manager.downloader = downloader.New(downloader.LightSync, chainDb, manager.eventMux, blockchain.HasHeader, nil, blockchain.GetHeaderByHash, nil, blockchain.CurrentHeader, nil, nil, nil, blockchain.GetTdByHash, blockchain.InsertHeaderChain, nil, nil, blockchain.Rollback, removePeer) - manager.fetcher = newLightFetcher(manager) } if odr != nil { @@ -216,19 +229,24 @@ func (pm *ProtocolManager) removePeer(id string) { if peer == nil { return } + if err := pm.peers.Unregister(id); err != nil { + if err == errNotRegistered { + return + } + glog.V(logger.Error).Infoln("Removal failed:", err) + } glog.V(logger.Debug).Infoln("Removing peer", id) // Unregister the peer from the downloader and Ethereum peer set glog.V(logger.Debug).Infof("LES: unregister peer %v", id) if pm.lightSync { pm.downloader.UnregisterPeer(id) - pm.odr.UnregisterPeer(peer) if pm.txrelay != nil { pm.txrelay.removePeer(id) } - } - if err := pm.peers.Unregister(id); err != nil { - glog.V(logger.Error).Infoln("Removal failed:", err) + if pm.fetcher != nil { + pm.fetcher.removePeer(peer) + } } // Hard disconnect at the networking layer if peer != nil { @@ -236,54 +254,26 @@ func (pm *ProtocolManager) removePeer(id string) { } } -func (pm *ProtocolManager) findServers() { - if pm.p2pServer == nil || pm.topicDisc == nil { - return - } - glog.V(logger.Debug).Infoln("Looking for topic", string(pm.lesTopic)) - enodes := make(chan string, 100) - stop := make(chan struct{}) - go pm.topicDisc.SearchTopic(pm.lesTopic, stop, enodes) - go func() { - added := make(map[string]bool) - for { - select { - case enode := <-enodes: - if !added[enode] { - glog.V(logger.Info).Infoln("Found LES server:", enode) - added[enode] = true - if node, err := discover.ParseNode(enode); err == nil { - pm.p2pServer.AddPeer(node) - } - } - case <-stop: - return - } - } - }() - select { - case <-time.After(time.Second * 20): - case <-pm.quitSync: - } - close(stop) -} - func (pm *ProtocolManager) Start(srvr *p2p.Server) { - pm.p2pServer = srvr + var topicDisc *discv5.Network if srvr != nil { - pm.topicDisc = srvr.DiscV5 + topicDisc = srvr.DiscV5 } - pm.lesTopic = discv5.Topic("LES@" + common.Bytes2Hex(pm.blockchain.Genesis().Hash().Bytes()[0:8])) + lesTopic := discv5.Topic("LES@" + common.Bytes2Hex(pm.blockchain.Genesis().Hash().Bytes()[0:8])) if pm.lightSync { // start sync handler - go pm.findServers() + if srvr != nil { // srvr is nil during testing + pm.serverPool = newServerPool(pm.chainDb, []byte("serverPool/"), srvr, lesTopic, pm.quitSync, &pm.wg) + pm.odr.serverPool = pm.serverPool + pm.fetcher = newLightFetcher(pm) + } go pm.syncer() } else { - if pm.topicDisc != nil { + if topicDisc != nil { go func() { - glog.V(logger.Debug).Infoln("Starting registering topic", string(pm.lesTopic)) - pm.topicDisc.RegisterTopic(pm.lesTopic, pm.quitSync) - glog.V(logger.Debug).Infoln("Stopped registering topic", string(pm.lesTopic)) + glog.V(logger.Info).Infoln("Starting registering topic", string(lesTopic)) + topicDisc.RegisterTopic(lesTopic, pm.quitSync) + glog.V(logger.Info).Infoln("Stopped registering topic", string(lesTopic)) }() } go func() { @@ -352,14 +342,16 @@ func (pm *ProtocolManager) handle(p *peer) error { glog.V(logger.Debug).Infof("LES: register peer %v", p.id) if pm.lightSync { requestHeadersByHash := func(origin common.Hash, amount int, skip int, reverse bool) error { - reqID := pm.odr.getNextReqID() + reqID := getNextReqID() cost := p.GetRequestCost(GetBlockHeadersMsg, amount) + p.fcServer.MustAssignRequest(reqID) p.fcServer.SendRequest(reqID, cost) return p.RequestHeadersByHash(reqID, cost, origin, amount, skip, reverse) } requestHeadersByNumber := func(origin uint64, amount int, skip int, reverse bool) error { - reqID := pm.odr.getNextReqID() + reqID := getNextReqID() cost := p.GetRequestCost(GetBlockHeadersMsg, amount) + p.fcServer.MustAssignRequest(reqID) p.fcServer.SendRequest(reqID, cost) return p.RequestHeadersByNumber(reqID, cost, origin, amount, skip, reverse) } @@ -367,12 +359,21 @@ func (pm *ProtocolManager) handle(p *peer) error { requestHeadersByHash, requestHeadersByNumber, nil, nil, nil); err != nil { return err } - pm.odr.RegisterPeer(p) if pm.txrelay != nil { pm.txrelay.addPeer(p) } - pm.fetcher.notify(p, nil) + p.lock.Lock() + head := p.headInfo + p.lock.Unlock() + if pm.fetcher != nil { + pm.fetcher.addPeer(p) + pm.fetcher.announce(p, head) + } + + if p.poolEntry != nil { + pm.serverPool.registered(p.poolEntry) + } } stop := make(chan struct{}) @@ -409,26 +410,23 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return err } - var costs *requestCosts - var reqCnt, maxReqs int - glog.V(logger.Debug).Infoln("msg:", msg.Code, msg.Size) - if rc, ok := p.fcCosts[msg.Code]; ok { // check if msg is a supported request type - costs = rc - if p.fcClient == nil { - return errResp(ErrRequestRejected, "") + + costs := p.fcCosts[msg.Code] + reject := func(reqCnt, maxCnt uint64) bool { + if p.fcClient == nil || reqCnt > maxCnt { + return true } - bv, ok := p.fcClient.AcceptRequest() - if !ok || bv < costs.baseCost { - return errResp(ErrRequestRejected, "") + bufValue, _ := p.fcClient.AcceptRequest() + cost := costs.baseCost + reqCnt*costs.reqCost + if cost > pm.server.defParams.BufLimit { + cost = pm.server.defParams.BufLimit } - maxReqs = 10000 - if bv < pm.server.defParams.BufLimit { - d := bv - costs.baseCost - if d/10000 < costs.reqCost { - maxReqs = int(d / costs.reqCost) - } + if cost > bufValue { + glog.V(logger.Error).Infof("Request from %v came %v too early", p.id, time.Duration((cost-bufValue)*1000000/pm.server.defParams.MinRecharge)) + return true } + return false } if msg.Size > ProtocolMaxMsgSize { @@ -454,7 +452,9 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "%v: %v", msg, err) } glog.V(logger.Detail).Infoln("AnnounceMsg:", req.Number, req.Hash, req.Td, req.ReorgDepth) - pm.fetcher.notify(p, &req) + if pm.fetcher != nil { + pm.fetcher.announce(p, &req) + } case GetBlockHeadersMsg: glog.V(logger.Debug).Infof("<=== GetBlockHeadersMsg from peer %v", p.id) @@ -468,7 +468,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } query := req.Query - if query.Amount > uint64(maxReqs) || query.Amount > MaxHeaderFetch { + if reject(query.Amount, MaxHeaderFetch) { return errResp(ErrRequestRejected, "") } @@ -552,8 +552,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "msg %v: %v", msg, err) } p.fcServer.GotReply(resp.ReqID, resp.BV) - if pm.fetcher.requestedID(resp.ReqID) { - pm.fetcher.deliverHeaders(resp.ReqID, resp.Headers) + if pm.fetcher != nil && pm.fetcher.requestedID(resp.ReqID) { + pm.fetcher.deliverHeaders(p, resp.ReqID, resp.Headers) } else { err := pm.downloader.DeliverHeaders(p.id, resp.Headers) if err != nil { @@ -576,8 +576,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { bytes int bodies []rlp.RawValue ) - reqCnt = len(req.Hashes) - if reqCnt > maxReqs || reqCnt > MaxBodyFetch { + reqCnt := len(req.Hashes) + if reject(uint64(reqCnt), MaxBodyFetch) { return errResp(ErrRequestRejected, "") } for _, hash := range req.Hashes { @@ -630,8 +630,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { bytes int data [][]byte ) - reqCnt = len(req.Reqs) - if reqCnt > maxReqs || reqCnt > MaxCodeFetch { + reqCnt := len(req.Reqs) + if reject(uint64(reqCnt), MaxCodeFetch) { return errResp(ErrRequestRejected, "") } for _, req := range req.Reqs { @@ -691,8 +691,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { bytes int receipts []rlp.RawValue ) - reqCnt = len(req.Hashes) - if reqCnt > maxReqs || reqCnt > MaxReceiptFetch { + reqCnt := len(req.Hashes) + if reject(uint64(reqCnt), MaxReceiptFetch) { return errResp(ErrRequestRejected, "") } for _, hash := range req.Hashes { @@ -754,8 +754,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { bytes int proofs proofsData ) - reqCnt = len(req.Reqs) - if reqCnt > maxReqs || reqCnt > MaxProofsFetch { + reqCnt := len(req.Reqs) + if reject(uint64(reqCnt), MaxProofsFetch) { return errResp(ErrRequestRejected, "") } for _, req := range req.Reqs { @@ -821,8 +821,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { bytes int proofs []ChtResp ) - reqCnt = len(req.Reqs) - if reqCnt > maxReqs || reqCnt > MaxHeaderProofsFetch { + reqCnt := len(req.Reqs) + if reject(uint64(reqCnt), MaxHeaderProofsFetch) { return errResp(ErrRequestRejected, "") } for _, req := range req.Reqs { @@ -875,11 +875,15 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&txs); err != nil { return errResp(ErrDecode, "msg %v: %v", msg, err) } - reqCnt = len(txs) - if reqCnt > maxReqs || reqCnt > MaxTxSend { + reqCnt := len(txs) + if reject(uint64(reqCnt), MaxTxSend) { return errResp(ErrRequestRejected, "") } - pm.txpool.AddBatch(txs) + + if err := pm.txpool.AddBatch(txs); err != nil { + return errResp(ErrUnexpectedResponse, "msg: %v", err) + } + _, rcost := p.fcClient.RequestProcessed(costs.baseCost + uint64(reqCnt)*costs.reqCost) pm.server.fcCostStats.update(msg.Code, uint64(reqCnt), rcost) diff --git a/les/handler_test.go b/les/handler_test.go index d887650bde..12b7c9e87e 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -49,7 +49,7 @@ func testGetBlockHeaders(t *testing.T, protocol int) { // Create a "random" unknown hash for testing var unknown common.Hash - for i, _ := range unknown { + for i := range unknown { unknown[i] = byte(i) } // Create a batch of tests for various scenarios @@ -189,17 +189,17 @@ func testGetBlockBodies(t *testing.T, protocol int) { //{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned {0, []common.Hash{bc.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable {0, []common.Hash{bc.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable - {0, []common.Hash{common.Hash{}}, []bool{false}, 0}, // A non existent block should not be returned + {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned // Existing and non-existing blocks interleaved should not cause problems {0, []common.Hash{ - common.Hash{}, + {}, bc.GetBlockByNumber(1).Hash(), - common.Hash{}, + {}, bc.GetBlockByNumber(10).Hash(), - common.Hash{}, + {}, bc.GetBlockByNumber(100).Hash(), - common.Hash{}, + {}, }, []bool{false, true, false, true, false, true, false}, 3}, } // Run each of the tests and verify the results against the chain @@ -312,7 +312,7 @@ func testGetProofs(t *testing.T, protocol int) { var proofreqs []ProofReq var proofs [][]rlp.RawValue - accounts := []common.Address{testBankAddress, acc1Addr, acc2Addr, common.Address{}} + accounts := []common.Address{testBankAddress, acc1Addr, acc2Addr, {}} for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ { header := bc.GetHeaderByNumber(i) root := header.Root diff --git a/les/helper_test.go b/les/helper_test.go index 1bb89cacb3..034b4f961f 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -25,6 +25,7 @@ import ( "math/big" "sync" "testing" + "time" "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/core" @@ -78,17 +79,17 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) nonce++ - tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key) + tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) @@ -98,7 +99,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -109,7 +110,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) block.AddTx(tx) } } @@ -216,7 +217,7 @@ func (p *testTxPool) GetTransactions() types.Transactions { // newTestTransaction create a new dummy transaction. func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) - tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from) + tx, _ = types.SignTx(tx, types.HomesteadSigner{}, from) return tx } @@ -334,3 +335,26 @@ func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, headNu func (p *testPeer) close() { p.app.Close() } + +type testServerPool struct { + peer *peer + lock sync.RWMutex +} + +func (p *testServerPool) setPeer(peer *peer) { + p.lock.Lock() + defer p.lock.Unlock() + + p.peer = peer +} + +func (p *testServerPool) selectPeerWait(uint64, func(*peer) (bool, time.Duration), <-chan struct{}) *peer { + p.lock.RLock() + defer p.lock.RUnlock() + + return p.peer +} + +func (p *testServerPool) adjustResponseTime(*poolEntry, time.Duration, bool) { + +} diff --git a/les/metrics.go b/les/metrics.go index faa714329d..ba6428ba3b 100644 --- a/les/metrics.go +++ b/les/metrics.go @@ -72,7 +72,7 @@ type meteredMsgReadWriter struct { } // newMeteredMsgWriter wraps a p2p MsgReadWriter with metering support. If the -// metrics system is disabled, this fucntion returns the original object. +// metrics system is disabled, this function returns the original object. func newMeteredMsgWriter(rw p2p.MsgReadWriter) p2p.MsgReadWriter { if !metrics.Enabled { return rw diff --git a/les/odr.go b/les/odr.go index a9b16efb3b..041cc9aee1 100644 --- a/les/odr.go +++ b/les/odr.go @@ -17,6 +17,8 @@ package les import ( + "crypto/rand" + "encoding/binary" "sync" "time" @@ -37,6 +39,11 @@ var ( // peerDropFn is a callback type for dropping a peer detected as malicious. type peerDropFn func(id string) +type odrPeerSelector interface { + selectPeerWait(uint64, func(*peer) (bool, time.Duration), <-chan struct{}) *peer + adjustResponseTime(*poolEntry, time.Duration, bool) +} + type LesOdr struct { light.OdrBackend db ethdb.Database @@ -44,15 +51,13 @@ type LesOdr struct { removePeer peerDropFn mlock, clock sync.Mutex sentReqs map[uint64]*sentReq - peers *odrPeerSet - lastReqID uint64 + serverPool odrPeerSelector } func NewLesOdr(db ethdb.Database) *LesOdr { return &LesOdr{ db: db, stop: make(chan struct{}), - peers: newOdrPeerSet(), sentReqs: make(map[uint64]*sentReq), } } @@ -77,16 +82,6 @@ type sentReq struct { answered chan struct{} // closed and set to nil when any peer answers it } -// RegisterPeer registers a new LES peer to the ODR capable peer set -func (self *LesOdr) RegisterPeer(p *peer) error { - return self.peers.register(p) -} - -// UnregisterPeer removes a peer from the ODR capable peer set -func (self *LesOdr) UnregisterPeer(p *peer) { - self.peers.unregister(p) -} - const ( MsgBlockBodies = iota MsgCode @@ -121,6 +116,7 @@ func (self *LesOdr) Deliver(peer *peer, msg *Msg) error { if req.valFunc(self.db, msg) { close(delivered) req.lock.Lock() + delete(req.sentTo, peer) if req.answered != nil { close(req.answered) req.answered = nil @@ -142,29 +138,27 @@ func (self *LesOdr) requestPeer(req *sentReq, peer *peer, delivered, timeout cha select { case <-delivered: - servTime := uint64(mclock.Now() - stime) - self.peers.updateTimeout(peer, false) - self.peers.updateServTime(peer, servTime) + if self.serverPool != nil { + self.serverPool.adjustResponseTime(peer.poolEntry, time.Duration(mclock.Now()-stime), false) + } return case <-time.After(softRequestTimeout): close(timeout) - if self.peers.updateTimeout(peer, true) { - self.removePeer(peer.id) - } case <-self.stop: return } select { case <-delivered: - servTime := uint64(mclock.Now() - stime) - self.peers.updateServTime(peer, servTime) - return case <-time.After(hardRequestTimeout): - self.removePeer(peer.id) + glog.V(logger.Debug).Infof("ODR hard request timeout from peer %v", peer.id) + go self.removePeer(peer.id) case <-self.stop: return } + if self.serverPool != nil { + self.serverPool.adjustResponseTime(peer.poolEntry, time.Duration(mclock.Now()-stime), true) + } } // networkRequest sends a request to known peers until an answer is received @@ -176,7 +170,7 @@ func (self *LesOdr) networkRequest(ctx context.Context, lreq LesOdrRequest) erro sentTo: make(map[*peer]chan struct{}), answered: answered, // reply delivered by any peer } - reqID := self.getNextReqID() + reqID := getNextReqID() self.mlock.Lock() self.sentReqs[reqID] = req self.mlock.Unlock() @@ -193,7 +187,16 @@ func (self *LesOdr) networkRequest(ctx context.Context, lreq LesOdrRequest) erro exclude := make(map[*peer]struct{}) for { - if peer := self.peers.bestPeer(lreq, exclude); peer == nil { + var p *peer + if self.serverPool != nil { + p = self.serverPool.selectPeerWait(reqID, func(p *peer) (bool, time.Duration) { + if _, ok := exclude[p]; ok || !lreq.CanSend(p) { + return false, 0 + } + return true, p.fcServer.CanSend(lreq.GetCost(p)) + }, ctx.Done()) + } + if p == nil { select { case <-ctx.Done(): return ctx.Err() @@ -202,17 +205,17 @@ func (self *LesOdr) networkRequest(ctx context.Context, lreq LesOdrRequest) erro case <-time.After(retryPeers): } } else { - exclude[peer] = struct{}{} + exclude[p] = struct{}{} delivered := make(chan struct{}) timeout := make(chan struct{}) req.lock.Lock() - req.sentTo[peer] = delivered + req.sentTo[p] = delivered req.lock.Unlock() reqWg.Add(1) - cost := lreq.GetCost(peer) - peer.fcServer.SendRequest(reqID, cost) - go self.requestPeer(req, peer, delivered, timeout, reqWg) - lreq.Request(reqID, peer) + cost := lreq.GetCost(p) + p.fcServer.SendRequest(reqID, cost) + go self.requestPeer(req, p, delivered, timeout, reqWg) + lreq.Request(reqID, p) select { case <-ctx.Done(): @@ -239,10 +242,8 @@ func (self *LesOdr) Retrieve(ctx context.Context, req light.OdrRequest) (err err return } -func (self *LesOdr) getNextReqID() uint64 { - self.clock.Lock() - defer self.clock.Unlock() - - self.lastReqID++ - return self.lastReqID +func getNextReqID() uint64 { + var rnd [8]byte + rand.Read(rnd[:]) + return binary.BigEndian.Uint64(rnd[:]) } diff --git a/les/odr_peerset.go b/les/odr_peerset.go deleted file mode 100644 index e9b7eec7ff..0000000000 --- a/les/odr_peerset.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package les - -import ( - "sync" -) - -const dropTimeoutRatio = 20 - -type odrPeerInfo struct { - reqTimeSum, reqTimeCnt, reqCnt, timeoutCnt uint64 -} - -// odrPeerSet represents the collection of active peer participating in the block -// download procedure. -type odrPeerSet struct { - peers map[*peer]*odrPeerInfo - lock sync.RWMutex -} - -// newPeerSet creates a new peer set top track the active download sources. -func newOdrPeerSet() *odrPeerSet { - return &odrPeerSet{ - peers: make(map[*peer]*odrPeerInfo), - } -} - -// Register injects a new peer into the working set, or returns an error if the -// peer is already known. -func (ps *odrPeerSet) register(p *peer) error { - ps.lock.Lock() - defer ps.lock.Unlock() - - if _, ok := ps.peers[p]; ok { - return errAlreadyRegistered - } - ps.peers[p] = &odrPeerInfo{} - return nil -} - -// Unregister removes a remote peer from the active set, disabling any further -// actions to/from that particular entity. -func (ps *odrPeerSet) unregister(p *peer) error { - ps.lock.Lock() - defer ps.lock.Unlock() - - if _, ok := ps.peers[p]; !ok { - return errNotRegistered - } - delete(ps.peers, p) - return nil -} - -func (ps *odrPeerSet) peerPriority(p *peer, info *odrPeerInfo, req LesOdrRequest) uint64 { - tm := p.fcServer.CanSend(req.GetCost(p)) - if info.reqTimeCnt > 0 { - tm += info.reqTimeSum / info.reqTimeCnt - } - return tm -} - -func (ps *odrPeerSet) bestPeer(req LesOdrRequest, exclude map[*peer]struct{}) *peer { - var best *peer - var bpv uint64 - ps.lock.Lock() - defer ps.lock.Unlock() - - for p, info := range ps.peers { - if _, ok := exclude[p]; !ok { - pv := ps.peerPriority(p, info, req) - if best == nil || pv < bpv { - best = p - bpv = pv - } - } - } - return best -} - -func (ps *odrPeerSet) updateTimeout(p *peer, timeout bool) (drop bool) { - ps.lock.Lock() - defer ps.lock.Unlock() - - if info, ok := ps.peers[p]; ok { - info.reqCnt++ - if timeout { - // check ratio before increase to allow an extra timeout - if info.timeoutCnt*dropTimeoutRatio >= info.reqCnt { - return true - } - info.timeoutCnt++ - } - } - return false -} - -func (ps *odrPeerSet) updateServTime(p *peer, servTime uint64) { - ps.lock.Lock() - defer ps.lock.Unlock() - - if info, ok := ps.peers[p]; ok { - info.reqTimeSum += servTime - info.reqTimeCnt++ - } -} diff --git a/les/odr_requests.go b/les/odr_requests.go index 9de1c567a4..1c5fd0134a 100644 --- a/les/odr_requests.go +++ b/les/odr_requests.go @@ -36,6 +36,7 @@ import ( type LesOdrRequest interface { GetCost(*peer) uint64 + CanSend(*peer) bool Request(uint64, *peer) error Valid(ethdb.Database, *Msg) bool // if true, keeps the retrieved object } @@ -66,6 +67,11 @@ func (self *BlockRequest) GetCost(peer *peer) uint64 { return peer.GetRequestCost(GetBlockBodiesMsg, 1) } +// CanSend tells if a certain peer is suitable for serving the given request +func (self *BlockRequest) CanSend(peer *peer) bool { + return peer.HasBlock(self.Hash, self.Number) +} + // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (self *BlockRequest) Request(reqID uint64, peer *peer) error { glog.V(logger.Debug).Infof("ODR: requesting body of block %08x from peer %v", self.Hash[:4], peer.id) @@ -121,6 +127,11 @@ func (self *ReceiptsRequest) GetCost(peer *peer) uint64 { return peer.GetRequestCost(GetReceiptsMsg, 1) } +// CanSend tells if a certain peer is suitable for serving the given request +func (self *ReceiptsRequest) CanSend(peer *peer) bool { + return peer.HasBlock(self.Hash, self.Number) +} + // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (self *ReceiptsRequest) Request(reqID uint64, peer *peer) error { glog.V(logger.Debug).Infof("ODR: requesting receipts for block %08x from peer %v", self.Hash[:4], peer.id) @@ -171,6 +182,11 @@ func (self *TrieRequest) GetCost(peer *peer) uint64 { return peer.GetRequestCost(GetProofsMsg, 1) } +// CanSend tells if a certain peer is suitable for serving the given request +func (self *TrieRequest) CanSend(peer *peer) bool { + return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber) +} + // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (self *TrieRequest) Request(reqID uint64, peer *peer) error { glog.V(logger.Debug).Infof("ODR: requesting trie root %08x key %08x from peer %v", self.Id.Root[:4], self.Key[:4], peer.id) @@ -221,6 +237,11 @@ func (self *CodeRequest) GetCost(peer *peer) uint64 { return peer.GetRequestCost(GetCodeMsg, 1) } +// CanSend tells if a certain peer is suitable for serving the given request +func (self *CodeRequest) CanSend(peer *peer) bool { + return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber) +} + // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (self *CodeRequest) Request(reqID uint64, peer *peer) error { glog.V(logger.Debug).Infof("ODR: requesting node data for hash %08x from peer %v", self.Hash[:4], peer.id) @@ -246,8 +267,7 @@ func (self *CodeRequest) Valid(db ethdb.Database, msg *Msg) bool { return false } data := reply[0] - hash := crypto.Sha3Hash(data) - if !bytes.Equal(self.Hash[:], hash[:]) { + if hash := crypto.Keccak256Hash(data); self.Hash != hash { glog.V(logger.Debug).Infof("ODR: requested hash %08x does not match received data hash %08x", self.Hash[:4], hash[:4]) return false } @@ -274,6 +294,14 @@ func (self *ChtRequest) GetCost(peer *peer) uint64 { return peer.GetRequestCost(GetHeaderProofsMsg, 1) } +// CanSend tells if a certain peer is suitable for serving the given request +func (self *ChtRequest) CanSend(peer *peer) bool { + peer.lock.RLock() + defer peer.lock.RUnlock() + + return self.ChtNum <= (peer.headInfo.Number-light.ChtConfirmations)/light.ChtFrequency +} + // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (self *ChtRequest) Request(reqID uint64, peer *peer) error { glog.V(logger.Debug).Infof("ODR: requesting CHT #%d block #%d from peer %v", self.ChtNum, self.BlockNum, peer.id) diff --git a/les/odr_test.go b/les/odr_test.go index df5d5adb73..232ee39454 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -115,12 +115,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai if bc != nil { header := bc.GetHeaderByHash(bhash) statedb, err := state.New(header.Root, db) + if err == nil { from := statedb.GetOrNewStateObject(testBankAddress) from.SetBalance(common.MaxBig) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)} - vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) + + context := core.NewEVMContext(msg, header, bc) + vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) + + //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) @@ -128,16 +133,20 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai } else { header := lc.GetHeaderByHash(bhash) state := light.NewLightState(light.StateTrieID(header), lc.Odr()) + vmstate := light.NewVMState(ctx, state) from, err := state.GetOrNewStateObject(ctx, testBankAddress) if err == nil { from.SetBalance(common.MaxBig) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)} - vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{}) + context := core.NewEVMContext(msg, header, lc) + vmenv := vm.NewEVM(context, vmstate, config, vm.Config{}) + + //vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) - if vmenv.Error() == nil { + if vmstate.Error() == nil { res = append(res, ret...) } } @@ -151,6 +160,9 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { pm, db, odr := newTestProtocolManagerMust(t, false, 4, testChainGen) lpm, ldb, odr := newTestProtocolManagerMust(t, true, 0, nil) _, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm) + pool := &testServerPool{} + pool.setPeer(lpeer) + odr.serverPool = pool select { case <-time.After(time.Millisecond * 100): case err := <-err1: @@ -179,13 +191,13 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { } // temporarily remove peer to test odr fails - odr.UnregisterPeer(lpeer) + pool.setPeer(nil) // expect retrievals to fail (except genesis block) without a les peer test(expFail) - odr.RegisterPeer(lpeer) + pool.setPeer(lpeer) // expect all retrievals to pass test(5) - odr.UnregisterPeer(lpeer) + pool.setPeer(nil) // still expect all retrievals to pass, now data should be cached locally test(5) } diff --git a/les/peer.go b/les/peer.go index 67f5beb0ec..6f9a5835f5 100644 --- a/les/peer.go +++ b/les/peer.go @@ -51,12 +51,14 @@ type peer struct { id string - firstHeadInfo, headInfo *announceData - headInfoLen int - lock sync.RWMutex + headInfo *announceData + lock sync.RWMutex announceChn chan announceData + poolEntry *poolEntry + hasBlock func(common.Hash, uint64) bool + fcClient *flowcontrol.ClientNode // nil if the peer is server only fcServer *flowcontrol.ServerNode // nil if the peer is client only fcServerParams *flowcontrol.ServerParams @@ -109,67 +111,6 @@ func (p *peer) headBlockInfo() blockInfo { return blockInfo{Hash: p.headInfo.Hash, Number: p.headInfo.Number, Td: p.headInfo.Td} } -func (p *peer) addNotify(announce *announceData) bool { - p.lock.Lock() - defer p.lock.Unlock() - - if announce.Td.Cmp(p.headInfo.Td) < 1 { - return false - } - if p.headInfoLen >= maxHeadInfoLen { - //return false - p.firstHeadInfo = p.firstHeadInfo.next - p.headInfoLen-- - } - if announce.haveHeaders == 0 { - hh := p.headInfo.Number - announce.ReorgDepth - if p.headInfo.haveHeaders < hh { - hh = p.headInfo.haveHeaders - } - announce.haveHeaders = hh - } - p.headInfo.next = announce - p.headInfo = announce - p.headInfoLen++ - return true -} - -func (p *peer) gotHeader(hash common.Hash, number uint64, td *big.Int) bool { - h := p.firstHeadInfo - ptr := 0 - for h != nil { - if h.Hash == hash { - if h.Number != number || h.Td.Cmp(td) != 0 { - return false - } - h.headKnown = true - h.haveHeaders = h.Number - p.firstHeadInfo = h - p.headInfoLen -= ptr - last := h - h = h.next - // propagate haveHeaders through the chain - for h != nil { - hh := last.Number - h.ReorgDepth - if last.haveHeaders < hh { - hh = last.haveHeaders - } - if hh > h.haveHeaders { - h.haveHeaders = hh - } else { - return true - } - last = h - h = h.next - } - return true - } - h = h.next - ptr++ - } - return true -} - // Td retrieves the current total difficulty of a peer. func (p *peer) Td() *big.Int { p.lock.RLock() @@ -195,6 +136,9 @@ func sendResponse(w p2p.MsgWriter, msgcode, reqID, bv uint64, data interface{}) } func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 { + p.lock.RLock() + defer p.lock.RUnlock() + cost := p.fcCosts[msgcode].baseCost + p.fcCosts[msgcode].reqCost*uint64(amount) if cost > p.fcServerParams.BufLimit { cost = p.fcServerParams.BufLimit @@ -202,6 +146,14 @@ func (p *peer) GetRequestCost(msgcode uint64, amount int) uint64 { return cost } +// HasBlock checks if the peer has a given block +func (p *peer) HasBlock(hash common.Hash, number uint64) bool { + p.lock.RLock() + hashBlock := p.hasBlock + p.lock.RUnlock() + return hashBlock != nil && hashBlock(hash, number) +} + // SendAnnounce announces the availability of a number of blocks through // a hash notification. func (p *peer) SendAnnounce(request announceData) error { @@ -289,7 +241,9 @@ func (p *peer) RequestHeaderProofs(reqID, cost uint64, reqs []*ChtReq) error { func (p *peer) SendTxs(cost uint64, txs types.Transactions) error { glog.V(logger.Debug).Infof("%v relaying %v txs", p, len(txs)) - p.fcServer.SendRequest(0, cost) + reqID := getNextReqID() + p.fcServer.MustAssignRequest(reqID) + p.fcServer.SendRequest(reqID, cost) return p2p.Send(p.rw, SendTxMsg, txs) } @@ -453,9 +407,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis p.fcCosts = MRC.decode() } - p.firstHeadInfo = &announceData{Td: rTd, Hash: rHash, Number: rNum} - p.headInfo = p.firstHeadInfo - p.headInfoLen = 1 + p.headInfo = &announceData{Td: rTd, Hash: rHash, Number: rNum} return nil } @@ -517,7 +469,7 @@ func (ps *peerSet) AllPeerIDs() []string { res := make([]string, len(ps.peers)) idx := 0 - for id, _ := range ps.peers { + for id := range ps.peers { res[idx] = id idx++ } diff --git a/les/randselect.go b/les/randselect.go new file mode 100644 index 0000000000..1a9d0695bd --- /dev/null +++ b/les/randselect.go @@ -0,0 +1,173 @@ +// 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 . + +// Package les implements the Light Ethereum Subprotocol. +package les + +import ( + "math/rand" +) + +// wrsItem interface should be implemented by any entries that are to be selected from +// a weightedRandomSelect set. Note that recalculating monotonously decreasing item +// weights on-demand (without constantly calling update) is allowed +type wrsItem interface { + Weight() int64 +} + +// weightedRandomSelect is capable of weighted random selection from a set of items +type weightedRandomSelect struct { + root *wrsNode + idx map[wrsItem]int +} + +// newWeightedRandomSelect returns a new weightedRandomSelect structure +func newWeightedRandomSelect() *weightedRandomSelect { + return &weightedRandomSelect{root: &wrsNode{maxItems: wrsBranches}, idx: make(map[wrsItem]int)} +} + +// update updates an item's weight, adds it if it was non-existent or removes it if +// the new weight is zero. Note that explicitly updating decreasing weights is not necessary. +func (w *weightedRandomSelect) update(item wrsItem) { + w.setWeight(item, item.Weight()) +} + +// remove removes an item from the set +func (w *weightedRandomSelect) remove(item wrsItem) { + w.setWeight(item, 0) +} + +// setWeight sets an item's weight to a specific value (removes it if zero) +func (w *weightedRandomSelect) setWeight(item wrsItem, weight int64) { + idx, ok := w.idx[item] + if ok { + w.root.setWeight(idx, weight) + if weight == 0 { + delete(w.idx, item) + } + } else { + if weight != 0 { + if w.root.itemCnt == w.root.maxItems { + // add a new level + newRoot := &wrsNode{sumWeight: w.root.sumWeight, itemCnt: w.root.itemCnt, level: w.root.level + 1, maxItems: w.root.maxItems * wrsBranches} + newRoot.items[0] = w.root + newRoot.weights[0] = w.root.sumWeight + w.root = newRoot + } + w.idx[item] = w.root.insert(item, weight) + } + } +} + +// choose randomly selects an item from the set, with a chance proportional to its +// current weight. If the weight of the chosen element has been decreased since the +// last stored value, returns it with a newWeight/oldWeight chance, otherwise just +// updates its weight and selects another one +func (w *weightedRandomSelect) choose() wrsItem { + for { + if w.root.sumWeight == 0 { + return nil + } + val := rand.Int63n(w.root.sumWeight) + choice, lastWeight := w.root.choose(val) + weight := choice.Weight() + if weight != lastWeight { + w.setWeight(choice, weight) + } + if weight >= lastWeight || rand.Int63n(lastWeight) < weight { + return choice + } + } +} + +const wrsBranches = 8 // max number of branches in the wrsNode tree + +// wrsNode is a node of a tree structure that can store wrsItems or further wrsNodes. +type wrsNode struct { + items [wrsBranches]interface{} + weights [wrsBranches]int64 + sumWeight int64 + level, itemCnt, maxItems int +} + +// insert recursively inserts a new item to the tree and returns the item index +func (n *wrsNode) insert(item wrsItem, weight int64) int { + branch := 0 + for n.items[branch] != nil && (n.level == 0 || n.items[branch].(*wrsNode).itemCnt == n.items[branch].(*wrsNode).maxItems) { + branch++ + if branch == wrsBranches { + panic(nil) + } + } + n.itemCnt++ + n.sumWeight += weight + n.weights[branch] += weight + if n.level == 0 { + n.items[branch] = item + return branch + } else { + var subNode *wrsNode + if n.items[branch] == nil { + subNode = &wrsNode{maxItems: n.maxItems / wrsBranches, level: n.level - 1} + n.items[branch] = subNode + } else { + subNode = n.items[branch].(*wrsNode) + } + subIdx := subNode.insert(item, weight) + return subNode.maxItems*branch + subIdx + } +} + +// setWeight updates the weight of a certain item (which should exist) and returns +// the change of the last weight value stored in the tree +func (n *wrsNode) setWeight(idx int, weight int64) int64 { + if n.level == 0 { + oldWeight := n.weights[idx] + n.weights[idx] = weight + diff := weight - oldWeight + n.sumWeight += diff + if weight == 0 { + n.items[idx] = nil + n.itemCnt-- + } + return diff + } + branchItems := n.maxItems / wrsBranches + branch := idx / branchItems + diff := n.items[branch].(*wrsNode).setWeight(idx-branch*branchItems, weight) + n.weights[branch] += diff + n.sumWeight += diff + if weight == 0 { + n.itemCnt-- + } + return diff +} + +// choose recursively selects an item from the tree and returns it along with its weight +func (n *wrsNode) choose(val int64) (wrsItem, int64) { + for i, w := range n.weights { + if val < w { + if n.level == 0 { + return n.items[i].(wrsItem), n.weights[i] + } else { + return n.items[i].(*wrsNode).choose(val) + } + } else { + val -= w + } + } + panic(nil) +} diff --git a/core/vm/jump_table_test.go b/les/randselect_test.go similarity index 51% rename from core/vm/jump_table_test.go rename to les/randselect_test.go index e90dd83bc2..9ae7726ddd 100644 --- a/core/vm/jump_table_test.go +++ b/les/randselect_test.go @@ -14,25 +14,54 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package vm +package les import ( - "math/big" + "math/rand" "testing" - - "github.com/ubiq/go-ubiq/params" ) -func TestInit(t *testing.T) { - jumpTable := newJumpTable(¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(0)) - if jumpTable[DELEGATECALL].valid { - t.Error("Expected DELEGATECALL not to be present") - } +type testWrsItem struct { + idx int + widx *int +} - for _, n := range []int64{1, 2, 100} { - jumpTable := newJumpTable(¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(n)) - if !jumpTable[DELEGATECALL].valid { - t.Error("Expected DELEGATECALL to be present for block", n) +func (t *testWrsItem) Weight() int64 { + w := *t.widx + if w == -1 || w == t.idx { + return int64(t.idx + 1) + } + return 0 +} + +func TestWeightedRandomSelect(t *testing.T) { + testFn := func(cnt int) { + s := newWeightedRandomSelect() + w := -1 + list := make([]testWrsItem, cnt) + for i := range list { + list[i] = testWrsItem{idx: i, widx: &w} + s.update(&list[i]) + } + w = rand.Intn(cnt) + c := s.choose() + if c == nil { + t.Errorf("expected item, got nil") + } else { + if c.(*testWrsItem).idx != w { + t.Errorf("expected another item") + } + } + w = -2 + if s.choose() != nil { + t.Errorf("expected nil, got item") } } + testFn(1) + testFn(10) + testFn(100) + testFn(1000) + testFn(10000) + testFn(100000) + testFn(1000000) } diff --git a/les/request_test.go b/les/request_test.go index 0a5536a166..0960bacc47 100644 --- a/les/request_test.go +++ b/les/request_test.go @@ -71,6 +71,9 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) { pm, db, _ := newTestProtocolManagerMust(t, false, 4, testChainGen) lpm, ldb, odr := newTestProtocolManagerMust(t, true, 0, nil) _, err1, lpeer, err2 := newTestPeerPair("peer", protocol, pm, lpm) + pool := &testServerPool{} + pool.setPeer(lpeer) + odr.serverPool = pool select { case <-time.After(time.Millisecond * 100): case err := <-err1: @@ -100,11 +103,10 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) { } // temporarily remove peer to test odr fails - odr.UnregisterPeer(lpeer) + pool.setPeer(nil) // expect retrievals to fail (except genesis block) without a les peer test(0) - odr.RegisterPeer(lpeer) + pool.setPeer(lpeer) // expect all retrievals to pass test(5) - odr.UnregisterPeer(lpeer) } diff --git a/les/server.go b/les/server.go index eeb5814822..8d01bb15bb 100644 --- a/les/server.go +++ b/les/server.go @@ -42,6 +42,9 @@ type LesServer struct { fcManager *flowcontrol.ClientManager // nil if our node is client only fcCostStats *requestCostStats defParams *flowcontrol.ServerParams + srvr *p2p.Server + synced, stopped bool + lock sync.Mutex } func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { @@ -67,12 +70,35 @@ func (s *LesServer) Protocols() []p2p.Protocol { return s.protocolManager.SubProtocols } +// Start only starts the actual service if the ETH protocol has already been synced, +// otherwise it will be started by Synced() func (s *LesServer) Start(srvr *p2p.Server) { - s.protocolManager.Start(srvr) + s.lock.Lock() + defer s.lock.Unlock() + s.srvr = srvr + if s.synced { + s.protocolManager.Start(s.srvr) + } } +// Synced notifies the server that the ETH protocol has been synced and LES service can be started +func (s *LesServer) Synced() { + s.lock.Lock() + defer s.lock.Unlock() + + s.synced = true + if s.srvr != nil && !s.stopped { + s.protocolManager.Start(s.srvr) + } +} + +// Stop stops the LES service func (s *LesServer) Stop() { + s.lock.Lock() + defer s.lock.Unlock() + + s.stopped = true s.fcCostStats.store() s.fcManager.Stop() go func() { @@ -323,9 +349,8 @@ func (pm *ProtocolManager) blockLoop() { } var ( - lastChtKey = []byte("LastChtNumber") // chtNum (uint64 big endian) - chtPrefix = []byte("cht") // chtPrefix + chtNum (uint64 big endian) -> trie root hash - chtConfirmations = light.ChtFrequency / 2 + lastChtKey = []byte("LastChtNumber") // chtNum (uint64 big endian) + chtPrefix = []byte("cht") // chtPrefix + chtNum (uint64 big endian) -> trie root hash ) func getChtRoot(db ethdb.Database, num uint64) common.Hash { @@ -346,8 +371,8 @@ func makeCht(db ethdb.Database) bool { headNum := core.GetBlockNumber(db, headHash) var newChtNum uint64 - if headNum > chtConfirmations { - newChtNum = (headNum - chtConfirmations) / light.ChtFrequency + if headNum > light.ChtConfirmations { + newChtNum = (headNum - light.ChtConfirmations) / light.ChtFrequency } var lastChtNum uint64 diff --git a/les/serverpool.go b/les/serverpool.go new file mode 100644 index 0000000000..d26a5af197 --- /dev/null +++ b/les/serverpool.go @@ -0,0 +1,810 @@ +// 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 . + +// Package les implements the Light Ethereum Subprotocol. +package les + +import ( + "io" + "math" + "math/rand" + "net" + "strconv" + "sync" + "time" + + "github.com/ubiq/go-ubiq/common/mclock" + "github.com/ubiq/go-ubiq/ethdb" + "github.com/ubiq/go-ubiq/logger" + "github.com/ubiq/go-ubiq/logger/glog" + "github.com/ubiq/go-ubiq/p2p" + "github.com/ubiq/go-ubiq/p2p/discover" + "github.com/ubiq/go-ubiq/p2p/discv5" + "github.com/ubiq/go-ubiq/rlp" +) + +const ( + // After a connection has been ended or timed out, there is a waiting period + // before it can be selected for connection again. + // waiting period = base delay * (1 + random(1)) + // base delay = shortRetryDelay for the first shortRetryCnt times after a + // successful connection, after that longRetryDelay is applied + shortRetryCnt = 5 + shortRetryDelay = time.Second * 5 + longRetryDelay = time.Minute * 10 + // maxNewEntries is the maximum number of newly discovered (never connected) nodes. + // If the limit is reached, the least recently discovered one is thrown out. + maxNewEntries = 1000 + // maxKnownEntries is the maximum number of known (already connected) nodes. + // If the limit is reached, the least recently connected one is thrown out. + // (not that unlike new entries, known entries are persistent) + maxKnownEntries = 1000 + // target for simultaneously connected servers + targetServerCount = 5 + // target for servers selected from the known table + // (we leave room for trying new ones if there is any) + targetKnownSelect = 3 + // after dialTimeout, consider the server unavailable and adjust statistics + dialTimeout = time.Second * 30 + // targetConnTime is the minimum expected connection duration before a server + // drops a client without any specific reason + targetConnTime = time.Minute * 10 + // new entry selection weight calculation based on most recent discovery time: + // unity until discoverExpireStart, then exponential decay with discoverExpireConst + discoverExpireStart = time.Minute * 20 + discoverExpireConst = time.Minute * 20 + // known entry selection weight is dropped by a factor of exp(-failDropLn) after + // each unsuccessful connection (restored after a successful one) + failDropLn = 0.1 + // known node connection success and quality statistics have a long term average + // and a short term value which is adjusted exponentially with a factor of + // pstatRecentAdjust with each dial/connection and also returned exponentially + // to the average with the time constant pstatReturnToMeanTC + pstatRecentAdjust = 0.1 + pstatReturnToMeanTC = time.Hour + // node address selection weight is dropped by a factor of exp(-addrFailDropLn) after + // each unsuccessful connection (restored after a successful one) + addrFailDropLn = math.Ln2 + // responseScoreTC and delayScoreTC are exponential decay time constants for + // calculating selection chances from response times and block delay times + responseScoreTC = time.Millisecond * 100 + delayScoreTC = time.Second * 5 + timeoutPow = 10 + // peerSelectMinWeight is added to calculated weights at request peer selection + // to give poorly performing peers a little chance of coming back + peerSelectMinWeight = 0.005 + // initStatsWeight is used to initialize previously unknown peers with good + // statistics to give a chance to prove themselves + initStatsWeight = 1 +) + +// serverPool implements a pool for storing and selecting newly discovered and already +// known light server nodes. It received discovered nodes, stores statistics about +// known nodes and takes care of always having enough good quality servers connected. +type serverPool struct { + db ethdb.Database + dbKey []byte + server *p2p.Server + quit chan struct{} + wg *sync.WaitGroup + connWg sync.WaitGroup + + discSetPeriod chan time.Duration + discNodes chan *discv5.Node + discLookups chan bool + + entries map[discover.NodeID]*poolEntry + lock sync.Mutex + timeout, enableRetry chan *poolEntry + adjustStats chan poolStatAdjust + + knownQueue, newQueue poolEntryQueue + knownSelect, newSelect *weightedRandomSelect + knownSelected, newSelected int + fastDiscover bool +} + +// newServerPool creates a new serverPool instance +func newServerPool(db ethdb.Database, dbPrefix []byte, server *p2p.Server, topic discv5.Topic, quit chan struct{}, wg *sync.WaitGroup) *serverPool { + pool := &serverPool{ + db: db, + dbKey: append(dbPrefix, []byte(topic)...), + server: server, + quit: quit, + wg: wg, + entries: make(map[discover.NodeID]*poolEntry), + timeout: make(chan *poolEntry, 1), + adjustStats: make(chan poolStatAdjust, 100), + enableRetry: make(chan *poolEntry, 1), + knownSelect: newWeightedRandomSelect(), + newSelect: newWeightedRandomSelect(), + fastDiscover: true, + } + pool.knownQueue = newPoolEntryQueue(maxKnownEntries, pool.removeEntry) + pool.newQueue = newPoolEntryQueue(maxNewEntries, pool.removeEntry) + wg.Add(1) + pool.loadNodes() + pool.checkDial() + + if pool.server.DiscV5 != nil { + pool.discSetPeriod = make(chan time.Duration, 1) + pool.discNodes = make(chan *discv5.Node, 100) + pool.discLookups = make(chan bool, 100) + go pool.server.DiscV5.SearchTopic(topic, pool.discSetPeriod, pool.discNodes, pool.discLookups) + } + + go pool.eventLoop() + return pool +} + +// connect should be called upon any incoming connection. If the connection has been +// dialed by the server pool recently, the appropriate pool entry is returned. +// Otherwise, the connection should be rejected. +// Note that whenever a connection has been accepted and a pool entry has been returned, +// disconnect should also always be called. +func (pool *serverPool) connect(p *peer, ip net.IP, port uint16) *poolEntry { + pool.lock.Lock() + defer pool.lock.Unlock() + entry := pool.entries[p.ID()] + if entry == nil { + return nil + } + glog.V(logger.Debug).Infof("connecting to %v, state: %v", p.id, entry.state) + if entry.state != psDialed { + return nil + } + pool.connWg.Add(1) + entry.peer = p + entry.state = psConnected + addr := &poolEntryAddress{ + ip: ip, + port: port, + lastSeen: mclock.Now(), + } + entry.lastConnected = addr + entry.addr = make(map[string]*poolEntryAddress) + entry.addr[addr.strKey()] = addr + entry.addrSelect = *newWeightedRandomSelect() + entry.addrSelect.update(addr) + return entry +} + +// registered should be called after a successful handshake +func (pool *serverPool) registered(entry *poolEntry) { + glog.V(logger.Debug).Infof("registered %v", entry.id.String()) + pool.lock.Lock() + defer pool.lock.Unlock() + + entry.state = psRegistered + entry.regTime = mclock.Now() + if !entry.known { + pool.newQueue.remove(entry) + entry.known = true + } + pool.knownQueue.setLatest(entry) + entry.shortRetry = shortRetryCnt +} + +// disconnect should be called when ending a connection. Service quality statistics +// can be updated optionally (not updated if no registration happened, in this case +// only connection statistics are updated, just like in case of timeout) +func (pool *serverPool) disconnect(entry *poolEntry) { + glog.V(logger.Debug).Infof("disconnected %v", entry.id.String()) + pool.lock.Lock() + defer pool.lock.Unlock() + + if entry.state == psRegistered { + connTime := mclock.Now() - entry.regTime + connAdjust := float64(connTime) / float64(targetConnTime) + if connAdjust > 1 { + connAdjust = 1 + } + stopped := false + select { + case <-pool.quit: + stopped = true + default: + } + if stopped { + entry.connectStats.add(1, connAdjust) + } else { + entry.connectStats.add(connAdjust, 1) + } + } + + entry.state = psNotConnected + if entry.knownSelected { + pool.knownSelected-- + } else { + pool.newSelected-- + } + pool.setRetryDial(entry) + pool.connWg.Done() +} + +const ( + pseBlockDelay = iota + pseResponseTime + pseResponseTimeout +) + +// poolStatAdjust records are sent to adjust peer block delay/response time statistics +type poolStatAdjust struct { + adjustType int + entry *poolEntry + time time.Duration +} + +// adjustBlockDelay adjusts the block announce delay statistics of a node +func (pool *serverPool) adjustBlockDelay(entry *poolEntry, time time.Duration) { + pool.adjustStats <- poolStatAdjust{pseBlockDelay, entry, time} +} + +// adjustResponseTime adjusts the request response time statistics of a node +func (pool *serverPool) adjustResponseTime(entry *poolEntry, time time.Duration, timeout bool) { + if timeout { + pool.adjustStats <- poolStatAdjust{pseResponseTimeout, entry, time} + } else { + pool.adjustStats <- poolStatAdjust{pseResponseTime, entry, time} + } +} + +type selectPeerItem struct { + peer *peer + weight int64 + wait time.Duration +} + +func (sp selectPeerItem) Weight() int64 { + return sp.weight +} + +// selectPeer selects a suitable peer for a request, also returning a necessary waiting time to perform the request +// and a "locked" flag meaning that the request has been assigned to the given peer and its execution is guaranteed +// after the given waiting time. If locked flag is false, selectPeer should be called again after the waiting time. +func (pool *serverPool) selectPeer(reqID uint64, canSend func(*peer) (bool, time.Duration)) (*peer, time.Duration, bool) { + pool.lock.Lock() + type selectPeer struct { + peer *peer + rstat, tstat float64 + } + var list []selectPeer + sel := newWeightedRandomSelect() + for _, entry := range pool.entries { + if entry.state == psRegistered { + if !entry.peer.fcServer.IsAssigned() { + list = append(list, selectPeer{entry.peer, entry.responseStats.recentAvg(), entry.timeoutStats.recentAvg()}) + } + } + } + pool.lock.Unlock() + + for _, sp := range list { + ok, wait := canSend(sp.peer) + if ok { + w := int64(1000000000 * (peerSelectMinWeight + math.Exp(-(sp.rstat+float64(wait))/float64(responseScoreTC))*math.Pow((1-sp.tstat), timeoutPow))) + sel.update(selectPeerItem{peer: sp.peer, weight: w, wait: wait}) + } + } + choice := sel.choose() + if choice == nil { + return nil, 0, false + } + peer, wait := choice.(selectPeerItem).peer, choice.(selectPeerItem).wait + locked := false + if wait < time.Millisecond*100 { + if peer.fcServer.AssignRequest(reqID) { + ok, w := canSend(peer) + wait = time.Duration(w) + if ok && wait < time.Millisecond*100 { + locked = true + } else { + peer.fcServer.DeassignRequest(reqID) + wait = time.Millisecond * 100 + } + } + } else { + wait = time.Millisecond * 100 + } + return peer, wait, locked +} + +// selectPeer selects a suitable peer for a request, waiting until an assignment to +// the request is guaranteed or the process is aborted. +func (pool *serverPool) selectPeerWait(reqID uint64, canSend func(*peer) (bool, time.Duration), abort <-chan struct{}) *peer { + for { + peer, wait, locked := pool.selectPeer(reqID, canSend) + if locked { + return peer + } + select { + case <-abort: + return nil + case <-time.After(wait): + } + } +} + +// eventLoop handles pool events and mutex locking for all internal functions +func (pool *serverPool) eventLoop() { + lookupCnt := 0 + var convTime mclock.AbsTime + pool.discSetPeriod <- time.Millisecond * 100 + for { + select { + case entry := <-pool.timeout: + pool.lock.Lock() + if !entry.removed { + pool.checkDialTimeout(entry) + } + pool.lock.Unlock() + + case entry := <-pool.enableRetry: + pool.lock.Lock() + if !entry.removed { + entry.delayedRetry = false + pool.updateCheckDial(entry) + } + pool.lock.Unlock() + + case adj := <-pool.adjustStats: + pool.lock.Lock() + switch adj.adjustType { + case pseBlockDelay: + adj.entry.delayStats.add(float64(adj.time), 1) + case pseResponseTime: + adj.entry.responseStats.add(float64(adj.time), 1) + adj.entry.timeoutStats.add(0, 1) + case pseResponseTimeout: + adj.entry.timeoutStats.add(1, 1) + } + pool.lock.Unlock() + + case node := <-pool.discNodes: + pool.lock.Lock() + now := mclock.Now() + id := discover.NodeID(node.ID) + entry := pool.entries[id] + if entry == nil { + glog.V(logger.Debug).Infof("discovered %v", node.String()) + entry = &poolEntry{ + id: id, + addr: make(map[string]*poolEntryAddress), + addrSelect: *newWeightedRandomSelect(), + shortRetry: shortRetryCnt, + } + pool.entries[id] = entry + // initialize previously unknown peers with good statistics to give a chance to prove themselves + entry.connectStats.add(1, initStatsWeight) + entry.delayStats.add(0, initStatsWeight) + entry.responseStats.add(0, initStatsWeight) + entry.timeoutStats.add(0, initStatsWeight) + } + entry.lastDiscovered = now + addr := &poolEntryAddress{ + ip: node.IP, + port: node.TCP, + } + if a, ok := entry.addr[addr.strKey()]; ok { + addr = a + } else { + entry.addr[addr.strKey()] = addr + } + addr.lastSeen = now + entry.addrSelect.update(addr) + if !entry.known { + pool.newQueue.setLatest(entry) + } + pool.updateCheckDial(entry) + pool.lock.Unlock() + + case conv := <-pool.discLookups: + if conv { + if lookupCnt == 0 { + convTime = mclock.Now() + } + lookupCnt++ + if pool.fastDiscover && (lookupCnt == 50 || time.Duration(mclock.Now()-convTime) > time.Minute) { + pool.fastDiscover = false + pool.discSetPeriod <- time.Minute + } + } + + case <-pool.quit: + close(pool.discSetPeriod) + pool.connWg.Wait() + pool.saveNodes() + pool.wg.Done() + return + + } + } +} + +// loadNodes loads known nodes and their statistics from the database +func (pool *serverPool) loadNodes() { + enc, err := pool.db.Get(pool.dbKey) + if err != nil { + return + } + var list []*poolEntry + err = rlp.DecodeBytes(enc, &list) + if err != nil { + glog.V(logger.Debug).Infof("node list decode error: %v", err) + return + } + for _, e := range list { + glog.V(logger.Debug).Infof("loaded server stats %016x fails: %v connStats: %v / %v delayStats: %v / %v responseStats: %v / %v timeoutStats: %v / %v", e.id[0:8], e.lastConnected.fails, e.connectStats.avg, e.connectStats.weight, time.Duration(e.delayStats.avg), e.delayStats.weight, time.Duration(e.responseStats.avg), e.responseStats.weight, e.timeoutStats.avg, e.timeoutStats.weight) + pool.entries[e.id] = e + pool.knownQueue.setLatest(e) + pool.knownSelect.update((*knownEntry)(e)) + } +} + +// saveNodes saves known nodes and their statistics into the database. Nodes are +// ordered from least to most recently connected. +func (pool *serverPool) saveNodes() { + list := make([]*poolEntry, len(pool.knownQueue.queue)) + for i := range list { + list[i] = pool.knownQueue.fetchOldest() + } + enc, err := rlp.EncodeToBytes(list) + if err == nil { + pool.db.Put(pool.dbKey, enc) + } +} + +// removeEntry removes a pool entry when the entry count limit is reached. +// Note that it is called by the new/known queues from which the entry has already +// been removed so removing it from the queues is not necessary. +func (pool *serverPool) removeEntry(entry *poolEntry) { + pool.newSelect.remove((*discoveredEntry)(entry)) + pool.knownSelect.remove((*knownEntry)(entry)) + entry.removed = true + delete(pool.entries, entry.id) +} + +// setRetryDial starts the timer which will enable dialing a certain node again +func (pool *serverPool) setRetryDial(entry *poolEntry) { + delay := longRetryDelay + if entry.shortRetry > 0 { + entry.shortRetry-- + delay = shortRetryDelay + } + delay += time.Duration(rand.Int63n(int64(delay) + 1)) + entry.delayedRetry = true + go func() { + select { + case <-pool.quit: + case <-time.After(delay): + select { + case <-pool.quit: + case pool.enableRetry <- entry: + } + } + }() +} + +// updateCheckDial is called when an entry can potentially be dialed again. It updates +// its selection weights and checks if new dials can/should be made. +func (pool *serverPool) updateCheckDial(entry *poolEntry) { + pool.newSelect.update((*discoveredEntry)(entry)) + pool.knownSelect.update((*knownEntry)(entry)) + pool.checkDial() +} + +// checkDial checks if new dials can/should be made. It tries to select servers both +// based on good statistics and recent discovery. +func (pool *serverPool) checkDial() { + fillWithKnownSelects := !pool.fastDiscover + for pool.knownSelected < targetKnownSelect { + entry := pool.knownSelect.choose() + if entry == nil { + fillWithKnownSelects = false + break + } + pool.dial((*poolEntry)(entry.(*knownEntry)), true) + } + for pool.knownSelected+pool.newSelected < targetServerCount { + entry := pool.newSelect.choose() + if entry == nil { + break + } + pool.dial((*poolEntry)(entry.(*discoveredEntry)), false) + } + if fillWithKnownSelects { + // no more newly discovered nodes to select and since fast discover period + // is over, we probably won't find more in the near future so select more + // known entries if possible + for pool.knownSelected < targetServerCount { + entry := pool.knownSelect.choose() + if entry == nil { + break + } + pool.dial((*poolEntry)(entry.(*knownEntry)), true) + } + } +} + +// dial initiates a new connection +func (pool *serverPool) dial(entry *poolEntry, knownSelected bool) { + if entry.state != psNotConnected { + return + } + entry.state = psDialed + entry.knownSelected = knownSelected + if knownSelected { + pool.knownSelected++ + } else { + pool.newSelected++ + } + addr := entry.addrSelect.choose().(*poolEntryAddress) + glog.V(logger.Debug).Infof("dialing %v out of %v, known: %v", entry.id.String()+"@"+addr.strKey(), len(entry.addr), knownSelected) + entry.dialed = addr + go func() { + pool.server.AddPeer(discover.NewNode(entry.id, addr.ip, addr.port, addr.port)) + select { + case <-pool.quit: + case <-time.After(dialTimeout): + select { + case <-pool.quit: + case pool.timeout <- entry: + } + } + }() +} + +// checkDialTimeout checks if the node is still in dialed state and if so, resets it +// and adjusts connection statistics accordingly. +func (pool *serverPool) checkDialTimeout(entry *poolEntry) { + if entry.state != psDialed { + return + } + glog.V(logger.Debug).Infof("timeout %v", entry.id.String()+"@"+entry.dialed.strKey()) + entry.state = psNotConnected + if entry.knownSelected { + pool.knownSelected-- + } else { + pool.newSelected-- + } + entry.connectStats.add(0, 1) + entry.dialed.fails++ + pool.setRetryDial(entry) +} + +const ( + psNotConnected = iota + psDialed + psConnected + psRegistered +) + +// poolEntry represents a server node and stores its current state and statistics. +type poolEntry struct { + peer *peer + id discover.NodeID + addr map[string]*poolEntryAddress + lastConnected, dialed *poolEntryAddress + addrSelect weightedRandomSelect + + lastDiscovered mclock.AbsTime + known, knownSelected bool + connectStats, delayStats poolStats + responseStats, timeoutStats poolStats + state int + regTime mclock.AbsTime + queueIdx int + removed bool + + delayedRetry bool + shortRetry int +} + +func (e *poolEntry) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{e.id, e.lastConnected.ip, e.lastConnected.port, e.lastConnected.fails, &e.connectStats, &e.delayStats, &e.responseStats, &e.timeoutStats}) +} + +func (e *poolEntry) DecodeRLP(s *rlp.Stream) error { + var entry struct { + ID discover.NodeID + IP net.IP + Port uint16 + Fails uint + CStat, DStat, RStat, TStat poolStats + } + if err := s.Decode(&entry); err != nil { + return err + } + addr := &poolEntryAddress{ip: entry.IP, port: entry.Port, fails: entry.Fails, lastSeen: mclock.Now()} + e.id = entry.ID + e.addr = make(map[string]*poolEntryAddress) + e.addr[addr.strKey()] = addr + e.addrSelect = *newWeightedRandomSelect() + e.addrSelect.update(addr) + e.lastConnected = addr + e.connectStats = entry.CStat + e.delayStats = entry.DStat + e.responseStats = entry.RStat + e.timeoutStats = entry.TStat + e.shortRetry = shortRetryCnt + e.known = true + return nil +} + +// discoveredEntry implements wrsItem +type discoveredEntry poolEntry + +// Weight calculates random selection weight for newly discovered entries +func (e *discoveredEntry) Weight() int64 { + if e.state != psNotConnected || e.delayedRetry { + return 0 + } + t := time.Duration(mclock.Now() - e.lastDiscovered) + if t <= discoverExpireStart { + return 1000000000 + } else { + return int64(1000000000 * math.Exp(-float64(t-discoverExpireStart)/float64(discoverExpireConst))) + } +} + +// knownEntry implements wrsItem +type knownEntry poolEntry + +// Weight calculates random selection weight for known entries +func (e *knownEntry) Weight() int64 { + if e.state != psNotConnected || !e.known || e.delayedRetry { + return 0 + } + return int64(1000000000 * e.connectStats.recentAvg() * math.Exp(-float64(e.lastConnected.fails)*failDropLn-e.responseStats.recentAvg()/float64(responseScoreTC)-e.delayStats.recentAvg()/float64(delayScoreTC)) * math.Pow((1-e.timeoutStats.recentAvg()), timeoutPow)) +} + +// poolEntryAddress is a separate object because currently it is necessary to remember +// multiple potential network addresses for a pool entry. This will be removed after +// the final implementation of v5 discovery which will retrieve signed and serial +// numbered advertisements, making it clear which IP/port is the latest one. +type poolEntryAddress struct { + ip net.IP + port uint16 + lastSeen mclock.AbsTime // last time it was discovered, connected or loaded from db + fails uint // connection failures since last successful connection (persistent) +} + +func (a *poolEntryAddress) Weight() int64 { + t := time.Duration(mclock.Now() - a.lastSeen) + return int64(1000000*math.Exp(-float64(t)/float64(discoverExpireConst)-float64(a.fails)*addrFailDropLn)) + 1 +} + +func (a *poolEntryAddress) strKey() string { + return a.ip.String() + ":" + strconv.Itoa(int(a.port)) +} + +// poolStats implement statistics for a certain quantity with a long term average +// and a short term value which is adjusted exponentially with a factor of +// pstatRecentAdjust with each update and also returned exponentially to the +// average with the time constant pstatReturnToMeanTC +type poolStats struct { + sum, weight, avg, recent float64 + lastRecalc mclock.AbsTime +} + +// init initializes stats with a long term sum/update count pair retrieved from the database +func (s *poolStats) init(sum, weight float64) { + s.sum = sum + s.weight = weight + var avg float64 + if weight > 0 { + avg = s.sum / weight + } + s.avg = avg + s.recent = avg + s.lastRecalc = mclock.Now() +} + +// recalc recalculates recent value return-to-mean and long term average +func (s *poolStats) recalc() { + now := mclock.Now() + s.recent = s.avg + (s.recent-s.avg)*math.Exp(-float64(now-s.lastRecalc)/float64(pstatReturnToMeanTC)) + if s.sum == 0 { + s.avg = 0 + } else { + if s.sum > s.weight*1e30 { + s.avg = 1e30 + } else { + s.avg = s.sum / s.weight + } + } + s.lastRecalc = now +} + +// add updates the stats with a new value +func (s *poolStats) add(value, weight float64) { + s.weight += weight + s.sum += value * weight + s.recalc() +} + +// recentAvg returns the short-term adjusted average +func (s *poolStats) recentAvg() float64 { + s.recalc() + return s.recent +} + +func (s *poolStats) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, []interface{}{math.Float64bits(s.sum), math.Float64bits(s.weight)}) +} + +func (s *poolStats) DecodeRLP(st *rlp.Stream) error { + var stats struct { + SumUint, WeightUint uint64 + } + if err := st.Decode(&stats); err != nil { + return err + } + s.init(math.Float64frombits(stats.SumUint), math.Float64frombits(stats.WeightUint)) + return nil +} + +// poolEntryQueue keeps track of its least recently accessed entries and removes +// them when the number of entries reaches the limit +type poolEntryQueue struct { + queue map[int]*poolEntry // known nodes indexed by their latest lastConnCnt value + newPtr, oldPtr, maxCnt int + removeFromPool func(*poolEntry) +} + +// newPoolEntryQueue returns a new poolEntryQueue +func newPoolEntryQueue(maxCnt int, removeFromPool func(*poolEntry)) poolEntryQueue { + return poolEntryQueue{queue: make(map[int]*poolEntry), maxCnt: maxCnt, removeFromPool: removeFromPool} +} + +// fetchOldest returns and removes the least recently accessed entry +func (q *poolEntryQueue) fetchOldest() *poolEntry { + if len(q.queue) == 0 { + return nil + } + for { + if e := q.queue[q.oldPtr]; e != nil { + delete(q.queue, q.oldPtr) + q.oldPtr++ + return e + } + q.oldPtr++ + } +} + +// remove removes an entry from the queue +func (q *poolEntryQueue) remove(entry *poolEntry) { + if q.queue[entry.queueIdx] == entry { + delete(q.queue, entry.queueIdx) + } +} + +// setLatest adds or updates a recently accessed entry. It also checks if an old entry +// needs to be removed and removes it from the parent pool too with a callback function. +func (q *poolEntryQueue) setLatest(entry *poolEntry) { + if q.queue[entry.queueIdx] == entry { + delete(q.queue, entry.queueIdx) + } else { + if len(q.queue) == q.maxCnt { + e := q.fetchOldest() + q.remove(e) + q.removeFromPool(e) + } + } + entry.queueIdx = q.newPtr + q.queue[entry.queueIdx] = entry + q.newPtr++ +} diff --git a/les/sync.go b/les/sync.go index bc719df0a4..5c09de8c1d 100644 --- a/les/sync.go +++ b/les/sync.go @@ -43,12 +43,12 @@ func (pm *ProtocolManager) syncer() { for { select { case <-pm.newPeerCh: -/* // Make sure we have peers to select from, then sync - if pm.peers.Len() < minDesiredPeerCount { - break - } - go pm.synchronise(pm.peers.BestPeer()) -*/ + /* // Make sure we have peers to select from, then sync + if pm.peers.Len() < minDesiredPeerCount { + break + } + go pm.synchronise(pm.peers.BestPeer()) + */ /*case <-forceSync: // Force a sync even if not enough peers are present go pm.synchronise(pm.peers.BestPeer()) diff --git a/les/txrelay.go b/les/txrelay.go index d4170247de..844103875a 100644 --- a/les/txrelay.go +++ b/les/txrelay.go @@ -138,7 +138,7 @@ func (self *LesTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback if len(self.txPending) > 0 { txs := make(types.Transactions, len(self.txPending)) i := 0 - for hash, _ := range self.txPending { + for hash := range self.txPending { txs[i] = self.txSent[hash].tx i++ } diff --git a/light/lightchain.go b/light/lightchain.go index a784111f7f..7e035d5e83 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -128,7 +128,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux return nil, err } // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain - for hash, _ := range core.BadHashes { + for hash := range core.BadHashes { if header := bc.GetHeaderByHash(hash); header != nil { glog.V(logger.Error).Infof("Found bad hash, rewinding chain to block #%d [%x…]", header.Number, header.ParentHash[:4]) bc.SetHead(header.Number.Uint64() - 1) @@ -498,3 +498,14 @@ func (self *LightChain) SyncCht(ctx context.Context) bool { } return false } + +// LockChain locks the chain mutex for reading so that multiple canonical hashes can be +// retrieved while it is guaranteed that they belong to the same version of the chain +func (self *LightChain) LockChain() { + self.chainmu.RLock() +} + +// UnlockChain unlocks the chain mutex +func (self *LightChain) UnlockChain() { + self.chainmu.RUnlock() +} diff --git a/light/odr.go b/light/odr.go index 029d4a71bb..197ed152cd 100644 --- a/light/odr.go +++ b/light/odr.go @@ -48,6 +48,7 @@ type OdrRequest interface { // TrieID identifies a state or account storage trie type TrieID struct { BlockHash, Root common.Hash + BlockNumber uint64 AccKey []byte } @@ -55,9 +56,10 @@ type TrieID struct { // header. func StateTrieID(header *types.Header) *TrieID { return &TrieID{ - BlockHash: header.Hash(), - AccKey: nil, - Root: header.Root, + BlockHash: header.Hash(), + BlockNumber: header.Number.Uint64(), + AccKey: nil, + Root: header.Root, } } @@ -66,9 +68,10 @@ func StateTrieID(header *types.Header) *TrieID { // checking Merkle proofs. func StorageTrieID(state *TrieID, addr common.Address, root common.Hash) *TrieID { return &TrieID{ - BlockHash: state.BlockHash, - AccKey: crypto.Keccak256(addr[:]), - Root: root, + BlockHash: state.BlockHash, + BlockNumber: state.BlockNumber, + AccKey: crypto.Keccak256(addr[:]), + Root: root, } } diff --git a/light/odr_test.go b/light/odr_test.go index b4c4bec0b0..d345d43088 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -157,6 +157,8 @@ func (callmsg) CheckNonce() bool { return false } func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte { data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000") + config := params.TestChainConfig + var res []byte for i := 0; i < 3; i++ { data[35] = byte(i) @@ -168,7 +170,10 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain from.SetBalance(common.MaxBig) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)} - vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{}) + + context := core.NewEVMContext(msg, header, bc) + vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) + gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) @@ -176,15 +181,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain } else { header := lc.GetHeaderByHash(bhash) state := NewLightState(StateTrieID(header), lc.Odr()) + vmstate := NewVMState(ctx, state) from, err := state.GetOrNewStateObject(ctx, testBankAddress) if err == nil { from.SetBalance(common.MaxBig) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)} - vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{}) + context := core.NewEVMContext(msg, header, lc) + vmenv := vm.NewEVM(context, vmstate, config, vm.Config{}) gp := new(core.GasPool).AddGas(common.MaxBig) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) - if vmenv.Error() == nil { + if vmstate.Error() == nil { res = append(res, ret...) } } @@ -198,17 +205,17 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) nonce++ - tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key) + tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) @@ -218,7 +225,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -229,7 +236,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) block.AddTx(tx) } } diff --git a/light/odr_util.go b/light/odr_util.go index 2841af09ea..1cb3605360 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -38,8 +38,9 @@ var ( ErrNoTrustedCht = errors.New("No trusted canonical hash trie") ErrNoHeader = errors.New("Header not found") - ChtFrequency = uint64(4096) - trustedChtKey = []byte("TrustedCHT") + ChtFrequency = uint64(4096) + ChtConfirmations = uint64(2048) + trustedChtKey = []byte("TrustedCHT") ) type ChtNode struct { diff --git a/light/state.go b/light/state.go index c7ee3ce108..cb51c1ac3d 100644 --- a/light/state.go +++ b/light/state.go @@ -141,6 +141,15 @@ func (self *LightState) AddBalance(ctx context.Context, addr common.Address, amo return err } +// SubBalance adds the given amount to the balance of the specified account +func (self *LightState) SubBalance(ctx context.Context, addr common.Address, amount *big.Int) error { + stateObject, err := self.GetOrNewStateObject(ctx, addr) + if err == nil && stateObject != nil { + stateObject.SubBalance(amount) + } + return err +} + // SetNonce sets the nonce of the specified account func (self *LightState) SetNonce(ctx context.Context, addr common.Address, nonce uint64) error { stateObject, err := self.GetOrNewStateObject(ctx, addr) diff --git a/light/state_object.go b/light/state_object.go index 1ca7c519de..17044df479 100644 --- a/light/state_object.go +++ b/light/state_object.go @@ -179,7 +179,7 @@ func (c *StateObject) SetBalance(amount *big.Int) { } // ReturnGas returns 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) {} // Copy creates a copy of the state object func (self *StateObject) Copy() *StateObject { diff --git a/light/txpool.go b/light/txpool.go index 679e6d6fa9..0f098e095c 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -346,19 +346,8 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error if from, err = types.Sender(pool.signer, tx); err != nil { return core.ErrInvalidSender } - - // Make sure the account exist. Non existent accounts - // haven't got funds and well therefor never pass. - currentState := pool.currentState() - if h, err := currentState.HasAccount(ctx, from); err == nil { - if !h { - return core.ErrNonExistentAccount - } - } else { - return err - } - // Last but not least check for nonce errors + currentState := pool.currentState() if n, err := currentState.GetNonce(ctx, from); err == nil { if n > tx.Nonce() { return core.ErrNonce @@ -500,7 +489,7 @@ func (tp *TxPool) GetTransaction(hash common.Hash) *types.Transaction { // GetTransactions returns all currently processable transactions. // The returned slice may be modified by the caller. -func (self *TxPool) GetTransactions() (txs types.Transactions) { +func (self *TxPool) GetTransactions() (txs types.Transactions, err error) { self.mu.RLock() defer self.mu.RUnlock() @@ -510,7 +499,7 @@ func (self *TxPool) GetTransactions() (txs types.Transactions) { txs[i] = tx i++ } - return txs + return txs, nil } // Content retrieves the data content of the transaction pool, returning all the diff --git a/light/txpool_test.go b/light/txpool_test.go index 737d38ca78..50613bd1ca 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -32,20 +32,22 @@ import ( ) type testTxRelay struct { - send, nhMined, nhRollback, discard int + send, discard, mined chan int } func (self *testTxRelay) Send(txs types.Transactions) { - self.send = len(txs) + self.send <- len(txs) } func (self *testTxRelay) NewHead(head common.Hash, mined []common.Hash, rollback []common.Hash) { - self.nhMined = len(mined) - self.nhRollback = len(rollback) + m := len(mined) + if m != 0 { + self.mined <- m + } } func (self *testTxRelay) Discard(hashes []common.Hash) { - self.discard = len(hashes) + self.discard <- len(hashes) } const poolTestTxs = 1000 @@ -73,8 +75,8 @@ func txPoolTestChainGen(i int, block *core.BlockGen) { } func TestTxPool(t *testing.T) { - for i, _ := range testTx { - testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(types.HomesteadSigner{}, testBankKey) + for i := range testTx { + testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) } var ( @@ -94,7 +96,11 @@ func TestTxPool(t *testing.T) { } odr := &testOdr{sdb: sdb, ldb: ldb} - relay := &testTxRelay{} + relay := &testTxRelay{ + send: make(chan int, 1), + discard: make(chan int, 1), + mined: make(chan int, 1), + } lightchain, _ := NewLightChain(odr, testChainConfig(), pow, evmux) lightchain.SetValidator(bproc{}) txPermanent = 50 @@ -106,36 +112,33 @@ func TestTxPool(t *testing.T) { s := sentTx(i - 1) e := sentTx(i) for i := s; i < e; i++ { - relay.send = 0 pool.Add(ctx, testTx[i]) - got := relay.send + got := <-relay.send exp := 1 if got != exp { t.Errorf("relay.Send expected len = %d, got %d", exp, got) } } - relay.nhMined = 0 - relay.nhRollback = 0 - relay.discard = 0 if _, err := lightchain.InsertHeaderChain([]*types.Header{block.Header()}, 1); err != nil { panic(err) } - time.Sleep(time.Millisecond * 30) - got := relay.nhMined + got := <-relay.mined exp := minedTx(i) - minedTx(i-1) if got != exp { t.Errorf("relay.NewHead expected len(mined) = %d, got %d", exp, got) } - got = relay.discard exp = 0 if i > int(txPermanent)+1 { exp = minedTx(i-int(txPermanent)-1) - minedTx(i-int(txPermanent)-2) } - if got != exp { - t.Errorf("relay.Discard expected len = %d, got %d", exp, got) + if exp != 0 { + got = <-relay.discard + if got != exp { + t.Errorf("relay.Discard expected len = %d, got %d", exp, got) + } } } } diff --git a/light/vm_env.go b/light/vm_env.go index b46364ad0a..ea7a3c7c2a 100644 --- a/light/vm_env.go +++ b/light/vm_env.go @@ -20,123 +20,39 @@ import ( "math/big" "github.com/ubiq/go-ubiq/common" - "github.com/ubiq/go-ubiq/core" "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/params" "golang.org/x/net/context" ) -// VMEnv is the light client version of the vm execution environment. -// Unlike other structures, VMEnv holds a context that is applied by state -// retrieval requests through the entire execution. If any state operation -// returns an error, the execution fails. -type VMEnv struct { - vm.Environment - ctx context.Context - chainConfig *params.ChainConfig - evm *vm.EVM - state *VMState - header *types.Header - msg core.Message - depth int - chain *LightChain - err error -} - -// NewEnv creates a new execution environment based on an ODR capable light state -func NewEnv(ctx context.Context, state *LightState, chainConfig *params.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv { - env := &VMEnv{ - chainConfig: chainConfig, - chain: chain, - header: header, - msg: msg, - } - env.state = &VMState{ctx: ctx, state: state, env: env} - - env.evm = vm.New(env, cfg) - return env -} - -func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig } -func (self *VMEnv) Vm() vm.Vm { return self.evm } -func (self *VMEnv) Origin() common.Address { return self.msg.From() } -func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number } -func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase } -func (self *VMEnv) Time() *big.Int { return self.header.Time } -func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty } -func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit } -func (self *VMEnv) Db() vm.Database { return self.state } -func (self *VMEnv) Depth() int { return self.depth } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) GetHash(n uint64) common.Hash { - for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { - if header.Number.Uint64() == n { - return header.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) SnapshotDatabase() int { - return self.state.SnapshotDatabase() -} - -func (self *VMEnv) RevertToSnapshot(idx int) { - self.state.RevertToSnapshot(idx) -} - -func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) { - core.Transfer(from, to, amount) -} - -func (self *VMEnv) Call(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return core.Call(self, me, addr, data, gas, price, value) -} -func (self *VMEnv) CallCode(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - return core.CallCode(self, me, addr, data, gas, price, value) -} - -func (self *VMEnv) DelegateCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - return core.DelegateCall(self, me, addr, data, gas, price) -} - -func (self *VMEnv) Create(me vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - return core.Create(self, me, data, gas, price, value) -} - -// Error returns the error (if any) that happened during execution. -func (self *VMEnv) Error() error { - return self.err -} - // VMState is a wrapper for the light state that holds the actual context and // passes it to any state operation that requires it. type VMState struct { - vm.Database ctx context.Context state *LightState snapshots []*LightState - env *VMEnv + err error } +func NewVMState(ctx context.Context, state *LightState) *VMState { + return &VMState{ctx: ctx, state: state} +} + +func (s *VMState) Error() error { + return s.err +} + +func (s *VMState) AddLog(log *types.Log) {} + // errHandler handles and stores any state error that happens during execution. func (s *VMState) errHandler(err error) { - if err != nil && s.env.err == nil { - s.env.err = err + if err != nil && s.err == nil { + s.err = err } } -func (self *VMState) SnapshotDatabase() int { +func (self *VMState) Snapshot() int { self.snapshots = append(self.snapshots, self.state.Copy()) return len(self.snapshots) - 1 } @@ -175,6 +91,12 @@ func (s *VMState) AddBalance(addr common.Address, amount *big.Int) { s.errHandler(err) } +// SubBalance adds the given amount to the balance of the specified account +func (s *VMState) SubBalance(addr common.Address, amount *big.Int) { + err := s.state.SubBalance(s.ctx, addr, amount) + s.errHandler(err) +} + // GetBalance retrieves the balance from the given address or 0 if the account does // not exist func (s *VMState) GetBalance(addr common.Address) *big.Int { diff --git a/logger/example_test.go b/logger/example_test.go deleted file mode 100644 index ce5f9da67f..0000000000 --- a/logger/example_test.go +++ /dev/null @@ -1,37 +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 . - -package logger - -import "os" - -func ExampleLogger() { - logger := NewLogger("TAG") - logger.Infoln("so awesome") // prints [TAG] so awesome - logger.Infof("this %q is raw", "coin") // prints [TAG] this "coin" is raw -} - -func ExampleLogSystem() { - filename := "test.log" - file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) - fileLog := NewStdLogSystem(file, 0, WarnLevel) - AddLogSystem(fileLog) - - stdoutLog := NewStdLogSystem(os.Stdout, 0, WarnLevel) - AddLogSystem(stdoutLog) - - NewLogger("TAG").Warnln("reactor meltdown") // writes to both logs -} diff --git a/logger/glog/glog.go b/logger/glog/glog.go index 6fe129725f..4691fa00e3 100644 --- a/logger/glog/glog.go +++ b/logger/glog/glog.go @@ -928,7 +928,7 @@ const flushInterval = 30 * time.Second // flushDaemon periodically flushes the log file buffers. func (l *loggingT) flushDaemon() { - for _ = range time.NewTicker(flushInterval).C { + for range time.NewTicker(flushInterval).C { l.lockAndFlushAll() } } diff --git a/logger/log.go b/logger/log.go deleted file mode 100644 index 77b0df8660..0000000000 --- a/logger/log.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package logger - -import ( - "fmt" - "io" - "log" - "os" - - "github.com/ubiq/go-ubiq/common" -) - -func openLogFile(datadir string, filename string) *os.File { - path := common.AbsolutePath(datadir, filename) - file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - panic(fmt.Sprintf("error opening log file '%s': %v", filename, err)) - } - return file -} - -func New(datadir string, logFile string, logLevel int) LogSystem { - var writer io.Writer - if logFile == "" { - writer = os.Stdout - } else { - writer = openLogFile(datadir, logFile) - } - - var sys LogSystem - sys = NewStdLogSystem(writer, log.LstdFlags, LogLevel(logLevel)) - AddLogSystem(sys) - - return sys -} - -func NewJSONsystem(datadir string, logFile string) LogSystem { - var writer io.Writer - if logFile == "-" { - writer = os.Stdout - } else { - writer = openLogFile(datadir, logFile) - } - - var sys LogSystem - sys = NewJsonLogSystem(writer) - AddLogSystem(sys) - - return sys -} diff --git a/logger/loggers.go b/logger/loggers.go deleted file mode 100644 index e63355d0bf..0000000000 --- a/logger/loggers.go +++ /dev/null @@ -1,149 +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 . - -/* -Package logger implements a multi-output leveled logger. - -Other packages use tagged logger to send log messages to shared -(process-wide) logging engine. The shared logging engine dispatches to -multiple log systems. The log level can be set separately per log -system. - -Logging is asynchronous and does not block the caller. Message -formatting is performed by the caller goroutine to avoid incorrect -logging of mutable state. -*/ -package logger - -import ( - "encoding/json" - "fmt" - "os" -) - -type LogLevel uint32 - -const ( - // Standard log levels - Silence LogLevel = iota - ErrorLevel - WarnLevel - InfoLevel - DebugLevel - DebugDetailLevel -) - -// A Logger prints messages prefixed by a given tag. It provides named -// Printf and Println style methods for all loglevels. Each ethereum -// component should have its own logger with a unique prefix. -type Logger struct { - tag string -} - -func NewLogger(tag string) *Logger { - return &Logger{"[" + tag + "] "} -} - -func (logger *Logger) Sendln(level LogLevel, v ...interface{}) { - logMessageC <- stdMsg{level, logger.tag + fmt.Sprintln(v...)} -} - -func (logger *Logger) Sendf(level LogLevel, format string, v ...interface{}) { - logMessageC <- stdMsg{level, logger.tag + fmt.Sprintf(format, v...)} -} - -// Errorln writes a message with ErrorLevel. -func (logger *Logger) Errorln(v ...interface{}) { - logger.Sendln(ErrorLevel, v...) -} - -// Warnln writes a message with WarnLevel. -func (logger *Logger) Warnln(v ...interface{}) { - logger.Sendln(WarnLevel, v...) -} - -// Infoln writes a message with InfoLevel. -func (logger *Logger) Infoln(v ...interface{}) { - logger.Sendln(InfoLevel, v...) -} - -// Debugln writes a message with DebugLevel. -func (logger *Logger) Debugln(v ...interface{}) { - logger.Sendln(DebugLevel, v...) -} - -// DebugDetailln writes a message with DebugDetailLevel. -func (logger *Logger) DebugDetailln(v ...interface{}) { - logger.Sendln(DebugDetailLevel, v...) -} - -// Errorf writes a message with ErrorLevel. -func (logger *Logger) Errorf(format string, v ...interface{}) { - logger.Sendf(ErrorLevel, format, v...) -} - -// Warnf writes a message with WarnLevel. -func (logger *Logger) Warnf(format string, v ...interface{}) { - logger.Sendf(WarnLevel, format, v...) -} - -// Infof writes a message with InfoLevel. -func (logger *Logger) Infof(format string, v ...interface{}) { - logger.Sendf(InfoLevel, format, v...) -} - -// Debugf writes a message with DebugLevel. -func (logger *Logger) Debugf(format string, v ...interface{}) { - logger.Sendf(DebugLevel, format, v...) -} - -// DebugDetailf writes a message with DebugDetailLevel. -func (logger *Logger) DebugDetailf(format string, v ...interface{}) { - logger.Sendf(DebugDetailLevel, format, v...) -} - -// Fatalln writes a message with ErrorLevel and exits the program. -func (logger *Logger) Fatalln(v ...interface{}) { - logger.Sendln(ErrorLevel, v...) - Flush() - os.Exit(0) -} - -// Fatalf writes a message with ErrorLevel and exits the program. -func (logger *Logger) Fatalf(format string, v ...interface{}) { - logger.Sendf(ErrorLevel, format, v...) - Flush() - os.Exit(0) -} - -type JsonLogger struct { - Coinbase string -} - -func NewJsonLogger() *JsonLogger { - return &JsonLogger{} -} - -func (logger *JsonLogger) LogJson(v JsonLog) { - msgname := v.EventName() - obj := map[string]interface{}{ - msgname: v, - } - - jsontxt, _ := json.Marshal(obj) - logMessageC <- (jsonMsg(jsontxt)) - -} diff --git a/logger/loggers_test.go b/logger/loggers_test.go deleted file mode 100644 index 85564698bc..0000000000 --- a/logger/loggers_test.go +++ /dev/null @@ -1,192 +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 . - -package logger - -import ( - "io/ioutil" - "math/rand" - "os" - "sync" - "testing" - "time" -) - -type TestLogSystem struct { - mutex sync.Mutex - output string - level LogLevel -} - -func (ls *TestLogSystem) LogPrint(msg LogMsg) { - ls.mutex.Lock() - if ls.level >= msg.Level() { - ls.output += msg.String() - } - ls.mutex.Unlock() -} - -func (ls *TestLogSystem) SetLogLevel(i LogLevel) { - ls.mutex.Lock() - ls.level = i - ls.mutex.Unlock() -} - -func (ls *TestLogSystem) GetLogLevel() LogLevel { - ls.mutex.Lock() - defer ls.mutex.Unlock() - return ls.level -} - -func (ls *TestLogSystem) CheckOutput(t *testing.T, expected string) { - ls.mutex.Lock() - output := ls.output - ls.mutex.Unlock() - if output != expected { - t.Errorf("log output mismatch:\n got: %q\n want: %q\n", output, expected) - } -} - -type blockedLogSystem struct { - LogSystem - unblock chan struct{} -} - -func (ls blockedLogSystem) LogPrint(msg LogMsg) { - <-ls.unblock - ls.LogSystem.LogPrint(msg) -} - -func TestLoggerFlush(t *testing.T) { - Reset() - - logger := NewLogger("TEST") - ls := blockedLogSystem{&TestLogSystem{level: WarnLevel}, make(chan struct{})} - AddLogSystem(ls) - for i := 0; i < 5; i++ { - // these writes shouldn't hang even though ls is blocked - logger.Errorf(".") - } - - beforeFlush := time.Now() - time.AfterFunc(80*time.Millisecond, func() { close(ls.unblock) }) - Flush() // this should hang for approx. 80ms - if blockd := time.Now().Sub(beforeFlush); blockd < 80*time.Millisecond { - t.Errorf("Flush didn't block long enough, blocked for %v, should've been >= 80ms", blockd) - } - - ls.LogSystem.(*TestLogSystem).CheckOutput(t, "[TEST] .[TEST] .[TEST] .[TEST] .[TEST] .") -} - -func TestLoggerPrintln(t *testing.T) { - Reset() - - logger := NewLogger("TEST") - testLogSystem := &TestLogSystem{level: WarnLevel} - AddLogSystem(testLogSystem) - logger.Errorln("error") - logger.Warnln("warn") - logger.Infoln("info") - logger.Debugln("debug") - Flush() - - testLogSystem.CheckOutput(t, "[TEST] error\n[TEST] warn\n") -} - -func TestLoggerPrintf(t *testing.T) { - Reset() - - logger := NewLogger("TEST") - testLogSystem := &TestLogSystem{level: WarnLevel} - AddLogSystem(testLogSystem) - logger.Errorf("error to %v\n", []int{1, 2, 3}) - logger.Warnf("warn %%d %d", 5) - logger.Infof("info") - logger.Debugf("debug") - Flush() - testLogSystem.CheckOutput(t, "[TEST] error to [1 2 3]\n[TEST] warn %d 5") -} - -func TestMultipleLogSystems(t *testing.T) { - Reset() - - logger := NewLogger("TEST") - testLogSystem0 := &TestLogSystem{level: ErrorLevel} - testLogSystem1 := &TestLogSystem{level: WarnLevel} - AddLogSystem(testLogSystem0) - AddLogSystem(testLogSystem1) - logger.Errorln("error") - logger.Warnln("warn") - Flush() - - testLogSystem0.CheckOutput(t, "[TEST] error\n") - testLogSystem1.CheckOutput(t, "[TEST] error\n[TEST] warn\n") -} - -func TestFileLogSystem(t *testing.T) { - Reset() - - logger := NewLogger("TEST") - filename := "test.log" - file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) - testLogSystem := NewStdLogSystem(file, 0, WarnLevel) - AddLogSystem(testLogSystem) - logger.Errorf("error to %s\n", filename) - logger.Warnln("warn") - Flush() - contents, _ := ioutil.ReadFile(filename) - output := string(contents) - if output != "[TEST] error to test.log\n[TEST] warn\n" { - t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", output) - } else { - os.Remove(filename) - } -} - -func TestNoLogSystem(t *testing.T) { - Reset() - - logger := NewLogger("TEST") - logger.Warnln("warn") - Flush() -} - -func TestConcurrentAddSystem(t *testing.T) { - rand.Seed(time.Now().Unix()) - Reset() - - logger := NewLogger("TEST") - stop := make(chan struct{}) - writer := func() { - select { - case <-stop: - return - default: - logger.Infoln("foo") - Flush() - } - } - - go writer() - go writer() - - stopTime := time.Now().Add(100 * time.Millisecond) - for time.Now().Before(stopTime) { - time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond) - AddLogSystem(NewStdLogSystem(ioutil.Discard, 0, InfoLevel)) - } - close(stop) -} diff --git a/logger/logsystem.go b/logger/logsystem.go deleted file mode 100644 index 24f4351d49..0000000000 --- a/logger/logsystem.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package logger - -import ( - "io" - "log" - "sync/atomic" -) - -// LogSystem is implemented by log output devices. -// All methods can be called concurrently from multiple goroutines. -type LogSystem interface { - LogPrint(LogMsg) -} - -// NewStdLogSystem creates a LogSystem that prints to the given writer. -// The flag values are defined package log. -func NewStdLogSystem(writer io.Writer, flags int, level LogLevel) *StdLogSystem { - logger := log.New(writer, "", flags) - return &StdLogSystem{logger, uint32(level)} -} - -type StdLogSystem struct { - logger *log.Logger - level uint32 -} - -func (t *StdLogSystem) LogPrint(msg LogMsg) { - stdmsg, ok := msg.(stdMsg) - if ok { - if t.GetLogLevel() >= stdmsg.Level() { - t.logger.Print(stdmsg.String()) - } - } -} - -func (t *StdLogSystem) SetLogLevel(i LogLevel) { - atomic.StoreUint32(&t.level, uint32(i)) -} - -func (t *StdLogSystem) GetLogLevel() LogLevel { - return LogLevel(atomic.LoadUint32(&t.level)) -} - -// NewJSONLogSystem creates a LogSystem that prints to the given writer without -// adding extra information irrespective of loglevel only if message is JSON type -func NewJsonLogSystem(writer io.Writer) LogSystem { - logger := log.New(writer, "", 0) - return &jsonLogSystem{logger} -} - -type jsonLogSystem struct { - logger *log.Logger -} - -func (t *jsonLogSystem) LogPrint(msg LogMsg) { - jsonmsg, ok := msg.(jsonMsg) - if ok { - t.logger.Print(jsonmsg.String()) - } -} diff --git a/logger/sys.go b/logger/sys.go deleted file mode 100644 index 18d4ea641c..0000000000 --- a/logger/sys.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package logger - -import ( - "fmt" - "sync" -) - -type stdMsg struct { - level LogLevel - msg string -} - -type jsonMsg []byte - -func (m jsonMsg) Level() LogLevel { - return 0 -} - -func (m jsonMsg) String() string { - return string(m) -} - -type LogMsg interface { - Level() LogLevel - fmt.Stringer -} - -func (m stdMsg) Level() LogLevel { - return m.level -} - -func (m stdMsg) String() string { - return m.msg -} - -var ( - logMessageC = make(chan LogMsg) - addSystemC = make(chan LogSystem) - flushC = make(chan chan struct{}) - resetC = make(chan chan struct{}) -) - -func init() { - go dispatchLoop() -} - -// each system can buffer this many messages before -// blocking incoming log messages. -const sysBufferSize = 500 - -func dispatchLoop() { - var ( - systems []LogSystem - systemIn []chan LogMsg - systemWG sync.WaitGroup - ) - bootSystem := func(sys LogSystem) { - in := make(chan LogMsg, sysBufferSize) - systemIn = append(systemIn, in) - systemWG.Add(1) - go sysLoop(sys, in, &systemWG) - } - - for { - select { - case msg := <-logMessageC: - for _, c := range systemIn { - c <- msg - } - - case sys := <-addSystemC: - systems = append(systems, sys) - bootSystem(sys) - - case waiter := <-resetC: - // reset means terminate all systems - for _, c := range systemIn { - close(c) - } - systems = nil - systemIn = nil - systemWG.Wait() - close(waiter) - - case waiter := <-flushC: - // flush means reboot all systems - for _, c := range systemIn { - close(c) - } - systemIn = nil - systemWG.Wait() - for _, sys := range systems { - bootSystem(sys) - } - close(waiter) - } - } -} - -func sysLoop(sys LogSystem, in <-chan LogMsg, wg *sync.WaitGroup) { - for msg := range in { - sys.LogPrint(msg) - } - wg.Done() -} - -// Reset removes all active log systems. -// It blocks until all current messages have been delivered. -func Reset() { - waiter := make(chan struct{}) - resetC <- waiter - <-waiter -} - -// Flush waits until all current log messages have been dispatched to -// the active log systems. -func Flush() { - waiter := make(chan struct{}) - flushC <- waiter - <-waiter -} - -// AddLogSystem starts printing messages to the given LogSystem. -func AddLogSystem(sys LogSystem) { - addSystemC <- sys -} diff --git a/logger/types.go b/logger/types.go deleted file mode 100644 index ee7e845de8..0000000000 --- a/logger/types.go +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package logger - -import ( - "math/big" - "time" -) - -type utctime8601 struct{} - -func (utctime8601) MarshalJSON() ([]byte, error) { - timestr := time.Now().UTC().Format(time.RFC3339Nano) - // Bounds check - if len(timestr) > 26 { - timestr = timestr[:26] - } - return []byte(`"` + timestr + `Z"`), nil -} - -type JsonLog interface { - EventName() string -} - -type LogEvent struct { - // Guid string `json:"guid"` - Ts utctime8601 `json:"ts"` - // Level string `json:"level"` -} - -type LogStarting struct { - ClientString string `json:"client_impl"` - ProtocolVersion int `json:"eth_version"` - LogEvent -} - -func (l *LogStarting) EventName() string { - return "starting" -} - -type P2PConnected struct { - RemoteId string `json:"remote_id"` - RemoteAddress string `json:"remote_addr"` - RemoteVersionString string `json:"remote_version_string"` - NumConnections int `json:"num_connections"` - LogEvent -} - -func (l *P2PConnected) EventName() string { - return "p2p.connected" -} - -type P2PDisconnected struct { - NumConnections int `json:"num_connections"` - RemoteId string `json:"remote_id"` - LogEvent -} - -func (l *P2PDisconnected) EventName() string { - return "p2p.disconnected" -} - -type EthMinerNewBlock struct { - BlockHash string `json:"block_hash"` - BlockNumber *big.Int `json:"block_number"` - ChainHeadHash string `json:"chain_head_hash"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthMinerNewBlock) EventName() string { - return "eth.miner.new_block" -} - -type EthChainReceivedNewBlock struct { - BlockHash string `json:"block_hash"` - BlockNumber *big.Int `json:"block_number"` - ChainHeadHash string `json:"chain_head_hash"` - BlockPrevHash string `json:"block_prev_hash"` - RemoteId string `json:"remote_id"` - LogEvent -} - -func (l *EthChainReceivedNewBlock) EventName() string { - return "eth.chain.received.new_block" -} - -type EthChainNewHead struct { - BlockHash string `json:"block_hash"` - BlockNumber *big.Int `json:"block_number"` - ChainHeadHash string `json:"chain_head_hash"` - BlockPrevHash string `json:"block_prev_hash"` - LogEvent -} - -func (l *EthChainNewHead) EventName() string { - return "eth.chain.new_head" -} - -type EthTxReceived struct { - TxHash string `json:"tx_hash"` - RemoteId string `json:"remote_id"` - LogEvent -} - -func (l *EthTxReceived) EventName() string { - return "eth.tx.received" -} - -// -// -// The types below are legacy and need to be converted to new format or deleted -// -// - -// type P2PConnecting struct { -// RemoteId string `json:"remote_id"` -// RemoteEndpoint string `json:"remote_endpoint"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PConnecting) EventName() string { -// return "p2p.connecting" -// } - -// type P2PHandshaked struct { -// RemoteCapabilities []string `json:"remote_capabilities"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PHandshaked) EventName() string { -// return "p2p.handshaked" -// } - -// type P2PDisconnecting struct { -// Reason string `json:"reason"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PDisconnecting) EventName() string { -// return "p2p.disconnecting" -// } - -// type P2PDisconnectingBadHandshake struct { -// Reason string `json:"reason"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PDisconnectingBadHandshake) EventName() string { -// return "p2p.disconnecting.bad_handshake" -// } - -// type P2PDisconnectingBadProtocol struct { -// Reason string `json:"reason"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PDisconnectingBadProtocol) EventName() string { -// return "p2p.disconnecting.bad_protocol" -// } - -// type P2PDisconnectingReputation struct { -// Reason string `json:"reason"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PDisconnectingReputation) EventName() string { -// return "p2p.disconnecting.reputation" -// } - -// type P2PDisconnectingDHT struct { -// Reason string `json:"reason"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PDisconnectingDHT) EventName() string { -// return "p2p.disconnecting.dht" -// } - -// type P2PEthDisconnectingBadBlock struct { -// Reason string `json:"reason"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PEthDisconnectingBadBlock) EventName() string { -// return "p2p.eth.disconnecting.bad_block" -// } - -// type P2PEthDisconnectingBadTx struct { -// Reason string `json:"reason"` -// RemoteId string `json:"remote_id"` -// NumConnections int `json:"num_connections"` -// LogEvent -// } - -// func (l *P2PEthDisconnectingBadTx) EventName() string { -// return "p2p.eth.disconnecting.bad_tx" -// } - -// type EthNewBlockBroadcasted struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockBroadcasted) EventName() string { -// return "eth.newblock.broadcasted" -// } - -// type EthNewBlockIsKnown struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockIsKnown) EventName() string { -// return "eth.newblock.is_known" -// } - -// type EthNewBlockIsNew struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockIsNew) EventName() string { -// return "eth.newblock.is_new" -// } - -// type EthNewBlockMissingParent struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockMissingParent) EventName() string { -// return "eth.newblock.missing_parent" -// } - -// type EthNewBlockIsInvalid struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockIsInvalid) EventName() string { -// return "eth.newblock.is_invalid" -// } - -// type EthNewBlockChainIsOlder struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockChainIsOlder) EventName() string { -// return "eth.newblock.chain.is_older" -// } - -// type EthNewBlockChainIsCanonical struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockChainIsCanonical) EventName() string { -// return "eth.newblock.chain.is_cannonical" -// } - -// type EthNewBlockChainNotCanonical struct { -// BlockNumber int `json:"block_number"` -// HeadHash string `json:"head_hash"` -// BlockHash string `json:"block_hash"` -// BlockDifficulty int `json:"block_difficulty"` -// BlockPrevHash string `json:"block_prev_hash"` -// LogEvent -// } - -// func (l *EthNewBlockChainNotCanonical) EventName() string { -// return "eth.newblock.chain.not_cannonical" -// } - -// type EthTxCreated struct { -// TxHash string `json:"tx_hash"` -// TxSender string `json:"tx_sender"` -// TxAddress string `json:"tx_address"` -// TxHexRLP string `json:"tx_hexrlp"` -// TxNonce int `json:"tx_nonce"` -// LogEvent -// } - -// func (l *EthTxCreated) EventName() string { -// return "eth.tx.created" -// } - -// type EthTxBroadcasted struct { -// TxHash string `json:"tx_hash"` -// TxSender string `json:"tx_sender"` -// TxAddress string `json:"tx_address"` -// TxNonce int `json:"tx_nonce"` -// LogEvent -// } - -// func (l *EthTxBroadcasted) EventName() string { -// return "eth.tx.broadcasted" -// } - -// type EthTxValidated struct { -// TxHash string `json:"tx_hash"` -// TxSender string `json:"tx_sender"` -// TxAddress string `json:"tx_address"` -// TxNonce int `json:"tx_nonce"` -// LogEvent -// } - -// func (l *EthTxValidated) EventName() string { -// return "eth.tx.validated" -// } - -// type EthTxIsInvalid struct { -// TxHash string `json:"tx_hash"` -// TxSender string `json:"tx_sender"` -// TxAddress string `json:"tx_address"` -// Reason string `json:"reason"` -// TxNonce int `json:"tx_nonce"` -// LogEvent -// } - -// func (l *EthTxIsInvalid) EventName() string { -// return "eth.tx.is_invalid" -// } diff --git a/metrics/disk_linux.go b/metrics/disk_linux.go index d0eac08b91..8d610cd674 100644 --- a/metrics/disk_linux.go +++ b/metrics/disk_linux.go @@ -47,15 +47,16 @@ func ReadDiskStats(stats *DiskStats) error { } return err } - key, value := "", int64(0) - if parts := strings.Split(line, ":"); len(parts) != 2 { + parts := strings.Split(line, ":") + if len(parts) != 2 { continue - } else { - key = strings.TrimSpace(parts[0]) - if value, err = strconv.ParseInt(strings.TrimSpace(parts[1]), 10, 64); err != nil { - return err - } } + key := strings.TrimSpace(parts[0]) + value, err := strconv.ParseInt(strings.TrimSpace(parts[1]), 10, 64) + if err != nil { + return err + } + // Update the counter based on the key switch key { case "syscr": diff --git a/miner/agent.go b/miner/agent.go index 999aae6b6d..aef0176633 100644 --- a/miner/agent.go +++ b/miner/agent.go @@ -22,6 +22,7 @@ import ( "sync/atomic" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/logger" "github.com/ubiq/go-ubiq/logger/glog" "github.com/ubiq/go-ubiq/pow" @@ -112,7 +113,7 @@ func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) { // Mine nonce, mixDigest := self.pow.Search(work.Block, stop, self.index) if nonce != 0 { - block := work.Block.WithMiningResult(nonce, common.BytesToHash(mixDigest)) + block := work.Block.WithMiningResult(types.EncodeNonce(nonce), common.BytesToHash(mixDigest)) self.returnCh <- &Result{work, block} } else { self.returnCh <- nil diff --git a/miner/miner.go b/miner/miner.go index c6c8f8454a..9167d8c89d 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -119,15 +119,14 @@ func (m *Miner) SetGasPrice(price *big.Int) { func (self *Miner) Start(coinbase common.Address, threads int) { atomic.StoreInt32(&self.shouldStart, 1) - self.threads = threads - self.worker.coinbase = coinbase + self.worker.setEtherbase(coinbase) self.coinbase = coinbase + self.threads = threads if atomic.LoadInt32(&self.canStart) == 0 { glog.V(logger.Info).Infoln("Can not start mining operation due to network sync (starts when finished)") return } - atomic.StoreInt32(&self.mining, 1) for i := 0; i < threads; i++ { @@ -135,9 +134,7 @@ func (self *Miner) Start(coinbase common.Address, threads int) { } glog.V(logger.Info).Infof("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents)) - self.worker.start() - self.worker.commitNewWork() } @@ -177,8 +174,7 @@ func (self *Miner) SetExtra(extra []byte) error { if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() { return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize) } - - self.worker.extra = extra + self.worker.setExtra(extra) return nil } @@ -188,9 +184,9 @@ func (self *Miner) Pending() (*types.Block, *state.StateDB) { } // PendingBlock returns the currently pending block. -// -// Note, to access both the pending block and the pending state -// simultaneously, please use Pending(), as the pending state can +// +// Note, to access both the pending block and the pending state +// simultaneously, please use Pending(), as the pending state can // change between multiple method calls func (self *Miner) PendingBlock() *types.Block { return self.worker.pendingBlock() diff --git a/miner/remote_agent.go b/miner/remote_agent.go index aa77bb4a4c..41dcd7388a 100644 --- a/miner/remote_agent.go +++ b/miner/remote_agent.go @@ -25,8 +25,10 @@ import ( "github.com/ethereum/ethash" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/core/types" "github.com/ubiq/go-ubiq/logger" "github.com/ubiq/go-ubiq/logger/glog" + "github.com/ubiq/go-ubiq/pow" ) type hashrate struct { @@ -37,10 +39,11 @@ type hashrate struct { type RemoteAgent struct { mu sync.Mutex - quit chan struct{} + quitCh chan struct{} workCh chan *Work returnCh chan<- *Result + pow pow.PoW currentWork *Work work map[common.Hash]*Work @@ -50,8 +53,9 @@ type RemoteAgent struct { running int32 // running indicates whether the agent is active. Call atomically } -func NewRemoteAgent() *RemoteAgent { +func NewRemoteAgent(pow pow.PoW) *RemoteAgent { return &RemoteAgent{ + pow: pow, work: make(map[common.Hash]*Work), hashrate: make(map[common.Hash]hashrate), } @@ -76,18 +80,16 @@ func (a *RemoteAgent) Start() { if !atomic.CompareAndSwapInt32(&a.running, 0, 1) { return } - - a.quit = make(chan struct{}) + a.quitCh = make(chan struct{}) a.workCh = make(chan *Work, 1) - go a.maintainLoop() + go a.loop(a.workCh, a.quitCh) } func (a *RemoteAgent) Stop() { if !atomic.CompareAndSwapInt32(&a.running, 1, 0) { return } - - close(a.quit) + close(a.quitCh) close(a.workCh) } @@ -128,35 +130,46 @@ func (a *RemoteAgent) GetWork() ([3]string, error) { return res, errors.New("No work available yet, don't panic.") } -// Returns true or false, but does not indicate if the PoW was correct -func (a *RemoteAgent) SubmitWork(nonce uint64, mixDigest, hash common.Hash) bool { +// SubmitWork tries to inject a PoW solution tinto the remote agent, returning +// whether the solution was acceted or not (not can be both a bad PoW as well as +// any other error, like no work pending). +func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.Hash) bool { a.mu.Lock() defer a.mu.Unlock() // Make sure the work submitted is present - if a.work[hash] != nil { - block := a.work[hash].Block.WithMiningResult(nonce, mixDigest) - a.returnCh <- &Result{a.work[hash], block} - - delete(a.work, hash) - - return true - } else { - glog.V(logger.Info).Infof("Work was submitted for %x but no pending work found\n", hash) + work := a.work[hash] + if work == nil { + glog.V(logger.Info).Infof("Work was submitted for %x but no pending work found", hash) + return false } + // Make sure the PoW solutions is indeed valid + block := work.Block.WithMiningResult(nonce, mixDigest) + if !a.pow.Verify(block) { + glog.V(logger.Warn).Infof("Invalid PoW submitted for %x", hash) + return false + } + // Solutions seems to be valid, return to the miner and notify acceptance + a.returnCh <- &Result{work, block} + delete(a.work, hash) - return false + return true } -func (a *RemoteAgent) maintainLoop() { +// loop monitors mining events on the work and quit channels, updating the internal +// state of the rmeote miner until a termination is requested. +// +// Note, the reason the work and quit channels are passed as parameters is because +// RemoteAgent.Start() constantly recreates these channels, so the loop code cannot +// assume data stability in these member fields. +func (a *RemoteAgent) loop(workCh chan *Work, quitCh chan struct{}) { ticker := time.Tick(5 * time.Second) -out: for { select { - case <-a.quit: - break out - case work := <-a.workCh: + case <-quitCh: + return + case work := <-workCh: a.mu.Lock() a.currentWork = work a.mu.Unlock() diff --git a/miner/unconfirmed.go b/miner/unconfirmed.go new file mode 100644 index 0000000000..1a1912c12a --- /dev/null +++ b/miner/unconfirmed.go @@ -0,0 +1,118 @@ +// 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 . + +package miner + +import ( + "container/ring" + "sync" + + "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/core/types" + "github.com/ubiq/go-ubiq/logger" + "github.com/ubiq/go-ubiq/logger/glog" +) + +// headerRetriever is used by the unconfirmed block set to verify whether a previously +// mined block is part of the canonical chain or not. +type headerRetriever interface { + // GetHeaderByNumber retrieves the canonical header associated with a block number. + GetHeaderByNumber(number uint64) *types.Header +} + +// unconfirmedBlock is a small collection of metadata about a locally mined block +// that is placed into a unconfirmed set for canonical chain inclusion tracking. +type unconfirmedBlock struct { + index uint64 + hash common.Hash +} + +// unconfirmedBlocks implements a data structure to maintain locally mined blocks +// have have not yet reached enough maturity to guarantee chain inclusion. It is +// used by the miner to provide logs to the user when a previously mined block +// has a high enough guarantee to not be reorged out of te canonical chain. +type unconfirmedBlocks struct { + chain headerRetriever // Blockchain to verify canonical status through + depth uint // Depth after which to discard previous blocks + blocks *ring.Ring // Block infos to allow canonical chain cross checks + lock sync.RWMutex // Protects the fields from concurrent access +} + +// newUnconfirmedBlocks returns new data structure to track currently unconfirmed blocks. +func newUnconfirmedBlocks(chain headerRetriever, depth uint) *unconfirmedBlocks { + return &unconfirmedBlocks{ + chain: chain, + depth: depth, + } +} + +// Insert adds a new block to the set of unconfirmed ones. +func (set *unconfirmedBlocks) Insert(index uint64, hash common.Hash) { + // If a new block was mined locally, shift out any old enough blocks + set.Shift(index) + + // Create the new item as its own ring + item := ring.New(1) + item.Value = &unconfirmedBlock{ + index: index, + hash: hash, + } + // Set as the initial ring or append to the end + set.lock.Lock() + defer set.lock.Unlock() + + if set.blocks == nil { + set.blocks = item + } else { + set.blocks.Move(-1).Link(item) + } + // Display a log for the user to notify of a new mined block unconfirmed + glog.V(logger.Info).Infof("🔨 mined potential block #%d [%x…], waiting for %d blocks to confirm", index, hash.Bytes()[:4], set.depth) +} + +// Shift drops all unconfirmed blocks from the set which exceed the unconfirmed sets depth +// allowance, checking them against the canonical chain for inclusion or staleness +// report. +func (set *unconfirmedBlocks) Shift(height uint64) { + set.lock.Lock() + defer set.lock.Unlock() + + for set.blocks != nil { + // Retrieve the next unconfirmed block and abort if too fresh + next := set.blocks.Value.(*unconfirmedBlock) + if next.index+uint64(set.depth) > height { + break + } + // Block seems to exceed depth allowance, check for canonical status + header := set.chain.GetHeaderByNumber(next.index) + switch { + case header == nil: + glog.V(logger.Warn).Infof("failed to retrieve header of mined block #%d [%x…]", next.index, next.hash.Bytes()[:4]) + case header.Hash() == next.hash: + glog.V(logger.Info).Infof("🔗 mined block #%d [%x…] reached canonical chain", next.index, next.hash.Bytes()[:4]) + default: + glog.V(logger.Info).Infof("⑂ mined block #%d [%x…] became a side fork", next.index, next.hash.Bytes()[:4]) + } + // Drop the block out of the ring + if set.blocks.Value == set.blocks.Next().Value { + set.blocks = nil + } else { + set.blocks = set.blocks.Move(-1) + set.blocks.Unlink(1) + set.blocks = set.blocks.Move(1) + } + } +} diff --git a/miner/unconfirmed_test.go b/miner/unconfirmed_test.go new file mode 100644 index 0000000000..8a5f581201 --- /dev/null +++ b/miner/unconfirmed_test.go @@ -0,0 +1,85 @@ +// 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 . + +package miner + +import ( + "testing" + + "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/core/types" +) + +// noopHeaderRetriever is an implementation of headerRetriever that always +// returns nil for any requested headers. +type noopHeaderRetriever struct{} + +func (r *noopHeaderRetriever) GetHeaderByNumber(number uint64) *types.Header { + return nil +} + +// Tests that inserting blocks into the unconfirmed set accumulates them until +// the desired depth is reached, after which they begin to be dropped. +func TestUnconfirmedInsertBounds(t *testing.T) { + limit := uint(10) + + pool := newUnconfirmedBlocks(new(noopHeaderRetriever), limit) + for depth := uint64(0); depth < 2*uint64(limit); depth++ { + // Insert multiple blocks for the same level just to stress it + for i := 0; i < int(depth); i++ { + pool.Insert(depth, common.Hash([32]byte{byte(depth), byte(i)})) + } + // Validate that no blocks below the depth allowance are left in + pool.blocks.Do(func(block interface{}) { + if block := block.(*unconfirmedBlock); block.index+uint64(limit) <= depth { + t.Errorf("depth %d: block %x not dropped", depth, block.hash) + } + }) + } +} + +// Tests that shifting blocks out of the unconfirmed set works both for normal +// cases as well as for corner cases such as empty sets, empty shifts or full +// shifts. +func TestUnconfirmedShifts(t *testing.T) { + // Create a pool with a few blocks on various depths + limit, start := uint(10), uint64(25) + + pool := newUnconfirmedBlocks(new(noopHeaderRetriever), limit) + for depth := start; depth < start+uint64(limit); depth++ { + pool.Insert(depth, common.Hash([32]byte{byte(depth)})) + } + // Try to shift below the limit and ensure no blocks are dropped + pool.Shift(start + uint64(limit) - 1) + if n := pool.blocks.Len(); n != int(limit) { + t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit) + } + // Try to shift half the blocks out and verify remainder + pool.Shift(start + uint64(limit) - 1 + uint64(limit/2)) + if n := pool.blocks.Len(); n != int(limit)/2 { + t.Errorf("unconfirmed count mismatch: have %d, want %d", n, limit/2) + } + // Try to shift all the remaining blocks out and verify emptyness + pool.Shift(start + 2*uint64(limit)) + if n := pool.blocks.Len(); n != 0 { + t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0) + } + // Try to shift out from the empty set and make sure it doesn't break + pool.Shift(start + 3*uint64(limit)) + if n := pool.blocks.Len(); n != 0 { + t.Errorf("unconfirmed count mismatch: have %d, want %d", n, 0) + } +} diff --git a/miner/worker.go b/miner/worker.go index 3dc2e9f544..b38d67c3ae 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -38,8 +38,6 @@ import ( "gopkg.in/fatih/set.v0" ) -var jsonlogger = logger.NewJsonLogger() - const ( resultQueueSize = 10 miningLogAtDepth = 5 @@ -54,26 +52,20 @@ type Agent interface { GetHashRate() int64 } -type uint64RingBuffer struct { - ints []uint64 //array of all integers in buffer - next int //where is the next insertion? assert 0 <= next < len(ints) -} - // Work is the workers current environment and holds // all of the current state information type Work struct { config *params.ChainConfig signer types.Signer - state *state.StateDB // apply state changes here - ancestors *set.Set // ancestor set (used for checking uncle parent validity) - family *set.Set // family set (used for checking uncle invalidity) - uncles *set.Set // uncle set - tcount int // tx count in cycle - ownedAccounts *set.Set - lowGasTxs types.Transactions - failedTxs types.Transactions - localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion) + state *state.StateDB // apply state changes here + ancestors *set.Set // ancestor set (used for checking uncle parent validity) + family *set.Set // family set (used for checking uncle invalidity) + uncles *set.Set // uncle set + tcount int // tx count in cycle + ownedAccounts *set.Set + lowGasTxs types.Transactions + failedTxs types.Transactions Block *types.Block // the new block @@ -122,6 +114,8 @@ type worker struct { txQueueMu sync.Mutex txQueue map[common.Hash]*types.Transaction + unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations + // atomic status counters mining int32 atWork int32 @@ -143,6 +137,7 @@ func newWorker(config *params.ChainConfig, coinbase common.Address, eth Backend, coinbase: coinbase, txQueue: make(map[common.Hash]*types.Transaction), agents: make(map[Agent]struct{}), + unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), 5), fullValidation: false, } worker.events = worker.mux.Subscribe(core.ChainHeadEvent{}, core.ChainSideEvent{}, core.TxPreEvent{}) @@ -160,6 +155,12 @@ func (self *worker) setEtherbase(addr common.Address) { self.coinbase = addr } +func (self *worker) setExtra(extra []byte) { + self.mu.Lock() + defer self.mu.Unlock() + self.extra = extra +} + func (self *worker) pending() (*types.Block, *state.StateDB) { self.currentMu.Lock() defer self.currentMu.Unlock() @@ -252,7 +253,7 @@ func (self *worker) update() { self.currentMu.Lock() acc, _ := types.Sender(self.current.signer, ev.Tx) - txs := map[common.Address]types.Transactions{acc: types.Transactions{ev.Tx}} + txs := map[common.Address]types.Transactions{acc: {ev.Tx}} txset := types.NewTransactionsByPriceAndNonce(txs) self.current.commitTransactions(self.mux, txset, self.gasPrice, self.chain) @@ -262,18 +263,6 @@ func (self *worker) update() { } } -func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *uint64RingBuffer) (minedBlocks *uint64RingBuffer) { - if prevMinedBlocks == nil { - minedBlocks = &uint64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth+1)} - } else { - minedBlocks = prevMinedBlocks - } - - minedBlocks.ints[minedBlocks.next] = blockNumber - minedBlocks.next = (minedBlocks.next + 1) % len(minedBlocks.ints) - return minedBlocks -} - func (self *worker) wait() { for { mustCommitNewWork := true @@ -335,7 +324,7 @@ func (self *worker) wait() { } // broadcast before waiting for validation - go func(block *types.Block, logs vm.Logs, receipts []*types.Receipt) { + go func(block *types.Block, logs []*types.Log, receipts []*types.Receipt) { self.mux.Post(core.NewMinedBlockEvent{Block: block}) self.mux.Post(core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) @@ -348,17 +337,8 @@ func (self *worker) wait() { } }(block, work.state.Logs(), work.receipts) } - - // check staleness and display confirmation - var stale, confirm string - canonBlock := self.chain.GetBlockByNumber(block.NumberU64()) - if canonBlock != nil && canonBlock.Hash() != block.Hash() { - stale = "stale " - } else { - confirm = "Wait 5 blocks for confirmation" - work.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), work.localMinedBlocks) - } - glog.V(logger.Info).Infof("🔨 Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm) + // Insert the block into the set of pending ones to wait for confirmations + self.unconfirmed.Insert(block.NumberU64(), block.Hash()) if mustCommitNewWork { self.commitNewWork() @@ -410,9 +390,6 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error // Keep track of transactions which return errors so they can be removed work.tcount = 0 work.ownedAccounts = accountAddressesSet(accounts) - if self.current != nil { - work.localMinedBlocks = self.current.localMinedBlocks - } self.current = work return nil } @@ -428,38 +405,6 @@ func (w *worker) setGasPrice(p *big.Int) { w.mux.Post(core.GasPriceChanged{Price: w.gasPrice}) } -func (self *worker) isBlockLocallyMined(current *Work, deepBlockNum uint64) bool { - //Did this instance mine a block at {deepBlockNum} ? - var isLocal = false - for idx, blockNum := range current.localMinedBlocks.ints { - if deepBlockNum == blockNum { - isLocal = true - current.localMinedBlocks.ints[idx] = 0 //prevent showing duplicate logs - break - } - } - //Short-circuit on false, because the previous and following tests must both be true - if !isLocal { - return false - } - - //Does the block at {deepBlockNum} send earnings to my coinbase? - var block = self.chain.GetBlockByNumber(deepBlockNum) - return block != nil && block.Coinbase() == self.coinbase -} - -func (self *worker) logLocalMinedBlocks(current, previous *Work) { - if previous != nil && current.localMinedBlocks != nil { - nextBlockNum := current.Block.NumberU64() - for checkBlockNum := previous.Block.NumberU64(); checkBlockNum < nextBlockNum; checkBlockNum++ { - inspectBlockNum := checkBlockNum - miningLogAtDepth - if self.isBlockLocallyMined(current, inspectBlockNum) { - glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum) - } - } - } -} - func (self *worker) commitNewWork() { self.mu.Lock() defer self.mu.Unlock() @@ -493,7 +438,6 @@ func (self *worker) commitNewWork() { Extra: self.extra, Time: big.NewInt(tstamp), } - previous := self.current // Could potentially happen if starting to mine in an odd state. err := self.makeCurrent(parent, header) if err != nil { @@ -502,7 +446,13 @@ func (self *worker) commitNewWork() { } // Create the current work task and check any fork transitions needed work := self.current - txs := types.NewTransactionsByPriceAndNonce(self.eth.TxPool().Pending()) + pending, err := self.eth.TxPool().Pending() + if err != nil { + glog.Errorf("Could not fetch pending transactions: %v", err) + return + } + + txs := types.NewTransactionsByPriceAndNonce(pending) work.commitTransactions(self.mux, txs, self.gasPrice, self.chain) self.eth.TxPool().RemoveBatch(work.lowGasTxs) @@ -524,7 +474,7 @@ func (self *worker) commitNewWork() { } badUncles = append(badUncles, hash) } else { - glog.V(logger.Debug).Infof("commiting %x as uncle\n", hash[:4]) + glog.V(logger.Debug).Infof("committing %x as uncle\n", hash[:4]) uncles = append(uncles, uncle.Header()) } } @@ -544,7 +494,7 @@ func (self *worker) commitNewWork() { // We only care about logging if we're actually mining. if atomic.LoadInt32(&self.mining) == 1 { glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", work.Block.Number(), work.tcount, len(uncles), time.Since(tstart)) - self.logLocalMinedBlocks(work, previous) + self.unconfirmed.Shift(work.Block.NumberU64() - 1) } self.push(work) } @@ -567,7 +517,7 @@ func (self *worker) commitUncle(work *Work, uncle *types.Header) error { func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, gasPrice *big.Int, bc *core.BlockChain) { gp := new(core.GasPool).AddGas(env.header.GasLimit) - var coalescedLogs vm.Logs + var coalescedLogs []*types.Log for { // Retrieve the next transaction and abort if all done @@ -627,12 +577,12 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB // make a copy, the state caches the logs and these logs get "upgraded" from pending to mined // logs by filling in the block hash when the block was mined by the local miner. This can // cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. - cpy := make(vm.Logs, len(coalescedLogs)) + cpy := make([]*types.Log, len(coalescedLogs)) for i, l := range coalescedLogs { - cpy[i] = new(vm.Log) + cpy[i] = new(types.Log) *cpy[i] = *l } - go func(logs vm.Logs, tcount int) { + go func(logs []*types.Log, tcount int) { if len(logs) > 0 { mux.Post(core.PendingLogsEvent{Logs: logs}) } @@ -643,10 +593,10 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB } } -func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) { +func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, []*types.Log) { snap := env.state.Snapshot() - receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{}) + receipt, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{}) if err != nil { env.state.RevertToSnapshot(snap) return err, nil @@ -654,7 +604,7 @@ func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, g env.txs = append(env.txs, tx) env.receipts = append(env.receipts, receipt) - return nil, logs + return nil, receipt.Logs } // TODO: remove or use diff --git a/mobile/accounts.go b/mobile/accounts.go index afdd36d9a9..57f6803a0b 100644 --- a/mobile/accounts.go +++ b/mobile/accounts.go @@ -56,7 +56,7 @@ func (a *Accounts) Size() int { } // Get returns the account at the given index from the slice. -func (a *Accounts) Get(index int) (*Account, error) { +func (a *Accounts) Get(index int) (account *Account, _ error) { if index < 0 || index >= len(a.accounts) { return nil, errors.New("index out of bounds") } @@ -91,8 +91,8 @@ func NewAccountManager(keydir string, scryptN, scryptP int) *AccountManager { } // HasAddress reports whether a key with the given address is present. -func (am *AccountManager) HasAddress(addr *Address) bool { - return am.manager.HasAddress(addr.address) +func (am *AccountManager) HasAddress(address *Address) bool { + return am.manager.HasAddress(address.address) } // GetAccounts returns all key files present in the directory. @@ -102,43 +102,45 @@ func (am *AccountManager) GetAccounts() *Accounts { // DeleteAccount deletes the key matched by account if the passphrase is correct. // If a contains no filename, the address must match a unique key. -func (am *AccountManager) DeleteAccount(a *Account, passphrase string) error { +func (am *AccountManager) DeleteAccount(account *Account, passphrase string) error { return am.manager.DeleteAccount(accounts.Account{ - Address: a.account.Address, - File: a.account.File, + Address: account.account.Address, + File: account.account.File, }, passphrase) } -// Sign signs hash with an unlocked private key matching the given address. -func (am *AccountManager) Sign(addr *Address, hash []byte) ([]byte, error) { - return am.manager.Sign(addr.address, hash) +// Sign calculates a ECDSA signature for the given hash. The produced signature +// is in the [R || S || V] format where V is 0 or 1. +func (am *AccountManager) Sign(address *Address, hash []byte) (signature []byte, _ error) { + return am.manager.Sign(address.address, hash) } -// SignWithPassphrase signs hash if the private key matching the given address can be -// decrypted with the given passphrase. -func (am *AccountManager) SignWithPassphrase(addr *Address, passphrase string, hash []byte) ([]byte, error) { - return am.manager.SignWithPassphrase(addr.address, passphrase, hash) +// SignPassphrase signs hash if the private key matching the given address can +// be decrypted with the given passphrase. The produced signature is in the +// [R || S || V] format where V is 0 or 1. +func (am *AccountManager) SignPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { + return am.manager.SignWithPassphrase(account.account, passphrase, hash) } // Unlock unlocks the given account indefinitely. -func (am *AccountManager) Unlock(a *Account, passphrase string) error { - return am.manager.TimedUnlock(a.account, passphrase, 0) +func (am *AccountManager) Unlock(account *Account, passphrase string) error { + return am.manager.TimedUnlock(account.account, passphrase, 0) } // Lock removes the private key with the given address from memory. -func (am *AccountManager) Lock(addr *Address) error { - return am.manager.Lock(addr.address) +func (am *AccountManager) Lock(address *Address) error { + return am.manager.Lock(address.address) } -// TimedUnlock unlocks the given account with the passphrase. The account -// stays unlocked for the duration of timeout. A timeout of 0 unlocks the account -// until the program exits. The account must match a unique key file. +// TimedUnlock unlocks the given account with the passphrase. The account stays +// unlocked for the duration of timeout (nanoseconds). A timeout of 0 unlocks the +// account until the program exits. The account must match a unique key file. // // If the account address is already unlocked for a duration, TimedUnlock extends or // shortens the active unlock timeout. If the address was previously unlocked // indefinitely the timeout is not altered. -func (am *AccountManager) TimedUnlock(a *Account, passphrase string, timeout int64) error { - return am.manager.TimedUnlock(a.account, passphrase, time.Duration(timeout)) +func (am *AccountManager) TimedUnlock(account *Account, passphrase string, timeout int64) error { + return am.manager.TimedUnlock(account.account, passphrase, time.Duration(timeout)) } // NewAccount generates a new key and stores it into the key directory, @@ -152,27 +154,27 @@ func (am *AccountManager) NewAccount(passphrase string) (*Account, error) { } // ExportKey exports as a JSON key, encrypted with newPassphrase. -func (am *AccountManager) ExportKey(a *Account, passphrase, newPassphrase string) ([]byte, error) { - return am.manager.Export(a.account, passphrase, newPassphrase) +func (am *AccountManager) ExportKey(account *Account, passphrase, newPassphrase string) (key []byte, _ error) { + return am.manager.Export(account.account, passphrase, newPassphrase) } // ImportKey stores the given encrypted JSON key into the key directory. -func (am *AccountManager) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (*Account, error) { - account, err := am.manager.Import(keyJSON, passphrase, newPassphrase) +func (am *AccountManager) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (account *Account, _ error) { + acc, err := am.manager.Import(keyJSON, passphrase, newPassphrase) if err != nil { return nil, err } - return &Account{account}, nil + return &Account{acc}, nil } -// Update changes the passphrase of an existing account. -func (am *AccountManager) Update(a *Account, passphrase, newPassphrase string) error { - return am.manager.Update(a.account, passphrase, newPassphrase) +// UpdateAccount changes the passphrase of an existing account. +func (am *AccountManager) UpdateAccount(account *Account, passphrase, newPassphrase string) error { + return am.manager.Update(account.account, passphrase, newPassphrase) } // ImportPreSaleKey decrypts the given Ethereum presale wallet and stores // a key file in the key directory. The key file is encrypted with the same passphrase. -func (am *AccountManager) ImportPreSaleKey(keyJSON []byte, passphrase string) (*Account, error) { +func (am *AccountManager) ImportPreSaleKey(keyJSON []byte, passphrase string) (ccount *Account, _ error) { account, err := am.manager.ImportPreSaleKey(keyJSON, passphrase) if err != nil { return nil, err diff --git a/mobile/android_test.go b/mobile/android_test.go index 65c0d2a10f..02b97dfd91 100644 --- a/mobile/android_test.go +++ b/mobile/android_test.go @@ -14,9 +14,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Contains all the wrappers from the accounts package to support client side key -// management on mobile platforms. - package gubiq import ( @@ -46,14 +43,42 @@ public class AndroidTest extends InstrumentationTestCase { public AndroidTest() {} public void testAccountManagement() { - try { - AccountManager am = new AccountManager(getInstrumentation().getContext().getFilesDir() + "/keystore", Gubiq.LightScryptN, Gubiq.LightScryptP); + // Create an encrypted keystore manager with light crypto parameters. + AccountManager am = new AccountManager(getInstrumentation().getContext().getFilesDir() + "/keystore", Gubiq.LightScryptN, Gubiq.LightScryptP); + try { + // Create a new account with the specified encryption passphrase. Account newAcc = am.newAccount("Creation password"); + + // Export the newly created account with a different passphrase. The returned + // data from this method invocation is a JSON encoded, encrypted key-file. byte[] jsonAcc = am.exportKey(newAcc, "Creation password", "Export password"); - am.deleteAccount(newAcc, "Creation password"); + // Update the passphrase on the account created above inside the local keystore. + am.updateAccount(newAcc, "Creation password", "Update password"); + + // Delete the account updated above from the local keystore. + am.deleteAccount(newAcc, "Update password"); + + // Import back the account we've exported (and then deleted) above with yet + // again a fresh passphrase. Account impAcc = am.importKey(jsonAcc, "Export password", "Import password"); + + // Create a new account to sign transactions with + Account signer = am.newAccount("Signer password"); + Hash txHash = new Hash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"); + + // Sign a transaction with a single authorization + byte[] signature = am.signPassphrase(signer, "Signer password", txHash.getBytes()); + + // Sign a transaction with multiple manually cancelled authorizations + am.unlock(signer, "Signer password"); + signature = am.sign(signer.getAddress(), txHash.getBytes()); + am.lock(signer.getAddress()); + + // Sign a transaction with multiple automatically cancelled authorizations + am.timedUnlock(signer, "Signer password", 1000000000); + signature = am.sign(signer.getAddress(), txHash.getBytes()); } catch (Exception e) { fail(e.toString()); } diff --git a/mobile/big.go b/mobile/big.go index bf1c328be7..add860c679 100644 --- a/mobile/big.go +++ b/mobile/big.go @@ -78,7 +78,7 @@ func (bi *BigInts) Size() int { } // Get returns the bigint at the given index from the slice. -func (bi *BigInts) Get(index int) (*BigInt, error) { +func (bi *BigInts) Get(index int) (bigint *BigInt, _ error) { if index < 0 || index >= len(bi.bigints) { return nil, errors.New("index out of bounds") } diff --git a/mobile/bind.go b/mobile/bind.go index 70fa035886..50d827bb42 100644 --- a/mobile/bind.go +++ b/mobile/bind.go @@ -31,15 +31,15 @@ import ( // Signer is an interaface defining the callback when a contract requires a // method to sign the transaction before submission. type Signer interface { - Sign(*Address, *Transaction) (*Transaction, error) + Sign(*Address, *Transaction) (tx *Transaction, _ error) } type signer struct { sign bind.SignerFn } -func (s *signer) Sign(addr *Address, tx *Transaction) (*Transaction, error) { - sig, err := s.sign(types.HomesteadSigner{}, addr.address, tx.tx) +func (s *signer) Sign(addr *Address, unsignedTx *Transaction) (signedTx *Transaction, _ error) { + sig, err := s.sign(types.HomesteadSigner{}, addr.address, unsignedTx.tx) if err != nil { return nil, err } @@ -113,18 +113,13 @@ type BoundContract struct { // DeployContract deploys a contract onto the Ethereum blockchain and binds the // deployment address with a wrapper. -func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client *EthereumClient, args *Interfaces) (*BoundContract, error) { - // Convert all the deployment parameters to Go types - params := make([]interface{}, len(args.objects)) - for i, obj := range args.objects { - params[i] = obj - } +func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client *EthereumClient, args *Interfaces) (contract *BoundContract, _ error) { // Deploy the contract to the network parsed, err := abi.JSON(strings.NewReader(abiJSON)) if err != nil { return nil, err } - addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, bytecode, client.client, params...) + addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, bytecode, client.client, args.objects...) if err != nil { return nil, err } @@ -137,7 +132,7 @@ func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client // BindContract creates a low level contract interface through which calls and // transactions may be made through. -func BindContract(address *Address, abiJSON string, client *EthereumClient) (*BoundContract, error) { +func BindContract(address *Address, abiJSON string, client *EthereumClient) (contract *BoundContract, _ error) { parsed, err := abi.JSON(strings.NewReader(abiJSON)) if err != nil { return nil, err @@ -159,44 +154,30 @@ func (c *BoundContract) GetDeployer() *Transaction { // Call invokes the (constant) contract method with params as input values and // sets the output to result. func (c *BoundContract) Call(opts *CallOpts, out *Interfaces, method string, args *Interfaces) error { - // Convert all the input and output parameters to Go types - params := make([]interface{}, len(args.objects)) - for i, obj := range args.objects { - params[i] = obj - } results := make([]interface{}, len(out.objects)) - for i, obj := range out.objects { - results[i] = obj - } - // Execute the call to the contract and wrap any results - if err := c.contract.Call(&opts.opts, &results, method, params...); err != nil { + copy(results, out.objects) + if err := c.contract.Call(&opts.opts, &results, method, args.objects...); err != nil { return err } - for i, res := range results { - out.objects[i] = res - } + copy(out.objects, results) return nil } // Transact invokes the (paid) contract method with params as input values. -func (c *BoundContract) Transact(opts *TransactOpts, method string, args *Interfaces) (*Transaction, error) { - params := make([]interface{}, len(args.objects)) - for i, obj := range args.objects { - params[i] = obj - } - tx, err := c.contract.Transact(&opts.opts, method, params) +func (c *BoundContract) Transact(opts *TransactOpts, method string, args *Interfaces) (tx *Transaction, _ error) { + rawTx, err := c.contract.Transact(&opts.opts, method, args.objects) if err != nil { return nil, err } - return &Transaction{tx}, nil + return &Transaction{rawTx}, nil } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. -func (c *BoundContract) Transfer(opts *TransactOpts) (*Transaction, error) { - tx, err := c.contract.Transfer(&opts.opts) +func (c *BoundContract) Transfer(opts *TransactOpts) (tx *Transaction, _ error) { + rawTx, err := c.contract.Transfer(&opts.opts) if err != nil { return nil, err } - return &Transaction{tx}, nil + return &Transaction{rawTx}, nil } diff --git a/mobile/common.go b/mobile/common.go index e703713fca..2afd41ec4c 100644 --- a/mobile/common.go +++ b/mobile/common.go @@ -33,18 +33,18 @@ type Hash struct { } // NewHashFromBytes converts a slice of bytes to a hash value. -func NewHashFromBytes(hash []byte) (*Hash, error) { +func NewHashFromBytes(binary []byte) (hash *Hash, _ error) { h := new(Hash) - if err := h.SetBytes(hash); err != nil { + if err := h.SetBytes(binary); err != nil { return nil, err } return h, nil } // NewHashFromHex converts a hex string to a hash value. -func NewHashFromHex(hash string) (*Hash, error) { +func NewHashFromHex(hex string) (hash *Hash, _ error) { h := new(Hash) - if err := h.SetHex(hash); err != nil { + if err := h.SetHex(hex); err != nil { return nil, err } return h, nil @@ -95,7 +95,7 @@ func (h *Hashes) Size() int { } // Get returns the hash at the given index from the slice. -func (h *Hashes) Get(index int) (*Hash, error) { +func (h *Hashes) Get(index int) (hash *Hash, _ error) { if index < 0 || index >= len(h.hashes) { return nil, errors.New("index out of bounds") } @@ -108,18 +108,18 @@ type Address struct { } // NewAddressFromBytes converts a slice of bytes to a hash value. -func NewAddressFromBytes(address []byte) (*Address, error) { +func NewAddressFromBytes(binary []byte) (address *Address, _ error) { a := new(Address) - if err := a.SetBytes(address); err != nil { + if err := a.SetBytes(binary); err != nil { return nil, err } return a, nil } // NewAddressFromHex converts a hex string to a address value. -func NewAddressFromHex(address string) (*Address, error) { +func NewAddressFromHex(hex string) (address *Address, _ error) { a := new(Address) - if err := a.SetHex(address); err != nil { + if err := a.SetHex(hex); err != nil { return nil, err } return a, nil @@ -170,7 +170,7 @@ func (a *Addresses) Size() int { } // Get returns the address at the given index from the slice. -func (a *Addresses) Get(index int) (*Address, error) { +func (a *Addresses) Get(index int) (address *Address, _ error) { if index < 0 || index >= len(a.addresses) { return nil, errors.New("index out of bounds") } diff --git a/mobile/discover.go b/mobile/discover.go index e1d1a11e0c..900908173c 100644 --- a/mobile/discover.go +++ b/mobile/discover.go @@ -53,7 +53,7 @@ type Enode struct { // and UDP discovery port 30301. // // enode://@10.3.58.6:30388?discport=30301 -func NewEnode(rawurl string) (*Enode, error) { +func NewEnode(rawurl string) (enode *Enode, _ error) { node, err := discv5.ParseNode(rawurl) if err != nil { return nil, err @@ -82,7 +82,7 @@ func (e *Enodes) Size() int { } // Get returns the enode at the given index from the slice. -func (e *Enodes) Get(index int) (*Enode, error) { +func (e *Enodes) Get(index int) (enode *Enode, _ error) { if index < 0 || index >= len(e.nodes) { return nil, errors.New("index out of bounds") } diff --git a/mobile/doc.go b/mobile/doc.go index 144768b403..f3a0cacb19 100644 --- a/mobile/doc.go +++ b/mobile/doc.go @@ -51,6 +51,10 @@ // should not be provided to limit the remote code complexity. Arrays should be // avoided as much as possible since they complicate bounds checking. // +// If a method has multiple return values (e.g. some return + an error), those +// are generated as output arguments in ObjC. To avoid weird generated names like +// ret_0 for them, please always assign names to output variables if tuples. +// // Note, a panic *cannot* cross over language boundaries, instead will result in // an undebuggable SEGFAULT in the process. For error handling only ever use error // returns, which may be the only or the second return. diff --git a/mobile/ethclient.go b/mobile/ethclient.go index dda9c269c9..1b7ac66f53 100644 --- a/mobile/ethclient.go +++ b/mobile/ethclient.go @@ -22,7 +22,6 @@ import ( "math/big" "github.com/ubiq/go-ubiq/core/types" - "github.com/ubiq/go-ubiq/core/vm" "github.com/ubiq/go-ubiq/ethclient" ) @@ -32,79 +31,80 @@ type EthereumClient struct { } // NewEthereumClient connects a client to the given URL. -func NewEthereumClient(rawurl string) (*EthereumClient, error) { - client, err := ethclient.Dial(rawurl) - return &EthereumClient{client}, err +func NewEthereumClient(rawurl string) (client *EthereumClient, _ error) { + rawClient, err := ethclient.Dial(rawurl) + return &EthereumClient{rawClient}, err } // GetBlockByHash returns the given full block. -func (ec *EthereumClient) GetBlockByHash(ctx *Context, hash *Hash) (*Block, error) { - block, err := ec.client.BlockByHash(ctx.context, hash.hash) - return &Block{block}, err +func (ec *EthereumClient) GetBlockByHash(ctx *Context, hash *Hash) (block *Block, _ error) { + rawBlock, err := ec.client.BlockByHash(ctx.context, hash.hash) + return &Block{rawBlock}, err } // GetBlockByNumber returns a block from the current canonical chain. If number is <0, the // latest known block is returned. -func (ec *EthereumClient) GetBlockByNumber(ctx *Context, number int64) (*Block, error) { +func (ec *EthereumClient) GetBlockByNumber(ctx *Context, number int64) (block *Block, _ error) { if number < 0 { - block, err := ec.client.BlockByNumber(ctx.context, nil) - return &Block{block}, err + rawBlock, err := ec.client.BlockByNumber(ctx.context, nil) + return &Block{rawBlock}, err } - block, err := ec.client.BlockByNumber(ctx.context, big.NewInt(number)) - return &Block{block}, err + rawBlock, err := ec.client.BlockByNumber(ctx.context, big.NewInt(number)) + return &Block{rawBlock}, err } // GetHeaderByHash returns the block header with the given hash. -func (ec *EthereumClient) GetHeaderByHash(ctx *Context, hash *Hash) (*Header, error) { - header, err := ec.client.HeaderByHash(ctx.context, hash.hash) - return &Header{header}, err +func (ec *EthereumClient) GetHeaderByHash(ctx *Context, hash *Hash) (header *Header, _ error) { + rawHeader, err := ec.client.HeaderByHash(ctx.context, hash.hash) + return &Header{rawHeader}, err } // GetHeaderByNumber returns a block header from the current canonical chain. If number is <0, // the latest known header is returned. -func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (*Header, error) { +func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (header *Header, _ error) { if number < 0 { - header, err := ec.client.HeaderByNumber(ctx.context, nil) - return &Header{header}, err + rawHeader, err := ec.client.HeaderByNumber(ctx.context, nil) + return &Header{rawHeader}, err } - header, err := ec.client.HeaderByNumber(ctx.context, big.NewInt(number)) - return &Header{header}, err + rawHeader, err := ec.client.HeaderByNumber(ctx.context, big.NewInt(number)) + return &Header{rawHeader}, err } // GetTransactionByHash returns the transaction with the given hash. -func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (*Transaction, error) { - tx, err := ec.client.TransactionByHash(ctx.context, hash.hash) - return &Transaction{tx}, err +func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (tx *Transaction, _ error) { + // TODO(karalabe): handle isPending + rawTx, _, err := ec.client.TransactionByHash(ctx.context, hash.hash) + return &Transaction{rawTx}, err } // GetTransactionCount returns the total number of transactions in the given block. -func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (int, error) { - count, err := ec.client.TransactionCount(ctx.context, hash.hash) - return int(count), err +func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (count int, _ error) { + rawCount, err := ec.client.TransactionCount(ctx.context, hash.hash) + return int(rawCount), err } // GetTransactionInBlock returns a single transaction at index in the given block. -func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (*Transaction, error) { - tx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index)) - return &Transaction{tx}, err +func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (tx *Transaction, _ error) { + rawTx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index)) + return &Transaction{rawTx}, err } // GetTransactionReceipt returns the receipt of a transaction by transaction hash. // Note that the receipt is not available for pending transactions. -func (ec *EthereumClient) GetTransactionReceipt(ctx *Context, hash *Hash) (*Receipt, error) { - receipt, err := ec.client.TransactionReceipt(ctx.context, hash.hash) - return &Receipt{receipt}, err +func (ec *EthereumClient) GetTransactionReceipt(ctx *Context, hash *Hash) (receipt *Receipt, _ error) { + rawReceipt, err := ec.client.TransactionReceipt(ctx.context, hash.hash) + return &Receipt{rawReceipt}, err } // SyncProgress retrieves the current progress of the sync algorithm. If there's // no sync currently running, it returns nil. -func (ec *EthereumClient) SyncProgress(ctx *Context) (*SyncProgress, error) { - progress, err := ec.client.SyncProgress(ctx.context) - if progress == nil { +func (ec *EthereumClient) SyncProgress(ctx *Context) (progress *SyncProgress, _ error) { + rawProgress, err := ec.client.SyncProgress(ctx.context) + if rawProgress == nil { return nil, err } - return &SyncProgress{*progress}, err + return &SyncProgress{*rawProgress}, err } // NewHeadHandler is a client-side subscription callback to invoke on events and @@ -116,10 +116,10 @@ type NewHeadHandler interface { // SubscribeNewHead subscribes to notifications about the current blockchain head // on the given channel. -func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, buffer int) (*Subscription, error) { +func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, buffer int) (sub *Subscription, _ error) { // Subscribe to the event internally ch := make(chan *types.Header, buffer) - sub, err := ec.client.SubscribeNewHead(ctx.context, ch) + rawSub, err := ec.client.SubscribeNewHead(ctx.context, ch) if err != nil { return nil, err } @@ -130,31 +130,31 @@ func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, case header := <-ch: handler.OnNewHead(&Header{header}) - case err := <-sub.Err(): + case err := <-rawSub.Err(): handler.OnError(err.Error()) return } } }() - return &Subscription{sub}, nil + return &Subscription{rawSub}, nil } // State Access // GetBalanceAt returns the wei balance of the given account. // The block number can be <0, in which case the balance is taken from the latest known block. -func (ec *EthereumClient) GetBalanceAt(ctx *Context, account *Address, number int64) (*BigInt, error) { +func (ec *EthereumClient) GetBalanceAt(ctx *Context, account *Address, number int64) (balance *BigInt, _ error) { if number < 0 { - balance, err := ec.client.BalanceAt(ctx.context, account.address, nil) - return &BigInt{balance}, err + rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, nil) + return &BigInt{rawBalance}, err } - balance, err := ec.client.BalanceAt(ctx.context, account.address, big.NewInt(number)) - return &BigInt{balance}, err + rawBalance, err := ec.client.BalanceAt(ctx.context, account.address, big.NewInt(number)) + return &BigInt{rawBalance}, err } // GetStorageAt returns the value of key in the contract storage of the given account. // The block number can be <0, in which case the value is taken from the latest known block. -func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash, number int64) ([]byte, error) { +func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash, number int64) (storage []byte, _ error) { if number < 0 { return ec.client.StorageAt(ctx.context, account.address, key.hash, nil) } @@ -163,7 +163,7 @@ func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash // GetCodeAt returns the contract code of the given account. // The block number can be <0, in which case the code is taken from the latest known block. -func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64) ([]byte, error) { +func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64) (code []byte, _ error) { if number < 0 { return ec.client.CodeAt(ctx.context, account.address, nil) } @@ -172,26 +172,26 @@ func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64 // GetNonceAt returns the account nonce of the given account. // The block number can be <0, in which case the nonce is taken from the latest known block. -func (ec *EthereumClient) GetNonceAt(ctx *Context, account *Address, number int64) (int64, error) { +func (ec *EthereumClient) GetNonceAt(ctx *Context, account *Address, number int64) (nonce int64, _ error) { if number < 0 { - nonce, err := ec.client.NonceAt(ctx.context, account.address, nil) - return int64(nonce), err + rawNonce, err := ec.client.NonceAt(ctx.context, account.address, nil) + return int64(rawNonce), err } - nonce, err := ec.client.NonceAt(ctx.context, account.address, big.NewInt(number)) - return int64(nonce), err + rawNonce, err := ec.client.NonceAt(ctx.context, account.address, big.NewInt(number)) + return int64(rawNonce), err } // Filters // FilterLogs executes a filter query. -func (ec *EthereumClient) FilterLogs(ctx *Context, query *FilterQuery) (*Logs, error) { - logs, err := ec.client.FilterLogs(ctx.context, query.query) +func (ec *EthereumClient) FilterLogs(ctx *Context, query *FilterQuery) (logs *Logs, _ error) { + rawLogs, err := ec.client.FilterLogs(ctx.context, query.query) if err != nil { return nil, err } // Temp hack due to vm.Logs being []*vm.Log - res := make(vm.Logs, len(logs)) - for i, log := range logs { + res := make([]*types.Log, len(rawLogs)) + for i, log := range rawLogs { res[i] = &log } return &Logs{res}, nil @@ -205,10 +205,10 @@ type FilterLogsHandler interface { } // SubscribeFilterLogs subscribes to the results of a streaming filter query. -func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler FilterLogsHandler, buffer int) (*Subscription, error) { +func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler FilterLogsHandler, buffer int) (sub *Subscription, _ error) { // Subscribe to the event internally - ch := make(chan vm.Log, buffer) - sub, err := ec.client.SubscribeFilterLogs(ctx.context, query.query, ch) + ch := make(chan types.Log, buffer) + rawSub, err := ec.client.SubscribeFilterLogs(ctx.context, query.query, ch) if err != nil { return nil, err } @@ -219,44 +219,44 @@ func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, case log := <-ch: handler.OnFilterLogs(&Log{&log}) - case err := <-sub.Err(): + case err := <-rawSub.Err(): handler.OnError(err.Error()) return } } }() - return &Subscription{sub}, nil + return &Subscription{rawSub}, nil } // Pending State // GetPendingBalanceAt returns the wei balance of the given account in the pending state. -func (ec *EthereumClient) GetPendingBalanceAt(ctx *Context, account *Address) (*BigInt, error) { - balance, err := ec.client.PendingBalanceAt(ctx.context, account.address) - return &BigInt{balance}, err +func (ec *EthereumClient) GetPendingBalanceAt(ctx *Context, account *Address) (balance *BigInt, _ error) { + rawBalance, err := ec.client.PendingBalanceAt(ctx.context, account.address) + return &BigInt{rawBalance}, err } // GetPendingStorageAt returns the value of key in the contract storage of the given account in the pending state. -func (ec *EthereumClient) GetPendingStorageAt(ctx *Context, account *Address, key *Hash) ([]byte, error) { +func (ec *EthereumClient) GetPendingStorageAt(ctx *Context, account *Address, key *Hash) (storage []byte, _ error) { return ec.client.PendingStorageAt(ctx.context, account.address, key.hash) } // GetPendingCodeAt returns the contract code of the given account in the pending state. -func (ec *EthereumClient) GetPendingCodeAt(ctx *Context, account *Address) ([]byte, error) { +func (ec *EthereumClient) GetPendingCodeAt(ctx *Context, account *Address) (code []byte, _ error) { return ec.client.PendingCodeAt(ctx.context, account.address) } // GetPendingNonceAt returns the account nonce of the given account in the pending state. // This is the nonce that should be used for the next transaction. -func (ec *EthereumClient) GetPendingNonceAt(ctx *Context, account *Address) (int64, error) { - nonce, err := ec.client.PendingNonceAt(ctx.context, account.address) - return int64(nonce), err +func (ec *EthereumClient) GetPendingNonceAt(ctx *Context, account *Address) (nonce int64, _ error) { + rawNonce, err := ec.client.PendingNonceAt(ctx.context, account.address) + return int64(rawNonce), err } // GetPendingTransactionCount returns the total number of transactions in the pending state. -func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (int, error) { - count, err := ec.client.PendingTransactionCount(ctx.context) - return int(count), err +func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (count int, _ error) { + rawCount, err := ec.client.PendingTransactionCount(ctx.context) + return int(rawCount), err } // Contract Calling @@ -267,7 +267,7 @@ func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (int, error) // blockNumber selects the block height at which the call runs. It can be <0, in which // case the code is taken from the latest known block. Note that state from very old // blocks might not be available. -func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) ([]byte, error) { +func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) (output []byte, _ error) { if number < 0 { return ec.client.CallContract(ctx.context, msg.msg, nil) } @@ -276,24 +276,24 @@ func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) // PendingCallContract executes a message call transaction using the EVM. // The state seen by the contract call is the pending state. -func (ec *EthereumClient) PendingCallContract(ctx *Context, msg *CallMsg) ([]byte, error) { +func (ec *EthereumClient) PendingCallContract(ctx *Context, msg *CallMsg) (output []byte, _ error) { return ec.client.PendingCallContract(ctx.context, msg.msg) } // SuggestGasPrice retrieves the currently suggested gas price to allow a timely // execution of a transaction. -func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (*BigInt, error) { - price, err := ec.client.SuggestGasPrice(ctx.context) - return &BigInt{price}, err +func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (price *BigInt, _ error) { + rawPrice, err := ec.client.SuggestGasPrice(ctx.context) + return &BigInt{rawPrice}, err } // EstimateGas tries to estimate the gas needed to execute a specific transaction based on // the current pending state of the backend blockchain. There is no guarantee that this is // the true gas limit requirement as other transactions may be added or removed by miners, // but it should provide a basis for setting a reasonable default. -func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (*BigInt, error) { - price, err := ec.client.EstimateGas(ctx.context, msg.msg) - return &BigInt{price}, err +func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (gas *BigInt, _ error) { + rawGas, err := ec.client.EstimateGas(ctx.context, msg.msg) + return &BigInt{rawGas}, err } // SendTransaction injects a signed transaction into the pending pool for execution. diff --git a/mobile/ethereum.go b/mobile/ethereum.go index 25ac09ed4b..e4df042666 100644 --- a/mobile/ethereum.go +++ b/mobile/ethereum.go @@ -93,7 +93,7 @@ func (t *Topics) Size() int { } // Get returns the topic list at the given index from the slice. -func (t *Topics) Get(index int) (*Hashes, error) { +func (t *Topics) Get(index int) (hashes *Hashes, _ error) { if index < 0 || index >= len(t.topics) { return nil, errors.New("index out of bounds") } diff --git a/mobile/gubiq.go b/mobile/gubiq.go index 6c809b6dd1..6c9e7ecc2e 100644 --- a/mobile/gubiq.go +++ b/mobile/gubiq.go @@ -99,7 +99,7 @@ type Node struct { } // NewNode creates and configures a new Gubiq node. -func NewNode(datadir string, config *NodeConfig) (*Node, error) { +func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { // If no or partial configurations were specified, use defaults if config == nil { config = NewNodeConfig() @@ -124,7 +124,7 @@ func NewNode(datadir string, config *NodeConfig) (*Node, error) { NAT: nat.Any(), MaxPeers: config.MaxPeers, } - stack, err := node.New(nodeConf) + rawStack, err := node.New(nodeConf) if err != nil { return nil, err } @@ -151,14 +151,14 @@ func NewNode(datadir string, config *NodeConfig) (*Node, error) { GpobaseStepUp: 100, GpobaseCorrectionFactor: 110, } - if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return les.New(ctx, ethConf) }); err != nil { return nil, fmt.Errorf("ubiq init: %v", err) } // If netstats reporting is requested, do it if config.EthereumNetStats != "" { - if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) { var lesServ *les.LightEthereum ctx.Service(&lesServ) @@ -170,11 +170,11 @@ func NewNode(datadir string, config *NodeConfig) (*Node, error) { } // Register the Whisper protocol if requested if config.WhisperEnabled { - if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisperv2.New(), nil }); err != nil { + if err := rawStack.Register(func(*node.ServiceContext) (node.Service, error) { return whisperv2.New(), nil }); err != nil { return nil, fmt.Errorf("whisper init: %v", err) } } - return &Node{stack}, nil + return &Node{rawStack}, nil } // Start creates a live P2P node and starts running it. @@ -189,7 +189,7 @@ func (n *Node) Stop() error { } // GetEthereumClient retrieves a client to access the Ethereum subsystem. -func (n *Node) GetEthereumClient() (*EthereumClient, error) { +func (n *Node) GetEthereumClient() (client *EthereumClient, _ error) { rpc, err := n.node.Attach() if err != nil { return nil, err diff --git a/mobile/interface.go b/mobile/interface.go index edb5163629..e3eccef7ed 100644 --- a/mobile/interface.go +++ b/mobile/interface.go @@ -131,7 +131,7 @@ func (i *Interfaces) Size() int { } // Get returns the bigint at the given index from the slice. -func (i *Interfaces) Get(index int) (*Interface, error) { +func (i *Interfaces) Get(index int) (iface *Interface, _ error) { if index < 0 || index >= len(i.objects) { return nil, errors.New("index out of bounds") } diff --git a/core/vm/util_test.go b/mobile/logger.go similarity index 75% rename from core/vm/util_test.go rename to mobile/logger.go index 5844e3ad43..81920da06a 100644 --- a/core/vm/util_test.go +++ b/mobile/logger.go @@ -14,19 +14,13 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package vm +package geth import ( - "math/big" - - "github.com/ubiq/go-ubiq/params" + "github.com/ubiq/go-ubiq/logger/glog" ) -type ruleSet struct { - hs *big.Int -} - -func (r ruleSet) IsHomestead(n *big.Int) bool { return n.Cmp(r.hs) >= 0 } -func (r ruleSet) GasTable(*big.Int) params.GasTable { - return params.GasTableHomestead +// SetVerbosity sets the global verbosity level (between 0 and 6 - see logger/verbosity.go). +func SetVerbosity(level int) { + glog.SetV(level) } diff --git a/mobile/p2p.go b/mobile/p2p.go index a362ab34cb..eb4366ed24 100644 --- a/mobile/p2p.go +++ b/mobile/p2p.go @@ -38,7 +38,7 @@ func (ni *NodeInfo) GetListenerPort() int { return ni.info.Ports.Listener func (ni *NodeInfo) GetListenerAddress() string { return ni.info.ListenAddr } func (ni *NodeInfo) GetProtocols() *Strings { protos := []string{} - for proto, _ := range ni.info.Protocols { + for proto := range ni.info.Protocols { protos = append(protos, proto) } return &Strings{protos} @@ -66,7 +66,7 @@ func (pi *PeerInfos) Size() int { } // Get returns the peer info at the given index from the slice. -func (pi *PeerInfos) Get(index int) (*PeerInfo, error) { +func (pi *PeerInfos) Get(index int) (info *PeerInfo, _ error) { if index < 0 || index >= len(pi.infos) { return nil, errors.New("index out of bounds") } diff --git a/mobile/params.go b/mobile/params.go index 347ba281ae..cd11f6ef6e 100644 --- a/mobile/params.go +++ b/mobile/params.go @@ -79,8 +79,8 @@ func NewChainConfig() *ChainConfig { // by the foundation running the V5 discovery protocol. func FoundationBootnodes() *Enodes { nodes := &Enodes{nodes: make([]*discv5.Node, len(params.DiscoveryV5Bootnodes))} - for i, node := range params.DiscoveryV5Bootnodes { - nodes.nodes[i] = node + for i, url := range params.DiscoveryV5Bootnodes { + nodes.nodes[i] = discv5.MustParseNode(url) } return nodes } diff --git a/mobile/primitives.go b/mobile/primitives.go index 04f743301f..f61189046c 100644 --- a/mobile/primitives.go +++ b/mobile/primitives.go @@ -32,7 +32,7 @@ func (s *Strings) Size() int { } // Get returns the string at the given index from the slice. -func (s *Strings) Get(index int) (string, error) { +func (s *Strings) Get(index int) (str string, _ error) { if index < 0 || index >= len(s.strs) { return "", errors.New("index out of bounds") } diff --git a/mobile/types.go b/mobile/types.go index ad96915ab1..64ffc33d7e 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -89,7 +89,7 @@ func (h *Headers) Size() int { } // Get returns the header at the given index from the slice. -func (h *Headers) Get(index int) (*Header, error) { +func (h *Headers) Get(index int) (header *Header, _ error) { if index < 0 || index >= len(h.headers) { return nil, errors.New("index out of bounds") } @@ -142,7 +142,7 @@ func (tx *Transaction) GetHash() *Hash { return &Hash{tx.tx.Hash()} } func (tx *Transaction) GetSigHash() *Hash { return &Hash{tx.tx.SigHash(types.HomesteadSigner{})} } func (tx *Transaction) GetCost() *BigInt { return &BigInt{tx.tx.Cost()} } -func (tx *Transaction) GetFrom() (*Address, error) { +func (tx *Transaction) GetFrom() (address *Address, _ error) { from, err := types.Sender(types.HomesteadSigner{}, tx.tx) return &Address{from}, err } @@ -154,25 +154,25 @@ func (tx *Transaction) GetTo() *Address { return nil } -func (tx *Transaction) WithSignature(sig []byte) (*Transaction, error) { - t, err := tx.tx.WithSignature(types.HomesteadSigner{}, sig) - return &Transaction{t}, err +func (tx *Transaction) WithSignature(sig []byte) (signedTx *Transaction, _ error) { + rawTx, err := tx.tx.WithSignature(types.HomesteadSigner{}, sig) + return &Transaction{rawTx}, err } // Transactions represents a slice of transactions. type Transactions struct{ txs types.Transactions } // Size returns the number of transactions in the slice. -func (t *Transactions) Size() int { - return len(t.txs) +func (txs *Transactions) Size() int { + return len(txs.txs) } // Get returns the transaction at the given index from the slice. -func (t *Transactions) Get(index int) (*Transaction, error) { - if index < 0 || index >= len(t.txs) { +func (txs *Transactions) Get(index int) (tx *Transaction, _ error) { + if index < 0 || index >= len(txs.txs) { return nil, errors.New("index out of bounds") } - return &Transaction{t.txs[index]}, nil + return &Transaction{txs.txs[index]}, nil } // Receipt represents the results of a transaction. diff --git a/mobile/vm.go b/mobile/vm.go index 8965f73658..b0a9cabe57 100644 --- a/mobile/vm.go +++ b/mobile/vm.go @@ -21,13 +21,13 @@ package gubiq import ( "errors" - "github.com/ubiq/go-ubiq/core/vm" + "github.com/ubiq/go-ubiq/core/types" ) // Log represents a contract log event. These events are generated by the LOG // opcode and stored/indexed by the node. type Log struct { - log *vm.Log + log *types.Log } func (l *Log) GetAddress() *Address { return &Address{l.log.Address} } @@ -40,7 +40,7 @@ func (l *Log) GetBlockHash() *Hash { return &Hash{l.log.BlockHash} } func (l *Log) GetIndex() int { return int(l.log.Index) } // Logs represents a slice of VM logs. -type Logs struct{ logs vm.Logs } +type Logs struct{ logs []*types.Log } // Size returns the number of logs in the slice. func (l *Logs) Size() int { @@ -48,7 +48,7 @@ func (l *Logs) Size() int { } // Get returns the log at the given index from the slice. -func (l *Logs) Get(index int) (*Log, error) { +func (l *Logs) Get(index int) (log *Log, _ error) { if index < 0 || index >= len(l.logs) { return nil, errors.New("index out of bounds") } diff --git a/node/api.go b/node/api.go index 1c370e588d..e5035ed607 100644 --- a/node/api.go +++ b/node/api.go @@ -21,12 +21,11 @@ import ( "strings" "time" + "github.com/rcrowley/go-metrics" "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/p2p" "github.com/ubiq/go-ubiq/p2p/discover" - "github.com/ubiq/go-ubiq/rpc" - "github.com/rcrowley/go-metrics" ) // PrivateAdminAPI is the collection of administrative API methods exposed only @@ -75,7 +74,7 @@ func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { } // StartRPC starts the HTTP RPC API server. -func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *string, apis *string) (bool, error) { +func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -91,7 +90,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st host = &h } if port == nil { - port = rpc.NewHexNumber(api.node.config.HTTPPort) + port = &api.node.config.HTTPPort } if cors == nil { cors = &api.node.config.HTTPCors @@ -105,7 +104,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st } } - if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, port.Int()), api.node.rpcAPIs, modules, *cors); err != nil { + if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, *cors); err != nil { return false, err } return true, nil @@ -124,7 +123,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) { } // StartWS starts the websocket RPC API server. -func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOrigins *string, apis *string) (bool, error) { +func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { api.node.lock.Lock() defer api.node.lock.Unlock() @@ -140,7 +139,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr host = &h } if port == nil { - port = rpc.NewHexNumber(api.node.config.WSPort) + port = &api.node.config.WSPort } if allowedOrigins == nil { allowedOrigins = &api.node.config.WSOrigins @@ -154,7 +153,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr } } - if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, port.Int()), api.node.rpcAPIs, modules, *allowedOrigins); err != nil { + if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, *allowedOrigins); err != nil { return false, err } return true, nil diff --git a/node/config_test.go b/node/config_test.go index ea7c6030b1..ca4cb34187 100644 --- a/node/config_test.go +++ b/node/config_test.go @@ -121,8 +121,7 @@ func TestNodeKeyPersistency(t *testing.T) { if _, err := os.Stat(keyfile); err != nil { t.Fatalf("node key not persisted to data directory: %v", err) } - key, err = crypto.LoadECDSA(keyfile) - if err != nil { + if _, err = crypto.LoadECDSA(keyfile); err != nil { t.Fatalf("failed to load freshly persisted node key: %v", err) } blob1, err := ioutil.ReadFile(keyfile) @@ -137,7 +136,7 @@ func TestNodeKeyPersistency(t *testing.T) { if err != nil { t.Fatalf("failed to read previously persisted node key: %v", err) } - if bytes.Compare(blob1, blob2) != 0 { + if !bytes.Equal(blob1, blob2) { t.Fatalf("persisted node key mismatch: have %x, want %x", blob2, blob1) } diff --git a/node/node_example_test.go b/node/node_example_test.go index 0b2004141c..2a77a28ada 100644 --- a/node/node_example_test.go +++ b/node/node_example_test.go @@ -41,10 +41,10 @@ func (s *SampleService) APIs() []rpc.API { return nil } func (s *SampleService) Start(*p2p.Server) error { fmt.Println("Service starting..."); return nil } func (s *SampleService) Stop() error { fmt.Println("Service stopping..."); return nil } -func ExampleUsage() { +func ExampleService() { // Create a network node to run protocols with the default values. The below list // is only used to display each of the configuration options. All of these could - // have been ommited if the default behavior is desired. + // have been omitted if the default behavior is desired. nodeConfig := &node.Config{ DataDir: "", // Empty uses ephemeral storage PrivateKey: nil, // Nil generates a node key on the fly diff --git a/node/node_test.go b/node/node_test.go index 7421f9b0bd..e893d7fa8d 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -166,7 +166,7 @@ func TestServiceLifeCycle(t *testing.T) { if err := stack.Start(); err != nil { t.Fatalf("failed to start protocol stack: %v", err) } - for id, _ := range services { + for id := range services { if !started[id] { t.Fatalf("service %s: freshly started service not running", id) } @@ -178,7 +178,7 @@ func TestServiceLifeCycle(t *testing.T) { if err := stack.Stop(); err != nil { t.Fatalf("failed to stop protocol stack: %v", err) } - for id, _ := range services { + for id := range services { if !stopped[id] { t.Fatalf("service %s: freshly terminated service still running", id) } @@ -218,7 +218,7 @@ func TestServiceRestarts(t *testing.T) { } defer stack.Stop() - if running != true || started != 1 { + if !running || started != 1 { t.Fatalf("running/started mismatch: have %v/%d, want true/1", running, started) } // Restart the stack a few times and check successful service restarts @@ -227,7 +227,7 @@ func TestServiceRestarts(t *testing.T) { t.Fatalf("iter %d: failed to restart stack: %v", i, err) } } - if running != true || started != 4 { + if !running || started != 4 { t.Fatalf("running/started mismatch: have %v/%d, want true/4", running, started) } } @@ -270,7 +270,7 @@ func TestServiceConstructionAbortion(t *testing.T) { if err := stack.Start(); err != failure { t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) } - for id, _ := range services { + for id := range services { if started[id] { t.Fatalf("service %s: started should not have", id) } @@ -322,7 +322,7 @@ func TestServiceStartupAbortion(t *testing.T) { if err := stack.Start(); err != failure { t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) } - for id, _ := range services { + for id := range services { if started[id] && !stopped[id] { t.Fatalf("service %s: started but not stopped", id) } @@ -376,7 +376,7 @@ func TestServiceTerminationGuarantee(t *testing.T) { if err := stack.Start(); err != nil { t.Fatalf("iter %d: failed to start protocol stack: %v", i, err) } - for id, _ := range services { + for id := range services { if !started[id] { t.Fatalf("iter %d, service %s: service not running", i, id) } @@ -397,7 +397,7 @@ func TestServiceTerminationGuarantee(t *testing.T) { t.Fatalf("iter %d: failure count mismatch: have %d, want %d", i, len(err.Services), 1) } } - for id, _ := range services { + for id := range services { if !stopped[id] { t.Fatalf("iter %d, service %s: service not terminated", i, id) } diff --git a/p2p/discover/database.go b/p2p/discover/database.go index 2fd1bc841c..5cdb6bd387 100644 --- a/p2p/discover/database.go +++ b/p2p/discover/database.go @@ -258,7 +258,7 @@ func (db *nodeDB) expireNodes() error { continue } // Skip the node if not expired yet (and not self) - if bytes.Compare(id[:], db.self[:]) != 0 { + if !bytes.Equal(id[:], db.self[:]) { if seen := db.lastPong(id); seen.After(threshold) { continue } diff --git a/p2p/discover/database_test.go b/p2p/discover/database_test.go index fc1eec51d6..825e0fad7b 100644 --- a/p2p/discover/database_test.go +++ b/p2p/discover/database_test.go @@ -242,12 +242,12 @@ func TestNodeDBSeedQuery(t *testing.T) { if len(seeds) != len(want) { t.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want)) } - for id, _ := range have { + for id := range have { if _, ok := want[id]; !ok { t.Errorf("extra seed: %v", id) } } - for id, _ := range want { + for id := range want { if _, ok := have[id]; !ok { t.Errorf("missing seed: %v", id) } diff --git a/p2p/discover/node.go b/p2p/discover/node.go index f93abdcccc..74f38c4e46 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -224,11 +224,8 @@ func (n NodeID) GoString() string { // HexID converts a hex string to a NodeID. // The string may be prefixed with 0x. func HexID(in string) (NodeID, error) { - if strings.HasPrefix(in, "0x") { - in = in[2:] - } var id NodeID - b, err := hex.DecodeString(in) + b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) if err != nil { return id, err } else if len(b) != len(id) { diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 3694591300..50869a7c3a 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -433,7 +433,7 @@ func (tab *Table) bondall(nodes []*Node) (result []*Node) { rc <- nn }(nodes[i]) } - for _ = range nodes { + for range nodes { if n := <-rc; n != nil { result = append(result, n) } diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 10ad42d573..4b6fe60548 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -314,19 +314,19 @@ var lookupTestnet = &preminedTestnet{ target: MustHexID("166aea4f556532c6d34e8b740e5d314af7e9ac0ca79833bd751d6b665f12dfd38ec563c363b32f02aef4a80b44fd3def94612d497b99cb5f17fd24de454927ec"), targetSha: common.Hash{0x5c, 0x94, 0x4e, 0xe5, 0x1c, 0x5a, 0xe9, 0xf7, 0x2a, 0x95, 0xec, 0xcb, 0x8a, 0xed, 0x3, 0x74, 0xee, 0xcb, 0x51, 0x19, 0xd7, 0x20, 0xcb, 0xea, 0x68, 0x13, 0xe8, 0xe0, 0xd6, 0xad, 0x92, 0x61}, dists: [257][]NodeID{ - 240: []NodeID{ + 240: { MustHexID("2001ad5e3e80c71b952161bc0186731cf5ffe942d24a79230a0555802296238e57ea7a32f5b6f18564eadc1c65389448481f8c9338df0a3dbd18f708cbc2cbcb"), MustHexID("6ba3f4f57d084b6bf94cc4555b8c657e4a8ac7b7baf23c6874efc21dd1e4f56b7eb2721e07f5242d2f1d8381fc8cae535e860197c69236798ba1ad231b105794"), }, - 244: []NodeID{ + 244: { MustHexID("696ba1f0a9d55c59246f776600542a9e6432490f0cd78f8bb55a196918df2081a9b521c3c3ba48e465a75c10768807717f8f689b0b4adce00e1c75737552a178"), }, - 246: []NodeID{ + 246: { MustHexID("d6d32178bdc38416f46ffb8b3ec9e4cb2cfff8d04dd7e4311a70e403cb62b10be1b447311b60b4f9ee221a8131fc2cbd45b96dd80deba68a949d467241facfa8"), MustHexID("3ea3d04a43a3dfb5ac11cffc2319248cf41b6279659393c2f55b8a0a5fc9d12581a9d97ef5d8ff9b5abf3321a290e8f63a4f785f450dc8a672aba3ba2ff4fdab"), MustHexID("2fc897f05ae585553e5c014effd3078f84f37f9333afacffb109f00ca8e7a3373de810a3946be971cbccdfd40249f9fe7f322118ea459ac71acca85a1ef8b7f4"), }, - 247: []NodeID{ + 247: { MustHexID("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32"), MustHexID("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db"), MustHexID("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac"), @@ -338,7 +338,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("4ab0a75941b12892369b4490a1928c8ca52a9ad6d3dffbd1d8c0b907bc200fe74c022d011ec39b64808a39c0ca41f1d3254386c3e7733e7044c44259486461b6"), MustHexID("d45150a72dc74388773e68e03133a3b5f51447fe91837d566706b3c035ee4b56f160c878c6273394daee7f56cc398985269052f22f75a8057df2fe6172765354"), }, - 248: []NodeID{ + 248: { MustHexID("6aadfce366a189bab08ac84721567483202c86590642ea6d6a14f37ca78d82bdb6509eb7b8b2f6f63c78ae3ae1d8837c89509e41497d719b23ad53dd81574afa"), MustHexID("a605ecfd6069a4cf4cf7f5840e5bc0ce10d23a3ac59e2aaa70c6afd5637359d2519b4524f56fc2ca180cdbebe54262f720ccaae8c1b28fd553c485675831624d"), MustHexID("29701451cb9448ca33fc33680b44b840d815be90146eb521641efbffed0859c154e8892d3906eae9934bfacee72cd1d2fa9dd050fd18888eea49da155ab0efd2"), @@ -356,7 +356,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("b76ea1a6fd6506ef6e3506a4f1f60ed6287fff8114af6141b2ff13e61242331b54082b023cfea5b3083354a4fb3f9eb8be01fb4a518f579e731a5d0707291a6b"), MustHexID("9b53a37950ca8890ee349b325032d7b672cab7eced178d3060137b24ef6b92a43977922d5bdfb4a3409a2d80128e02f795f9dae6d7d99973ad0e23a2afb8442f"), }, - 249: []NodeID{ + 249: { MustHexID("675ae65567c3c72c50c73bc0fd4f61f202ea5f93346ca57b551de3411ccc614fad61cb9035493af47615311b9d44ee7a161972ee4d77c28fe1ec029d01434e6a"), MustHexID("8eb81408389da88536ae5800392b16ef5109d7ea132c18e9a82928047ecdb502693f6e4a4cdd18b54296caf561db937185731456c456c98bfe7de0baf0eaa495"), MustHexID("2adba8b1612a541771cb93a726a38a4b88e97b18eced2593eb7daf82f05a5321ca94a72cc780c306ff21e551a932fc2c6d791e4681907b5ceab7f084c3fa2944"), @@ -374,7 +374,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("d94193f236105010972f5df1b7818b55846592a0445b9cdc4eaed811b8c4c0f7c27dc8cc9837a4774656d6b34682d6d329d42b6ebb55da1d475c2474dc3dfdf4"), MustHexID("edd9af6aded4094e9785637c28fccbd3980cbe28e2eb9a411048a23c2ace4bd6b0b7088a7817997b49a3dd05fc6929ca6c7abbb69438dbdabe65e971d2a794b2"), }, - 250: []NodeID{ + 250: { MustHexID("53a5bd1215d4ab709ae8fdc2ced50bba320bced78bd9c5dc92947fb402250c914891786db0978c898c058493f86fc68b1c5de8a5cb36336150ac7a88655b6c39"), MustHexID("b7f79e3ab59f79262623c9ccefc8f01d682323aee56ffbe295437487e9d5acaf556a9c92e1f1c6a9601f2b9eb6b027ae1aeaebac71d61b9b78e88676efd3e1a3"), MustHexID("d374bf7e8d7ffff69cc00bebff38ef5bc1dcb0a8d51c1a3d70e61ac6b2e2d6617109254b0ac224354dfbf79009fe4239e09020c483cc60c071e00b9238684f30"), @@ -392,7 +392,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("5b116f0751526868a909b61a30b0c5282c37df6925cc03ddea556ef0d0602a9595fd6c14d371f8ed7d45d89918a032dcd22be4342a8793d88fdbeb3ca3d75bd7"), MustHexID("50f3222fb6b82481c7c813b2172e1daea43e2710a443b9c2a57a12bd160dd37e20f87aa968c82ad639af6972185609d47036c0d93b4b7269b74ebd7073221c10"), }, - 251: []NodeID{ + 251: { MustHexID("9b8f702a62d1bee67bedfeb102eca7f37fa1713e310f0d6651cc0c33ea7c5477575289ccd463e5a2574a00a676a1fdce05658ba447bb9d2827f0ba47b947e894"), MustHexID("b97532eb83054ed054b4abdf413bb30c00e4205545c93521554dbe77faa3cfaa5bd31ef466a107b0b34a71ec97214c0c83919720142cddac93aa7a3e928d4708"), MustHexID("2f7a5e952bfb67f2f90b8441b5fadc9ee13b1dcde3afeeb3dd64bf937f86663cc5c55d1fa83952b5422763c7df1b7f2794b751c6be316ebc0beb4942e65ab8c1"), @@ -410,7 +410,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("fcc9a2e1ac3667026ff16192876d1813bb75abdbf39b929a92863012fe8b1d890badea7a0de36274d5c1eb1e8f975785532c50d80fd44b1a4b692f437303393f"), MustHexID("6d8b3efb461151dd4f6de809b62726f5b89e9b38e9ba1391967f61cde844f7528fecf821b74049207cee5a527096b31f3ad623928cd3ce51d926fa345a6b2951"), }, - 252: []NodeID{ + 252: { MustHexID("f1ae93157cc48c2075dd5868fbf523e79e06caf4b8198f352f6e526680b78ff4227263de92612f7d63472bd09367bb92a636fff16fe46ccf41614f7a72495c2a"), MustHexID("587f482d111b239c27c0cb89b51dd5d574db8efd8de14a2e6a1400c54d4567e77c65f89c1da52841212080b91604104768350276b6682f2f961cdaf4039581c7"), MustHexID("e3f88274d35cefdaabdf205afe0e80e936cc982b8e3e47a84ce664c413b29016a4fb4f3a3ebae0a2f79671f8323661ed462bf4390af94c424dc8ace0c301b90f"), @@ -428,7 +428,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("d84f06fe64debc4cd0625e36d19b99014b6218375262cc2209202bdbafd7dffcc4e34ce6398e182e02fd8faeed622c3e175545864902dfd3d1ac57647cddf4c6"), MustHexID("d0ed87b294f38f1d741eb601020eeec30ac16331d05880fe27868f1e454446de367d7457b41c79e202eaf9525b029e4f1d7e17d85a55f83a557c005c68d7328a"), }, - 253: []NodeID{ + 253: { MustHexID("ad4485e386e3cc7c7310366a7c38fb810b8896c0d52e55944bfd320ca294e7912d6c53c0a0cf85e7ce226e92491d60430e86f8f15cda0161ed71893fb4a9e3a1"), MustHexID("36d0e7e5b7734f98c6183eeeb8ac5130a85e910a925311a19c4941b1290f945d4fc3996b12ef4966960b6fa0fb29b1604f83a0f81bd5fd6398d2e1a22e46af0c"), MustHexID("7d307d8acb4a561afa23bdf0bd945d35c90245e26345ec3a1f9f7df354222a7cdcb81339c9ed6744526c27a1a0c8d10857e98df942fa433602facac71ac68a31"), @@ -446,7 +446,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("7a369b2b8962cc4c65900be046482fbf7c14f98a135bbbae25152c82ad168fb2097b3d1429197cf46d3ce9fdeb64808f908a489cc6019725db040060fdfe5405"), MustHexID("47bcae48288da5ecc7f5058dfa07cf14d89d06d6e449cb946e237aa6652ea050d9f5a24a65efdc0013ccf232bf88670979eddef249b054f63f38da9d7796dbd8"), }, - 254: []NodeID{ + 254: { MustHexID("099739d7abc8abd38ecc7a816c521a1168a4dbd359fa7212a5123ab583ffa1cf485a5fed219575d6475dbcdd541638b2d3631a6c7fce7474e7fe3cba1d4d5853"), MustHexID("c2b01603b088a7182d0cf7ef29fb2b04c70acb320fccf78526bf9472e10c74ee70b3fcfa6f4b11d167bd7d3bc4d936b660f2c9bff934793d97cb21750e7c3d31"), MustHexID("20e4d8f45f2f863e94b45548c1ef22a11f7d36f263e4f8623761e05a64c4572379b000a52211751e2561b0f14f4fc92dd4130410c8ccc71eb4f0e95a700d4ca9"), @@ -464,7 +464,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("82504b6eb49bb2c0f91a7006ce9cefdbaf6df38706198502c2e06601091fc9dc91e4f15db3410d45c6af355bc270b0f268d3dff560f956985c7332d4b10bd1ed"), MustHexID("b39b5b677b45944ceebe76e76d1f051de2f2a0ec7b0d650da52135743e66a9a5dba45f638258f9a7545d9a790c7fe6d3fdf82c25425c7887323e45d27d06c057"), }, - 255: []NodeID{ + 255: { MustHexID("5c4d58d46e055dd1f093f81ee60a675e1f02f54da6206720adee4dccef9b67a31efc5c2a2949c31a04ee31beadc79aba10da31440a1f9ff2a24093c63c36d784"), MustHexID("ea72161ffdd4b1e124c7b93b0684805f4c4b58d617ed498b37a145c670dbc2e04976f8785583d9c805ffbf343c31d492d79f841652bbbd01b61ed85640b23495"), MustHexID("51caa1d93352d47a8e531692a3612adac1e8ac68d0a200d086c1c57ae1e1a91aa285ab242e8c52ef9d7afe374c9485b122ae815f1707b875569d0433c1c3ce85"), @@ -482,7 +482,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("f492c6ee2696d5f682f7f537757e52744c2ae560f1090a07024609e903d334e9e174fc01609c5a229ddbcac36c9d21adaf6457dab38a25bfd44f2f0ee4277998"), MustHexID("459e4db99298cb0467a90acee6888b08bb857450deac11015cced5104853be5adce5b69c740968bc7f931495d671a70cad9f48546d7cd203357fe9af0e8d2164"), }, - 256: []NodeID{ + 256: { MustHexID("a8593af8a4aef7b806b5197612017951bac8845a1917ca9a6a15dd6086d608505144990b245785c4cd2d67a295701c7aac2aa18823fb0033987284b019656268"), MustHexID("d2eebef914928c3aad77fc1b2a495f52d2294acf5edaa7d8a530b540f094b861a68fe8348a46a7c302f08ab609d85912a4968eacfea0740847b29421b4795d9e"), MustHexID("b14bfcb31495f32b650b63cf7d08492e3e29071fdc73cf2da0da48d4b191a70ba1a65f42ad8c343206101f00f8a48e8db4b08bf3f622c0853e7323b250835b91"), diff --git a/p2p/discover/udp_test.go b/p2p/discover/udp_test.go index 6eda835387..35b04b3da5 100644 --- a/p2p/discover/udp_test.go +++ b/p2p/discover/udp_test.go @@ -234,7 +234,7 @@ func TestUDP_findnode(t *testing.T) { defer test.table.Close() // put a few nodes into the table. their exact - // distribution shouldn't matter much, altough we need to + // distribution shouldn't matter much, although we need to // take care not to overflow any bucket. targetHash := crypto.Keccak256Hash(testTarget[:]) nodes := &nodesByDistance{target: targetHash} @@ -374,7 +374,7 @@ func TestUDP_successfulPing(t *testing.T) { if n.ID != rid { t.Errorf("node has wrong ID: got %v, want %v", n.ID, rid) } - if !bytes.Equal(n.IP, test.remoteaddr.IP) { + if !n.IP.Equal(test.remoteaddr.IP) { t.Errorf("node has wrong IP: got %v, want: %v", n.IP, test.remoteaddr.IP) } if int(n.UDP) != test.remoteaddr.Port { diff --git a/p2p/discv5/database.go b/p2p/discv5/database.go index 3525784b79..16e8966529 100644 --- a/p2p/discv5/database.go +++ b/p2p/discv5/database.go @@ -269,7 +269,7 @@ func (db *nodeDB) expireNodes() error { continue } // Skip the node if not expired yet (and not self) - if bytes.Compare(id[:], db.self[:]) != 0 { + if !bytes.Equal(id[:], db.self[:]) { if seen := db.lastPong(id); seen.After(threshold) { continue } diff --git a/p2p/discv5/database_test.go b/p2p/discv5/database_test.go index 4aeb776c85..186d08a0fd 100644 --- a/p2p/discv5/database_test.go +++ b/p2p/discv5/database_test.go @@ -242,12 +242,12 @@ func TestNodeDBSeedQuery(t *testing.T) { if len(seeds) != len(want) { t.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want)) } - for id, _ := range have { + for id := range have { if _, ok := want[id]; !ok { t.Errorf("extra seed: %v", id) } } - for id, _ := range want { + for id := range want { if _, ok := have[id]; !ok { t.Errorf("missing seed: %v", id) } diff --git a/p2p/discv5/net.go b/p2p/discv5/net.go index b506d0e536..49d23c9afb 100644 --- a/p2p/discv5/net.go +++ b/p2p/discv5/net.go @@ -126,8 +126,15 @@ type topicRegisterReq struct { } type topicSearchReq struct { - topic Topic - found chan<- string + topic Topic + found chan<- *Node + lookup chan<- bool + delay time.Duration +} + +type topicSearchResult struct { + target lookupInfo + nodes []*Node } type timeoutEvent struct { @@ -263,16 +270,23 @@ func (net *Network) lookup(target common.Hash, stopOnMatch bool) []*Node { break } // Wait for the next reply. - for _, n := range <-reply { - if n != nil && !seen[n.ID] { - seen[n.ID] = true - result.push(n, bucketSize) - if stopOnMatch && n.sha == target { - return result.entries + select { + case nodes := <-reply: + for _, n := range nodes { + if n != nil && !seen[n.ID] { + seen[n.ID] = true + result.push(n, bucketSize) + if stopOnMatch && n.sha == target { + return result.entries + } } } + pendingQueries-- + case <-time.After(respTimeout): + // forget all pending requests, start new ones + pendingQueries = 0 + reply = make(chan []*Node, alpha) } - pendingQueries-- } return result.entries } @@ -293,18 +307,20 @@ func (net *Network) RegisterTopic(topic Topic, stop <-chan struct{}) { } } -func (net *Network) SearchTopic(topic Topic, stop <-chan struct{}, found chan<- string) { - select { - case net.topicSearchReq <- topicSearchReq{topic, found}: - case <-net.closed: - return - } - select { - case <-net.closed: - case <-stop: +func (net *Network) SearchTopic(topic Topic, setPeriod <-chan time.Duration, found chan<- *Node, lookup chan<- bool) { + for { select { - case net.topicSearchReq <- topicSearchReq{topic, nil}: case <-net.closed: + return + case delay, ok := <-setPeriod: + select { + case net.topicSearchReq <- topicSearchReq{topic: topic, found: found, lookup: lookup, delay: delay}: + case <-net.closed: + return + } + if !ok { + return + } } } } @@ -347,6 +363,13 @@ func (net *Network) reqTableOp(f func()) (called bool) { // TODO: external address handling. +type topicSearchInfo struct { + lookupChn chan<- bool + period time.Duration +} + +const maxSearchCount = 5 + func (net *Network) loop() { var ( refreshTimer = time.NewTicker(autoRefreshInterval) @@ -385,10 +408,12 @@ func (net *Network) loop() { topicRegisterLookupTarget lookupInfo topicRegisterLookupDone chan []*Node topicRegisterLookupTick = time.NewTimer(0) - topicSearchLookupTarget lookupInfo searchReqWhenRefreshDone []topicSearchReq + searchInfo = make(map[Topic]topicSearchInfo) + activeSearchCount int ) - topicSearchLookupDone := make(chan []*Node, 1) + topicSearchLookupDone := make(chan topicSearchResult, 100) + topicSearch := make(chan Topic, 100) <-topicRegisterLookupTick.C statsDump := time.NewTicker(10 * time.Second) @@ -504,21 +529,52 @@ loop: case req := <-net.topicSearchReq: if refreshDone == nil { debugLog("<-net.topicSearchReq") - if req.found == nil { - net.ticketStore.removeSearchTopic(req.topic) + info, ok := searchInfo[req.topic] + if ok { + if req.delay == time.Duration(0) { + delete(searchInfo, req.topic) + net.ticketStore.removeSearchTopic(req.topic) + } else { + info.period = req.delay + searchInfo[req.topic] = info + } continue } - net.ticketStore.addSearchTopic(req.topic, req.found) - if (topicSearchLookupTarget.target == common.Hash{}) { - topicSearchLookupDone <- nil + if req.delay != time.Duration(0) { + var info topicSearchInfo + info.period = req.delay + info.lookupChn = req.lookup + searchInfo[req.topic] = info + net.ticketStore.addSearchTopic(req.topic, req.found) + topicSearch <- req.topic } } else { searchReqWhenRefreshDone = append(searchReqWhenRefreshDone, req) } - case nodes := <-topicSearchLookupDone: - debugLog("<-topicSearchLookupDone") - net.ticketStore.searchLookupDone(topicSearchLookupTarget, nodes, func(n *Node) []byte { + case topic := <-topicSearch: + if activeSearchCount < maxSearchCount { + activeSearchCount++ + target := net.ticketStore.nextSearchLookup(topic) + go func() { + nodes := net.lookup(target.target, false) + topicSearchLookupDone <- topicSearchResult{target: target, nodes: nodes} + }() + } + period := searchInfo[topic].period + if period != time.Duration(0) { + go func() { + time.Sleep(period) + topicSearch <- topic + }() + } + + case res := <-topicSearchLookupDone: + activeSearchCount-- + if lookupChn := searchInfo[res.target.topic].lookupChn; lookupChn != nil { + lookupChn <- net.ticketStore.radius[res.target.topic].converged + } + net.ticketStore.searchLookupDone(res.target, res.nodes, func(n *Node) []byte { net.ping(n, n.addr()) return n.pingEcho }, func(n *Node, topic Topic) []byte { @@ -531,11 +587,6 @@ loop: return nil } }) - topicSearchLookupTarget = net.ticketStore.nextSearchLookup() - target := topicSearchLookupTarget.target - if (target != common.Hash{}) { - go func() { topicSearchLookupDone <- net.lookup(target, false) }() - } case <-statsDump.C: debugLog("<-statsDump.C") @@ -708,7 +759,7 @@ func (net *Network) internNodeFromNeighbours(sender *net.UDPAddr, rn rpcNode) (n } return n, err } - if !bytes.Equal(n.IP, rn.IP) || n.UDP != rn.UDP || n.TCP != rn.TCP { + if !n.IP.Equal(rn.IP) || n.UDP != rn.UDP || n.TCP != rn.TCP { err = fmt.Errorf("metadata mismatch: got %v, want %v", rn, n) } return n, err diff --git a/p2p/discv5/net_test.go b/p2p/discv5/net_test.go index e3ae1db7ee..2523e3ee04 100644 --- a/p2p/discv5/net_test.go +++ b/p2p/discv5/net_test.go @@ -69,19 +69,19 @@ var lookupTestnet = &preminedTestnet{ target: MustHexID("166aea4f556532c6d34e8b740e5d314af7e9ac0ca79833bd751d6b665f12dfd38ec563c363b32f02aef4a80b44fd3def94612d497b99cb5f17fd24de454927ec"), targetSha: common.Hash{0x5c, 0x94, 0x4e, 0xe5, 0x1c, 0x5a, 0xe9, 0xf7, 0x2a, 0x95, 0xec, 0xcb, 0x8a, 0xed, 0x3, 0x74, 0xee, 0xcb, 0x51, 0x19, 0xd7, 0x20, 0xcb, 0xea, 0x68, 0x13, 0xe8, 0xe0, 0xd6, 0xad, 0x92, 0x61}, dists: [257][]NodeID{ - 240: []NodeID{ + 240: { MustHexID("2001ad5e3e80c71b952161bc0186731cf5ffe942d24a79230a0555802296238e57ea7a32f5b6f18564eadc1c65389448481f8c9338df0a3dbd18f708cbc2cbcb"), MustHexID("6ba3f4f57d084b6bf94cc4555b8c657e4a8ac7b7baf23c6874efc21dd1e4f56b7eb2721e07f5242d2f1d8381fc8cae535e860197c69236798ba1ad231b105794"), }, - 244: []NodeID{ + 244: { MustHexID("696ba1f0a9d55c59246f776600542a9e6432490f0cd78f8bb55a196918df2081a9b521c3c3ba48e465a75c10768807717f8f689b0b4adce00e1c75737552a178"), }, - 246: []NodeID{ + 246: { MustHexID("d6d32178bdc38416f46ffb8b3ec9e4cb2cfff8d04dd7e4311a70e403cb62b10be1b447311b60b4f9ee221a8131fc2cbd45b96dd80deba68a949d467241facfa8"), MustHexID("3ea3d04a43a3dfb5ac11cffc2319248cf41b6279659393c2f55b8a0a5fc9d12581a9d97ef5d8ff9b5abf3321a290e8f63a4f785f450dc8a672aba3ba2ff4fdab"), MustHexID("2fc897f05ae585553e5c014effd3078f84f37f9333afacffb109f00ca8e7a3373de810a3946be971cbccdfd40249f9fe7f322118ea459ac71acca85a1ef8b7f4"), }, - 247: []NodeID{ + 247: { MustHexID("3155e1427f85f10a5c9a7755877748041af1bcd8d474ec065eb33df57a97babf54bfd2103575fa829115d224c523596b401065a97f74010610fce76382c0bf32"), MustHexID("312c55512422cf9b8a4097e9a6ad79402e87a15ae909a4bfefa22398f03d20951933beea1e4dfa6f968212385e829f04c2d314fc2d4e255e0d3bc08792b069db"), MustHexID("38643200b172dcfef857492156971f0e6aa2c538d8b74010f8e140811d53b98c765dd2d96126051913f44582e8c199ad7c6d6819e9a56483f637feaac9448aac"), @@ -93,7 +93,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("4ab0a75941b12892369b4490a1928c8ca52a9ad6d3dffbd1d8c0b907bc200fe74c022d011ec39b64808a39c0ca41f1d3254386c3e7733e7044c44259486461b6"), MustHexID("d45150a72dc74388773e68e03133a3b5f51447fe91837d566706b3c035ee4b56f160c878c6273394daee7f56cc398985269052f22f75a8057df2fe6172765354"), }, - 248: []NodeID{ + 248: { MustHexID("6aadfce366a189bab08ac84721567483202c86590642ea6d6a14f37ca78d82bdb6509eb7b8b2f6f63c78ae3ae1d8837c89509e41497d719b23ad53dd81574afa"), MustHexID("a605ecfd6069a4cf4cf7f5840e5bc0ce10d23a3ac59e2aaa70c6afd5637359d2519b4524f56fc2ca180cdbebe54262f720ccaae8c1b28fd553c485675831624d"), MustHexID("29701451cb9448ca33fc33680b44b840d815be90146eb521641efbffed0859c154e8892d3906eae9934bfacee72cd1d2fa9dd050fd18888eea49da155ab0efd2"), @@ -111,7 +111,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("b76ea1a6fd6506ef6e3506a4f1f60ed6287fff8114af6141b2ff13e61242331b54082b023cfea5b3083354a4fb3f9eb8be01fb4a518f579e731a5d0707291a6b"), MustHexID("9b53a37950ca8890ee349b325032d7b672cab7eced178d3060137b24ef6b92a43977922d5bdfb4a3409a2d80128e02f795f9dae6d7d99973ad0e23a2afb8442f"), }, - 249: []NodeID{ + 249: { MustHexID("675ae65567c3c72c50c73bc0fd4f61f202ea5f93346ca57b551de3411ccc614fad61cb9035493af47615311b9d44ee7a161972ee4d77c28fe1ec029d01434e6a"), MustHexID("8eb81408389da88536ae5800392b16ef5109d7ea132c18e9a82928047ecdb502693f6e4a4cdd18b54296caf561db937185731456c456c98bfe7de0baf0eaa495"), MustHexID("2adba8b1612a541771cb93a726a38a4b88e97b18eced2593eb7daf82f05a5321ca94a72cc780c306ff21e551a932fc2c6d791e4681907b5ceab7f084c3fa2944"), @@ -129,7 +129,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("d94193f236105010972f5df1b7818b55846592a0445b9cdc4eaed811b8c4c0f7c27dc8cc9837a4774656d6b34682d6d329d42b6ebb55da1d475c2474dc3dfdf4"), MustHexID("edd9af6aded4094e9785637c28fccbd3980cbe28e2eb9a411048a23c2ace4bd6b0b7088a7817997b49a3dd05fc6929ca6c7abbb69438dbdabe65e971d2a794b2"), }, - 250: []NodeID{ + 250: { MustHexID("53a5bd1215d4ab709ae8fdc2ced50bba320bced78bd9c5dc92947fb402250c914891786db0978c898c058493f86fc68b1c5de8a5cb36336150ac7a88655b6c39"), MustHexID("b7f79e3ab59f79262623c9ccefc8f01d682323aee56ffbe295437487e9d5acaf556a9c92e1f1c6a9601f2b9eb6b027ae1aeaebac71d61b9b78e88676efd3e1a3"), MustHexID("d374bf7e8d7ffff69cc00bebff38ef5bc1dcb0a8d51c1a3d70e61ac6b2e2d6617109254b0ac224354dfbf79009fe4239e09020c483cc60c071e00b9238684f30"), @@ -147,7 +147,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("5b116f0751526868a909b61a30b0c5282c37df6925cc03ddea556ef0d0602a9595fd6c14d371f8ed7d45d89918a032dcd22be4342a8793d88fdbeb3ca3d75bd7"), MustHexID("50f3222fb6b82481c7c813b2172e1daea43e2710a443b9c2a57a12bd160dd37e20f87aa968c82ad639af6972185609d47036c0d93b4b7269b74ebd7073221c10"), }, - 251: []NodeID{ + 251: { MustHexID("9b8f702a62d1bee67bedfeb102eca7f37fa1713e310f0d6651cc0c33ea7c5477575289ccd463e5a2574a00a676a1fdce05658ba447bb9d2827f0ba47b947e894"), MustHexID("b97532eb83054ed054b4abdf413bb30c00e4205545c93521554dbe77faa3cfaa5bd31ef466a107b0b34a71ec97214c0c83919720142cddac93aa7a3e928d4708"), MustHexID("2f7a5e952bfb67f2f90b8441b5fadc9ee13b1dcde3afeeb3dd64bf937f86663cc5c55d1fa83952b5422763c7df1b7f2794b751c6be316ebc0beb4942e65ab8c1"), @@ -165,7 +165,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("fcc9a2e1ac3667026ff16192876d1813bb75abdbf39b929a92863012fe8b1d890badea7a0de36274d5c1eb1e8f975785532c50d80fd44b1a4b692f437303393f"), MustHexID("6d8b3efb461151dd4f6de809b62726f5b89e9b38e9ba1391967f61cde844f7528fecf821b74049207cee5a527096b31f3ad623928cd3ce51d926fa345a6b2951"), }, - 252: []NodeID{ + 252: { MustHexID("f1ae93157cc48c2075dd5868fbf523e79e06caf4b8198f352f6e526680b78ff4227263de92612f7d63472bd09367bb92a636fff16fe46ccf41614f7a72495c2a"), MustHexID("587f482d111b239c27c0cb89b51dd5d574db8efd8de14a2e6a1400c54d4567e77c65f89c1da52841212080b91604104768350276b6682f2f961cdaf4039581c7"), MustHexID("e3f88274d35cefdaabdf205afe0e80e936cc982b8e3e47a84ce664c413b29016a4fb4f3a3ebae0a2f79671f8323661ed462bf4390af94c424dc8ace0c301b90f"), @@ -183,7 +183,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("d84f06fe64debc4cd0625e36d19b99014b6218375262cc2209202bdbafd7dffcc4e34ce6398e182e02fd8faeed622c3e175545864902dfd3d1ac57647cddf4c6"), MustHexID("d0ed87b294f38f1d741eb601020eeec30ac16331d05880fe27868f1e454446de367d7457b41c79e202eaf9525b029e4f1d7e17d85a55f83a557c005c68d7328a"), }, - 253: []NodeID{ + 253: { MustHexID("ad4485e386e3cc7c7310366a7c38fb810b8896c0d52e55944bfd320ca294e7912d6c53c0a0cf85e7ce226e92491d60430e86f8f15cda0161ed71893fb4a9e3a1"), MustHexID("36d0e7e5b7734f98c6183eeeb8ac5130a85e910a925311a19c4941b1290f945d4fc3996b12ef4966960b6fa0fb29b1604f83a0f81bd5fd6398d2e1a22e46af0c"), MustHexID("7d307d8acb4a561afa23bdf0bd945d35c90245e26345ec3a1f9f7df354222a7cdcb81339c9ed6744526c27a1a0c8d10857e98df942fa433602facac71ac68a31"), @@ -201,7 +201,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("7a369b2b8962cc4c65900be046482fbf7c14f98a135bbbae25152c82ad168fb2097b3d1429197cf46d3ce9fdeb64808f908a489cc6019725db040060fdfe5405"), MustHexID("47bcae48288da5ecc7f5058dfa07cf14d89d06d6e449cb946e237aa6652ea050d9f5a24a65efdc0013ccf232bf88670979eddef249b054f63f38da9d7796dbd8"), }, - 254: []NodeID{ + 254: { MustHexID("099739d7abc8abd38ecc7a816c521a1168a4dbd359fa7212a5123ab583ffa1cf485a5fed219575d6475dbcdd541638b2d3631a6c7fce7474e7fe3cba1d4d5853"), MustHexID("c2b01603b088a7182d0cf7ef29fb2b04c70acb320fccf78526bf9472e10c74ee70b3fcfa6f4b11d167bd7d3bc4d936b660f2c9bff934793d97cb21750e7c3d31"), MustHexID("20e4d8f45f2f863e94b45548c1ef22a11f7d36f263e4f8623761e05a64c4572379b000a52211751e2561b0f14f4fc92dd4130410c8ccc71eb4f0e95a700d4ca9"), @@ -219,7 +219,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("82504b6eb49bb2c0f91a7006ce9cefdbaf6df38706198502c2e06601091fc9dc91e4f15db3410d45c6af355bc270b0f268d3dff560f956985c7332d4b10bd1ed"), MustHexID("b39b5b677b45944ceebe76e76d1f051de2f2a0ec7b0d650da52135743e66a9a5dba45f638258f9a7545d9a790c7fe6d3fdf82c25425c7887323e45d27d06c057"), }, - 255: []NodeID{ + 255: { MustHexID("5c4d58d46e055dd1f093f81ee60a675e1f02f54da6206720adee4dccef9b67a31efc5c2a2949c31a04ee31beadc79aba10da31440a1f9ff2a24093c63c36d784"), MustHexID("ea72161ffdd4b1e124c7b93b0684805f4c4b58d617ed498b37a145c670dbc2e04976f8785583d9c805ffbf343c31d492d79f841652bbbd01b61ed85640b23495"), MustHexID("51caa1d93352d47a8e531692a3612adac1e8ac68d0a200d086c1c57ae1e1a91aa285ab242e8c52ef9d7afe374c9485b122ae815f1707b875569d0433c1c3ce85"), @@ -237,7 +237,7 @@ var lookupTestnet = &preminedTestnet{ MustHexID("f492c6ee2696d5f682f7f537757e52744c2ae560f1090a07024609e903d334e9e174fc01609c5a229ddbcac36c9d21adaf6457dab38a25bfd44f2f0ee4277998"), MustHexID("459e4db99298cb0467a90acee6888b08bb857450deac11015cced5104853be5adce5b69c740968bc7f931495d671a70cad9f48546d7cd203357fe9af0e8d2164"), }, - 256: []NodeID{ + 256: { MustHexID("a8593af8a4aef7b806b5197612017951bac8845a1917ca9a6a15dd6086d608505144990b245785c4cd2d67a295701c7aac2aa18823fb0033987284b019656268"), MustHexID("d2eebef914928c3aad77fc1b2a495f52d2294acf5edaa7d8a530b540f094b861a68fe8348a46a7c302f08ab609d85912a4968eacfea0740847b29421b4795d9e"), MustHexID("b14bfcb31495f32b650b63cf7d08492e3e29071fdc73cf2da0da48d4b191a70ba1a65f42ad8c343206101f00f8a48e8db4b08bf3f622c0853e7323b250835b91"), diff --git a/p2p/discv5/node.go b/p2p/discv5/node.go index d7b271808d..2351a00e24 100644 --- a/p2p/discv5/node.go +++ b/p2p/discv5/node.go @@ -17,7 +17,6 @@ package discv5 import ( - "bytes" "crypto/ecdsa" "crypto/elliptic" "encoding/hex" @@ -81,7 +80,7 @@ func (n *Node) addrEqual(a *net.UDPAddr) bool { if ipv4 := a.IP.To4(); ipv4 != nil { ip = ipv4 } - return n.UDP == uint16(a.Port) && bytes.Equal(n.IP, ip) + return n.UDP == uint16(a.Port) && n.IP.Equal(ip) } // Incomplete returns true for nodes with no IP address. @@ -263,11 +262,8 @@ func (n NodeID) GoString() string { // HexID converts a hex string to a NodeID. // The string may be prefixed with 0x. func HexID(in string) (NodeID, error) { - if strings.HasPrefix(in, "0x") { - in = in[2:] - } var id NodeID - b, err := hex.DecodeString(in) + b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) if err != nil { return id, err } else if len(b) != len(id) { diff --git a/p2p/discv5/sim_test.go b/p2p/discv5/sim_test.go index 694c4ef6f7..56daaacd6e 100644 --- a/p2p/discv5/sim_test.go +++ b/p2p/discv5/sim_test.go @@ -74,7 +74,7 @@ func TestSimTopics(t *testing.T) { go func() { nets := make([]*Network, 1024) - for i, _ := range nets { + for i := range nets { net := sim.launchNode(false) nets[i] = net if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { @@ -147,7 +147,7 @@ func TestSimTopics(t *testing.T) { func testHierarchicalTopics(i int) []Topic { digits := strconv.FormatInt(int64(128+i/8), 2) res := make([]Topic, 8) - for i, _ := range res { + for i := range res { res[i] = Topic("foo" + digits[1:i+1]) } return res @@ -167,7 +167,7 @@ func TestSimTopicHierarchy(t *testing.T) { go func() { nets := make([]*Network, 1024) - for i, _ := range nets { + for i := range nets { net := sim.launchNode(false) nets[i] = net if err := net.SetFallbackNodes([]*Node{bootnode.Self()}); err != nil { diff --git a/p2p/discv5/ticket.go b/p2p/discv5/ticket.go index 43a20454c2..f542357130 100644 --- a/p2p/discv5/ticket.go +++ b/p2p/discv5/ticket.go @@ -138,16 +138,12 @@ type ticketStore struct { nextTicketReg mclock.AbsTime searchTopicMap map[Topic]searchTopic - searchTopicList []Topic - searchTopicPtr int nextTopicQueryCleanup mclock.AbsTime queriesSent map[*Node]map[common.Hash]sentQuery - radiusLookupCnt int } type searchTopic struct { - foundChn chan<- string - listIdx int + foundChn chan<- *Node } type sentQuery struct { @@ -183,23 +179,15 @@ func (s *ticketStore) addTopic(t Topic, register bool) { } } -func (s *ticketStore) addSearchTopic(t Topic, foundChn chan<- string) { +func (s *ticketStore) addSearchTopic(t Topic, foundChn chan<- *Node) { s.addTopic(t, false) if s.searchTopicMap[t].foundChn == nil { - s.searchTopicList = append(s.searchTopicList, t) - s.searchTopicMap[t] = searchTopic{foundChn: foundChn, listIdx: len(s.searchTopicList) - 1} + s.searchTopicMap[t] = searchTopic{foundChn: foundChn} } } func (s *ticketStore) removeSearchTopic(t Topic) { if st := s.searchTopicMap[t]; st.foundChn != nil { - lastIdx := len(s.searchTopicList) - 1 - lastTopic := s.searchTopicList[lastIdx] - s.searchTopicList[st.listIdx] = lastTopic - sl := s.searchTopicMap[lastTopic] - sl.listIdx = st.listIdx - s.searchTopicMap[lastTopic] = sl - s.searchTopicList = s.searchTopicList[:lastIdx] delete(s.searchTopicMap, t) } } @@ -247,20 +235,13 @@ func (s *ticketStore) nextRegisterLookup() (lookup lookupInfo, delay time.Durati return lookupInfo{}, 40 * time.Second } -func (s *ticketStore) nextSearchLookup() lookupInfo { - if len(s.searchTopicList) == 0 { - return lookupInfo{} - } - if s.searchTopicPtr >= len(s.searchTopicList) { - s.searchTopicPtr = 0 - } - topic := s.searchTopicList[s.searchTopicPtr] - s.searchTopicPtr++ - target := s.radius[topic].nextTarget(s.radiusLookupCnt >= searchForceQuery) +func (s *ticketStore) nextSearchLookup(topic Topic) lookupInfo { + tr := s.radius[topic] + target := tr.nextTarget(tr.radiusLookupCnt >= searchForceQuery) if target.radiusLookup { - s.radiusLookupCnt++ + tr.radiusLookupCnt++ } else { - s.radiusLookupCnt = 0 + tr.radiusLookupCnt = 0 } return target } @@ -662,9 +643,9 @@ func (s *ticketStore) gotTopicNodes(from *Node, hash common.Hash, nodes []rpcNod if ip.IsUnspecified() || ip.IsLoopback() { ip = from.IP } - enode := NewNode(node.ID, ip, node.UDP-1, node.TCP-1).String() // subtract one from port while discv5 is running in test mode on UDPport+1 + n := NewNode(node.ID, ip, node.UDP-1, node.TCP-1) // subtract one from port while discv5 is running in test mode on UDPport+1 select { - case chn <- enode: + case chn <- n: default: return false } @@ -677,6 +658,8 @@ type topicRadius struct { topicHashPrefix uint64 radius, minRadius uint64 buckets []topicRadiusBucket + converged bool + radiusLookupCnt int } type topicRadiusEvent int @@ -706,7 +689,7 @@ func (b *topicRadiusBucket) update(now mclock.AbsTime) { b.lastTime = now for target, tm := range b.lookupSent { - if now-tm > mclock.AbsTime(pingTimeout) { + if now-tm > mclock.AbsTime(respTimeout) { b.weights[trNoAdjust] += 1 delete(b.lookupSent, target) } @@ -848,7 +831,7 @@ func (r *topicRadius) recalcRadius() (radius uint64, radiusLookup int) { maxValue := float64(0) now := mclock.Now() v := float64(0) - for i, _ := range r.buckets { + for i := range r.buckets { r.buckets[i].update(now) v += r.buckets[i].weights[trOutside] - r.buckets[i].weights[trInside] r.buckets[i].value = v @@ -906,6 +889,7 @@ func (r *topicRadius) recalcRadius() (radius uint64, radiusLookup int) { if radiusLookup == -1 { // no more radius lookups needed at the moment, return a radius + r.converged = true rad := maxBucket if minRadBucket < rad { rad = minRadBucket diff --git a/p2p/discv5/topic.go b/p2p/discv5/topic.go index 49dac88561..0b464a9277 100644 --- a/p2p/discv5/topic.go +++ b/p2p/discv5/topic.go @@ -316,7 +316,7 @@ func (t *topicTable) collectGarbage() { t.checkDeleteNode(node) } - for topic, _ := range t.topics { + for topic := range t.topics { t.checkDeleteTopic(topic) } } diff --git a/p2p/discv5/udp.go b/p2p/discv5/udp.go index 56e4ffb65c..ea70d5fb2b 100644 --- a/p2p/discv5/udp.go +++ b/p2p/discv5/udp.go @@ -196,7 +196,7 @@ func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint { } func (e1 rpcEndpoint) equal(e2 rpcEndpoint) bool { - return e1.UDP == e2.UDP && e1.TCP == e2.TCP && bytes.Equal(e1.IP, e2.IP) + return e1.UDP == e2.UDP && e1.TCP == e2.TCP && e1.IP.Equal(e2.IP) } func nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { diff --git a/p2p/discv5/udp_test.go b/p2p/discv5/udp_test.go index c2a68eb16b..8fb87d2b70 100644 --- a/p2p/discv5/udp_test.go +++ b/p2p/discv5/udp_test.go @@ -126,7 +126,7 @@ var ( // defer test.table.Close() // // // put a few nodes into the table. their exact -// // distribution shouldn't matter much, altough we need to +// // distribution shouldn't matter much, although we need to // // take care not to overflow any bucket. // targetHash := crypto.Keccak256Hash(testTarget[:]) // nodes := &nodesByDistance{target: targetHash} diff --git a/p2p/nat/nat_test.go b/p2p/nat/nat_test.go index a079e7a22c..469101e997 100644 --- a/p2p/nat/nat_test.go +++ b/p2p/nat/nat_test.go @@ -17,7 +17,6 @@ package nat import ( - "bytes" "net" "testing" "time" @@ -56,7 +55,7 @@ func TestAutoDiscRace(t *testing.T) { t.Errorf("result %d: unexpected error: %v", i, rval.err) } wantIP := net.IP{33, 44, 55, 66} - if !bytes.Equal(rval.ip, wantIP) { + if !rval.ip.Equal(wantIP) { t.Errorf("result %d: got IP %v, want %v", i, rval.ip, wantIP) } } diff --git a/p2p/nat/natpmp.go b/p2p/nat/natpmp.go index c2f9408914..577a424fbe 100644 --- a/p2p/nat/natpmp.go +++ b/p2p/nat/natpmp.go @@ -82,7 +82,7 @@ func discoverPMP() Interface { // any responses after a very short timeout. timeout := time.NewTimer(1 * time.Second) defer timeout.Stop() - for _ = range gws { + for range gws { select { case c := <-found: if c != nil { diff --git a/p2p/peer_test.go b/p2p/peer_test.go index 6f96a823b4..f44300b15c 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -299,7 +299,7 @@ func TestMatchProtocols(t *testing.T) { } } // Make sure no protocols missed negotiation - for name, _ := range tt.Match { + for name := range tt.Match { if _, ok := result[name]; !ok { t.Errorf("test %d, proto '%s': not negotiated, should have", i, name) continue diff --git a/p2p/rlpx.go b/p2p/rlpx.go index b2ea7f6dd0..a28f9a144a 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -429,7 +429,7 @@ func (msg *authMsgV4) decodePlain(input []byte) { n := copy(msg.Signature[:], input) n += shaLen // skip sha3(initiator-ephemeral-pubk) n += copy(msg.InitiatorPubkey[:], input[n:]) - n += copy(msg.Nonce[:], input[n:]) + copy(msg.Nonce[:], input[n:]) msg.Version = 4 msg.gotPlain = true } @@ -437,13 +437,13 @@ func (msg *authMsgV4) decodePlain(input []byte) { func (msg *authRespV4) sealPlain(hs *encHandshake) ([]byte, error) { buf := make([]byte, authRespLen) n := copy(buf, msg.RandomPubkey[:]) - n += copy(buf[n:], msg.Nonce[:]) + copy(buf[n:], msg.Nonce[:]) return ecies.Encrypt(rand.Reader, hs.remotePub, buf, nil, nil) } func (msg *authRespV4) decodePlain(input []byte) { n := copy(msg.RandomPubkey[:], input) - n += copy(msg.Nonce[:], input[n:]) + copy(msg.Nonce[:], input[n:]) msg.Version = 4 } diff --git a/p2p/server.go b/p2p/server.go index fd2e2be873..1de7b0d348 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -54,8 +54,6 @@ const ( var errServerStopped = errors.New("server stopped") -var srvjslog = logger.NewJsonLogger() - // Config holds Server options. type Config struct { // This field must be set to a valid secp256k1 private key. @@ -737,12 +735,6 @@ func (srv *Server) checkpoint(c *conn, stage chan<- *conn) error { // the peer. func (srv *Server) runPeer(p *Peer) { glog.V(logger.Debug).Infof("Added %v\n", p) - srvjslog.LogJson(&logger.P2PConnected{ - RemoteId: p.ID().String(), - RemoteAddress: p.RemoteAddr().String(), - RemoteVersionString: p.Name(), - NumConnections: srv.PeerCount(), - }) if srv.newPeerHook != nil { srv.newPeerHook(p) @@ -753,10 +745,6 @@ func (srv *Server) runPeer(p *Peer) { srv.delpeer <- p glog.V(logger.Debug).Infof("Removed %v (%v)\n", p, discreason) - srvjslog.LogJson(&logger.P2PDisconnected{ - RemoteId: p.ID().String(), - NumConnections: srv.PeerCount(), - }) } // NodeInfo represents a short summary of the information known about the host. diff --git a/params/bootnodes.go b/params/bootnodes.go index 8c5978ec39..2cdc57ff1c 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -16,26 +16,19 @@ package params -import ( - "github.com/ubiq/go-ubiq/p2p/discover" - "github.com/ubiq/go-ubiq/p2p/discv5" -) - // MainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on // the main Ubiq network. -var MainnetBootnodes = []*discover.Node{ +var MainnetBootnodes = []string{ // Ubiq Go Bootnodes - discover.MustParseNode("enode://e51f1a9e4d92e71d4e4104c12447bbc0433351607e73e860bbf4340d464c798dd1b1054cd733fc7cf5279a486a38275a27f64bedb11ff5eec6d6191384f64aa5@107.191.104.192:30388"), - discover.MustParseNode("enode://b3a58d00c799f5181ebed01df04cb0bd714cde5b87a2c00d953227c85cf96ef98235ca856646d5419d01c2b8ff688dbce8fd4e6078ac9619502f0eabe93f404c@45.63.95.155:30388"), - discover.MustParseNode("enode://6c94a1caeef18228bdaecbef0802332566a73398d9f371f486e4ae2e7aa9a88f4e98c549dd60697d3f4ccb1ec65c0ed8e1554b274fee89da99e7358c580cc408@45.63.65.79:30388"), + "enode://e51f1a9e4d92e71d4e4104c12447bbc0433351607e73e860bbf4340d464c798dd1b1054cd733fc7cf5279a486a38275a27f64bedb11ff5eec6d6191384f64aa5@107.191.104.192:30388", + "enode://b3a58d00c799f5181ebed01df04cb0bd714cde5b87a2c00d953227c85cf96ef98235ca856646d5419d01c2b8ff688dbce8fd4e6078ac9619502f0eabe93f404c@45.63.95.155:30388", + "enode://6c94a1caeef18228bdaecbef0802332566a73398d9f371f486e4ae2e7aa9a88f4e98c549dd60697d3f4ccb1ec65c0ed8e1554b274fee89da99e7358c580cc408@45.63.65.79:30388", } // TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Morden test network. -var TestnetBootnodes = []*discover.Node{ -} +var TestnetBootnodes = []string{} // DiscoveryV5Bootnodes are the enode URLs of the P2P bootstrap nodes for the // experimental RLPx v5 topic-discovery network. -var DiscoveryV5Bootnodes = []*discv5.Node{ -} +var DiscoveryV5Bootnodes = []string{} diff --git a/params/protocol_params.go b/params/protocol_params.go index e98925c2b9..f5b6bedeb7 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -58,7 +58,7 @@ var ( Ripemd160WordGas = big.NewInt(120) // MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. CallCreateDepth = big.NewInt(1024) // Maximum depth of call/create stack. - ExpGas = big.NewInt(10) // Once per EXP instuction. + ExpGas = big.NewInt(10) // Once per EXP instruction. LogGas = big.NewInt(375) // Per LOG* operation. CopyGas = big.NewInt(3) // StackLimit = big.NewInt(1024) // Maximum size of VM stack allowed. diff --git a/params/version.go b/params/version.go index f8c0d3c9ac..6eb920a21e 100644 --- a/params/version.go +++ b/params/version.go @@ -21,7 +21,7 @@ import "fmt" const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 5 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release + VersionPatch = 7 // Patch version component of the current release VersionMeta = "unstable" // Version metadata to append to the version string ) diff --git a/pow/dagger/dagger.go b/pow/dagger/dagger.go deleted file mode 100644 index a392e6ff84..0000000000 --- a/pow/dagger/dagger.go +++ /dev/null @@ -1,176 +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 . - -package dagger - -import ( - "hash" - "math/big" - "math/rand" - "time" - - "github.com/ubiq/go-ubiq/common" - "github.com/ubiq/go-ubiq/crypto/sha3" - "github.com/ubiq/go-ubiq/logger" -) - -var powlogger = logger.NewLogger("POW") - -type Dagger struct { - hash *big.Int - xn *big.Int -} - -var Found bool - -func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - - for i := 0; i < 1000; i++ { - rnd := r.Int63() - - res := dag.Eval(big.NewInt(rnd)) - powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj) - if res.Cmp(obj) < 0 { - // Post back result on the channel - resChan <- rnd - // Notify other threads we've found a valid nonce - Found = true - } - - // Break out if found - if Found { - break - } - } - - resChan <- 0 -} - -func (dag *Dagger) Search(hash, diff *big.Int) (uint64, []byte) { - // TODO fix multi threading. Somehow it results in the wrong nonce - amountOfRoutines := 1 - - dag.hash = hash - - obj := common.BigPow(2, 256) - obj = obj.Div(obj, diff) - - Found = false - resChan := make(chan int64, 3) - var res int64 - - for k := 0; k < amountOfRoutines; k++ { - go dag.Find(obj, resChan) - - // Wait for each go routine to finish - } - for k := 0; k < amountOfRoutines; k++ { - // Get the result from the channel. 0 = quit - if r := <-resChan; r != 0 { - res = r - } - } - - return uint64(res), nil -} - -func (dag *Dagger) Verify(hash, diff, nonce *big.Int) bool { - dag.hash = hash - - obj := common.BigPow(2, 256) - obj = obj.Div(obj, diff) - - return dag.Eval(nonce).Cmp(obj) < 0 -} - -func DaggerVerify(hash, diff, nonce *big.Int) bool { - dagger := &Dagger{} - dagger.hash = hash - - obj := common.BigPow(2, 256) - obj = obj.Div(obj, diff) - - return dagger.Eval(nonce).Cmp(obj) < 0 -} - -func (dag *Dagger) Node(L uint64, i uint64) *big.Int { - if L == i { - return dag.hash - } - - var m *big.Int - if L == 9 { - m = big.NewInt(16) - } else { - m = big.NewInt(3) - } - - sha := sha3.NewKeccak256() - sha.Reset() - d := sha3.NewKeccak256() - b := new(big.Int) - ret := new(big.Int) - - for k := 0; k < int(m.Uint64()); k++ { - d.Reset() - d.Write(dag.hash.Bytes()) - d.Write(dag.xn.Bytes()) - d.Write(big.NewInt(int64(L)).Bytes()) - d.Write(big.NewInt(int64(i)).Bytes()) - d.Write(big.NewInt(int64(k)).Bytes()) - - b.SetBytes(Sum(d)) - pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1) - sha.Write(dag.Node(L-1, pk).Bytes()) - } - - ret.SetBytes(Sum(sha)) - - return ret -} - -func Sum(sha hash.Hash) []byte { - //in := make([]byte, 32) - return sha.Sum(nil) -} - -func (dag *Dagger) Eval(N *big.Int) *big.Int { - pow := common.BigPow(2, 26) - dag.xn = pow.Div(N, pow) - - sha := sha3.NewKeccak256() - sha.Reset() - ret := new(big.Int) - - for k := 0; k < 4; k++ { - d := sha3.NewKeccak256() - b := new(big.Int) - - d.Reset() - d.Write(dag.hash.Bytes()) - d.Write(dag.xn.Bytes()) - d.Write(N.Bytes()) - d.Write(big.NewInt(int64(k)).Bytes()) - - b.SetBytes(Sum(d)) - pk := (b.Uint64() & 0x1ffffff) - - sha.Write(dag.Node(9, pk).Bytes()) - } - - return ret.SetBytes(Sum(sha)) -} diff --git a/pow/ezp/pow.go b/pow/ezp/pow.go deleted file mode 100644 index e18416a4b7..0000000000 --- a/pow/ezp/pow.go +++ /dev/null @@ -1,113 +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 . - -package ezp - -import ( - "encoding/binary" - "math/big" - "math/rand" - "time" - - "github.com/ubiq/go-ubiq/common" - "github.com/ubiq/go-ubiq/crypto/sha3" - "github.com/ubiq/go-ubiq/logger" - "github.com/ubiq/go-ubiq/pow" -) - -var powlogger = logger.NewLogger("POW") - -type EasyPow struct { - hash *big.Int - HashRate int64 - turbo bool -} - -func New() *EasyPow { - return &EasyPow{turbo: false} -} - -func (pow *EasyPow) GetHashrate() int64 { - return pow.HashRate -} - -func (pow *EasyPow) Turbo(on bool) { - pow.turbo = on -} - -func (pow *EasyPow) Search(block pow.Block, stop <-chan struct{}, index int) (uint64, []byte) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - hash := block.HashNoNonce() - diff := block.Difficulty() - //i := int64(0) - // TODO fix offset - i := rand.Int63() - starti := i - start := time.Now().UnixNano() - - defer func() { pow.HashRate = 0 }() - - // Make sure stop is empty -empty: - for { - select { - case <-stop: - default: - break empty - } - } - - for { - select { - case <-stop: - return 0, nil - default: - i++ - - elapsed := time.Now().UnixNano() - start - hashes := ((float64(1e9) / float64(elapsed)) * float64(i-starti)) / 1000 - pow.HashRate = int64(hashes) - - sha := uint64(r.Int63()) - if verify(hash, diff, sha) { - return sha, nil - } - } - - if !pow.turbo { - time.Sleep(20 * time.Microsecond) - } - } -} - -func (pow *EasyPow) Verify(block pow.Block) bool { - return Verify(block) -} - -func verify(hash common.Hash, diff *big.Int, nonce uint64) bool { - sha := sha3.NewKeccak256() - n := make([]byte, 8) - binary.PutUvarint(n, nonce) - sha.Write(n) - sha.Write(hash[:]) - verification := new(big.Int).Div(common.BigPow(2, 256), diff) - res := common.BigD(sha.Sum(nil)) - return res.Cmp(verification) <= 0 -} - -func Verify(block pow.Block) bool { - return verify(block.HashNoNonce(), block.Difficulty(), block.Nonce()) -} diff --git a/rpc/json.go b/rpc/json.go index 74704b8954..4fd82a57d6 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -17,6 +17,7 @@ package rpc import ( + "bytes" "encoding/json" "fmt" "io" @@ -165,7 +166,7 @@ func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) { // subscribe are special, they will always use `subscribeMethod` as first param in the payload if in.Method == subscribeMethod { - reqs := []rpcRequest{rpcRequest{id: &in.Id, isPubSub: true}} + reqs := []rpcRequest{{id: &in.Id, isPubSub: true}} if len(in.Payload) > 0 { // first param must be subscription name var subscribeMethod [1]string @@ -183,7 +184,7 @@ func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) { } if in.Method == unsubscribeMethod { - return []rpcRequest{rpcRequest{id: &in.Id, isPubSub: true, + return []rpcRequest{{id: &in.Id, isPubSub: true, method: unsubscribeMethod, params: in.Payload}}, false, nil } @@ -194,10 +195,10 @@ func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) { // regular RPC call if len(in.Payload) == 0 { - return []rpcRequest{rpcRequest{service: elems[0], method: elems[1], id: &in.Id}}, false, nil + return []rpcRequest{{service: elems[0], method: elems[1], id: &in.Id}}, false, nil } - return []rpcRequest{rpcRequest{service: elems[0], method: elems[1], id: &in.Id, params: in.Payload}}, false, nil + return []rpcRequest{{service: elems[0], method: elems[1], id: &in.Id, params: in.Payload}}, false, nil } // parseBatchRequest will parse a batch request into a collection of requests from the given RawMessage, an indication @@ -256,8 +257,8 @@ func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) return requests, true, nil } -// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given types. It returns the parsed -// values or an error when the parsing failed. +// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given +// types. It returns the parsed values or an error when the parsing failed. func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interface{}) ([]reflect.Value, Error) { if args, ok := params.(json.RawMessage); !ok { return nil, &invalidParamsError{"Invalid params supplied"} @@ -266,42 +267,42 @@ func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interf } } -// parsePositionalArguments tries to parse the given args to an array of values with the given types. -// It returns the parsed values or an error when the args could not be parsed. Missing optional arguments -// are returned as reflect.Zero values. -func parsePositionalArguments(args json.RawMessage, callbackArgs []reflect.Type) ([]reflect.Value, Error) { - params := make([]interface{}, 0, len(callbackArgs)) - for _, t := range callbackArgs { - params = append(params, reflect.New(t).Interface()) +// parsePositionalArguments tries to parse the given args to an array of values with the +// given types. It returns the parsed values or an error when the args could not be +// parsed. Missing optional arguments are returned as reflect.Zero values. +func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, Error) { + // Read beginning of the args array. + dec := json.NewDecoder(bytes.NewReader(rawArgs)) + if tok, _ := dec.Token(); tok != json.Delim('[') { + return nil, &invalidParamsError{"non-array args"} } - - if err := json.Unmarshal(args, ¶ms); err != nil { + // Read args. + args := make([]reflect.Value, 0, len(types)) + for i := 0; dec.More(); i++ { + if i >= len(types) { + return nil, &invalidParamsError{fmt.Sprintf("too many arguments, want at most %d", len(types))} + } + argval := reflect.New(types[i]) + if err := dec.Decode(argval.Interface()); err != nil { + return nil, &invalidParamsError{fmt.Sprintf("invalid argument %d: %v", i, err)} + } + if argval.IsNil() && types[i].Kind() != reflect.Ptr { + return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} + } + args = append(args, argval.Elem()) + } + // Read end of args array. + if _, err := dec.Token(); err != nil { return nil, &invalidParamsError{err.Error()} } - - if len(params) > len(callbackArgs) { - return nil, &invalidParamsError{fmt.Sprintf("too many params, want %d got %d", len(callbackArgs), len(params))} - } - - // assume missing params are null values - for i := len(params); i < len(callbackArgs); i++ { - params = append(params, nil) - } - - argValues := make([]reflect.Value, len(params)) - for i, p := range params { - // verify that JSON null values are only supplied for optional arguments (ptr types) - if p == nil && callbackArgs[i].Kind() != reflect.Ptr { - return nil, &invalidParamsError{fmt.Sprintf("invalid or missing value for params[%d]", i)} - } - if p == nil { - argValues[i] = reflect.Zero(callbackArgs[i]) - } else { // deref pointers values creates previously with reflect.New - argValues[i] = reflect.ValueOf(p).Elem() + // Set any missing args to nil. + for i := len(args); i < len(types); i++ { + if types[i].Kind() != reflect.Ptr { + return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} } + args = append(args, reflect.Zero(types[i])) } - - return argValues, nil + return args, nil } // CreateResponse will create a JSON-RPC success response with the given id and reply as result. diff --git a/rpc/subscription.go b/rpc/subscription.go index 863d34b202..bcdc3cdfca 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -30,7 +30,7 @@ var ( ErrSubscriptionNotFound = errors.New("subscription not found") ) -// ID defines a psuedo random number that is used to identify RPC subscriptions. +// ID defines a pseudo random number that is used to identify RPC subscriptions. type ID string // a Subscription is created by a notifier and tight to that notifier. The client can use diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 8bb3416947..00c4e0e354 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -62,7 +62,7 @@ func (s *NotificationTestService) SomeSubscription(ctx context.Context, n, val i subscription := notifier.CreateSubscription() go func() { - // test expects n events, if we begin sending event immediatly some events + // test expects n events, if we begin sending event immediately some events // will probably be dropped since the subscription ID might not be send to // the client. time.Sleep(5 * time.Second) @@ -141,7 +141,7 @@ func TestNotifications(t *testing.T) { } var ok bool - if subid, ok = response.Result.(string); !ok { + if _, ok = response.Result.(string); !ok { t.Fatalf("expected subscription id, got %T", response.Result) } diff --git a/rpc/types.go b/rpc/types.go index ebe3883735..d8d736efbc 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -17,8 +17,6 @@ package rpc import ( - "bytes" - "encoding/hex" "fmt" "math" "math/big" @@ -123,91 +121,6 @@ type ServerCodec interface { Closed() <-chan interface{} } -// HexNumber serializes a number to hex format using the "%#x" format -type HexNumber big.Int - -// NewHexNumber creates a new hex number instance which will serialize the given val with `%#x` on marshal. -func NewHexNumber(val interface{}) *HexNumber { - if val == nil { - return nil // note, this doesn't catch nil pointers, only passing nil directly! - } - - if v, ok := val.(*big.Int); ok { - if v != nil { - return (*HexNumber)(new(big.Int).Set(v)) - } - return nil - } - - rval := reflect.ValueOf(val) - - var unsigned uint64 - utype := reflect.TypeOf(unsigned) - if t := rval.Type(); t.ConvertibleTo(utype) { - hn := new(big.Int).SetUint64(rval.Convert(utype).Uint()) - return (*HexNumber)(hn) - } - - var signed int64 - stype := reflect.TypeOf(signed) - if t := rval.Type(); t.ConvertibleTo(stype) { - hn := new(big.Int).SetInt64(rval.Convert(stype).Int()) - return (*HexNumber)(hn) - } - - return nil -} - -func (h *HexNumber) UnmarshalJSON(input []byte) error { - length := len(input) - if length >= 2 && input[0] == '"' && input[length-1] == '"' { - input = input[1 : length-1] - } - - hn := (*big.Int)(h) - if _, ok := hn.SetString(string(input), 0); ok { - return nil - } - - return fmt.Errorf("Unable to parse number") -} - -// MarshalJSON serialize the hex number instance to a hex representation. -func (h *HexNumber) MarshalJSON() ([]byte, error) { - if h != nil { - hn := (*big.Int)(h) - if hn.BitLen() == 0 { - return []byte(`"0x0"`), nil - } - return []byte(fmt.Sprintf(`"0x%x"`, hn)), nil - } - return nil, nil -} - -func (h *HexNumber) Int() int { - hn := (*big.Int)(h) - return int(hn.Int64()) -} - -func (h *HexNumber) Int64() int64 { - hn := (*big.Int)(h) - return hn.Int64() -} - -func (h *HexNumber) Uint() uint { - hn := (*big.Int)(h) - return uint(hn.Uint64()) -} - -func (h *HexNumber) Uint64() uint64 { - hn := (*big.Int)(h) - return hn.Uint64() -} - -func (h *HexNumber) BigInt() *big.Int { - return (*big.Int)(h) -} - var ( pendingBlockNumber = big.NewInt(-2) latestBlockNumber = big.NewInt(-1) @@ -222,7 +135,7 @@ const ( LatestBlockNumber = BlockNumber(-1) ) -// UnmarshalJSON parses the given JSON fragement into a BlockNumber. It supports: +// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: // - "latest", "earliest" or "pending" as string arguments // - the block number // Returned errors: @@ -274,31 +187,3 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { func (bn BlockNumber) Int64() int64 { return (int64)(bn) } - -// HexBytes JSON-encodes as hex with 0x prefix. -type HexBytes []byte - -func (b HexBytes) MarshalJSON() ([]byte, error) { - result := make([]byte, len(b)*2+4) - copy(result, `"0x`) - hex.Encode(result[3:], b) - result[len(result)-1] = '"' - return result, nil -} - -func (b *HexBytes) UnmarshalJSON(input []byte) error { - if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { - input = input[1 : len(input)-1] - } - if !bytes.HasPrefix(input, []byte("0x")) { - return fmt.Errorf("missing 0x prefix for hex byte array") - } - input = input[2:] - if len(input) == 0 { - *b = nil - return nil - } - *b = make([]byte, len(input)/2) - _, err := hex.Decode(*b, input) - return err -} diff --git a/rpc/types_test.go b/rpc/types_test.go deleted file mode 100644 index 5482557b89..0000000000 --- a/rpc/types_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "bytes" - "encoding/json" - "math/big" - "testing" -) - -func TestNewHexNumber(t *testing.T) { - tests := []interface{}{big.NewInt(123), int64(123), uint64(123), int8(123), uint8(123)} - - for i, v := range tests { - hn := NewHexNumber(v) - if hn == nil { - t.Fatalf("Unable to create hex number instance for tests[%d]", i) - } - if hn.Int64() != 123 { - t.Fatalf("expected %d, got %d on value tests[%d]", 123, hn.Int64(), i) - } - } - - failures := []interface{}{"", nil, []byte{1, 2, 3, 4}} - for i, v := range failures { - hn := NewHexNumber(v) - if hn != nil { - t.Fatalf("Creating a nex number instance of %T should fail (failures[%d])", failures[i], i) - } - } -} - -func TestHexNumberUnmarshalJSON(t *testing.T) { - tests := []string{`"0x4d2"`, "1234", `"1234"`} - for i, v := range tests { - var hn HexNumber - if err := json.Unmarshal([]byte(v), &hn); err != nil { - t.Fatalf("Test %d failed - %s", i, err) - } - - if hn.Int64() != 1234 { - t.Fatalf("Expected %d, got %d for test[%d]", 1234, hn.Int64(), i) - } - } -} - -func TestHexNumberMarshalJSON(t *testing.T) { - hn := NewHexNumber(1234567890) - got, err := json.Marshal(hn) - if err != nil { - t.Fatalf("Unable to marshal hex number - %s", err) - } - - exp := []byte(`"0x499602d2"`) - if bytes.Compare(exp, got) != 0 { - t.Fatalf("Invalid json.Marshal, expected '%s', got '%s'", exp, got) - } -} - -var hexBytesTests = []struct{ in, out []byte }{ - {in: []byte(`"0x"`), out: []byte{}}, - {in: []byte(`"0x00"`), out: []byte{0}}, - {in: []byte(`"0x01ff"`), out: []byte{0x01, 0xFF}}, -} - -func TestHexBytes(t *testing.T) { - for i, test := range hexBytesTests { - var dec HexBytes - if err := json.Unmarshal(test.in, &dec); err != nil { - t.Fatalf("test %d: can't decode: %v", i, err) - } - enc, _ := json.Marshal(HexBytes(test.out)) - if !bytes.Equal(dec, test.out) { - t.Errorf("test %d: wrong decoded value 0x%x", i, dec) - } - if !bytes.Equal(enc, test.in) { - t.Errorf("test %d: wrong encoded value %#q", i, enc) - } - } -} diff --git a/swarm/api/api.go b/swarm/api/api.go index ad66e10219..04a5b55b85 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -140,8 +140,11 @@ func (self *Api) Put(content, contentType string) (string, error) { // to resolve path to content using dpa retrieve // it returns a section reader, mimeType, status and an error func (self *Api) Get(uri string, nameresolver bool) (reader storage.LazySectionReader, mimeType string, status int, err error) { - key, _, path, err := self.parseAndResolve(uri, nameresolver) + if err != nil { + return nil, "", 500, fmt.Errorf("can't resolve: %v", err) + } + quitC := make(chan bool) trie, err := loadManifest(self.dpa, key, quitC) if err != nil { @@ -166,6 +169,10 @@ func (self *Api) Get(uri string, nameresolver bool) (reader storage.LazySectionR func (self *Api) Modify(uri, contentHash, contentType string, nameresolver bool) (newRootHash string, err error) { root, _, path, err := self.parseAndResolve(uri, nameresolver) + if err != nil { + return "", fmt.Errorf("can't resolve: %v", err) + } + quitC := make(chan bool) trie, err := loadManifest(self.dpa, root, quitC) if err != nil { diff --git a/swarm/api/config.go b/swarm/api/config.go index 2fcadab2df..f4711290e6 100644 --- a/swarm/api/config.go +++ b/swarm/api/config.go @@ -69,7 +69,7 @@ func NewConfig(path string, contract common.Address, prvKey *ecdsa.PrivateKey, n var data []byte pubkey := crypto.FromECDSAPub(&prvKey.PublicKey) pubkeyhex := common.ToHex(pubkey) - keyhex := crypto.Sha3Hash(pubkey).Hex() + keyhex := crypto.Keccak256Hash(pubkey).Hex() self = &Config{ SyncParams: network.NewSyncParams(dirpath), diff --git a/swarm/api/filesystem.go b/swarm/api/filesystem.go index 04c03e2903..fdf252b65d 100644 --- a/swarm/api/filesystem.go +++ b/swarm/api/filesystem.go @@ -241,24 +241,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { } go func(i int, entry *downloadListEntry) { defer wg.Done() - f, err := os.Create(entry.path) // TODO: path separators - if err == nil { - - reader := self.api.dpa.Retrieve(entry.key) - writer := bufio.NewWriter(f) - size, err := reader.Size(quitC) - if err == nil { - _, err = io.CopyN(writer, reader, size) // TODO: handle errors - err2 := writer.Flush() - if err == nil { - err = err2 - } - err2 = f.Close() - if err == nil { - err = err2 - } - } - } + err := retrieveToFile(quitC, self.api.dpa, entry.key, entry.path) if err != nil { select { case errC <- err: @@ -279,5 +262,24 @@ func (self *FileSystem) Download(bzzpath, localpath string) error { case <-quitC: return fmt.Errorf("aborted") } - +} + +func retrieveToFile(quitC chan bool, dpa *storage.DPA, key storage.Key, path string) error { + f, err := os.Create(path) // TODO: path separators + if err != nil { + return err + } + reader := dpa.Retrieve(key) + writer := bufio.NewWriter(f) + size, err := reader.Size(quitC) + if err != nil { + return err + } + if _, err = io.CopyN(writer, reader, size); err != nil { + return err + } + if err := writer.Flush(); err != nil { + return err + } + return f.Close() } diff --git a/swarm/api/filesystem_test.go b/swarm/api/filesystem_test.go index f6657aedee..4a27cb1da6 100644 --- a/swarm/api/filesystem_test.go +++ b/swarm/api/filesystem_test.go @@ -130,6 +130,7 @@ func TestApiDirUploadModify(t *testing.T) { content = readPath(t, "testdata", "test0", "index.css") resp = testGet(t, api, bzzhash+"/index.css") exp = expResponse(content, "text/css", 0) + checkResponse(t, resp, exp) _, _, _, err = api.Get(bzzhash, true) if err == nil { diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index 449bf79131..7e090c1d17 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -24,9 +24,11 @@ import ( "io" "net/http" "regexp" + "strings" "sync" "time" + "github.com/rs/cors" "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/logger" "github.com/ubiq/go-ubiq/logger/glog" @@ -53,19 +55,37 @@ type sequentialReader struct { lock sync.Mutex } +// Server is the basic configuration needs for the HTTP server and also +// includes CORS settings. +type Server struct { + Addr string + CorsString string +} + // browser API for registering bzz url scheme handlers: // https://developer.mozilla.org/en/docs/Web-based_protocol_handlers // electron (chromium) api for registering bzz url scheme handlers: // https://github.com/atom/electron/blob/master/docs/api/protocol.md // starts up http server -func StartHttpServer(api *api.Api, port string) { +func StartHttpServer(api *api.Api, server *Server) { serveMux := http.NewServeMux() serveMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { handler(w, r, api) }) - go http.ListenAndServe(":"+port, serveMux) - glog.V(logger.Info).Infof("Swarm HTTP proxy started on localhost:%s", port) + var allowedOrigins []string + for _, domain := range strings.Split(server.CorsString, ",") { + allowedOrigins = append(allowedOrigins, strings.TrimSpace(domain)) + } + c := cors.New(cors.Options{ + AllowedOrigins: allowedOrigins, + AllowedMethods: []string{"POST", "GET", "DELETE", "PATCH", "PUT"}, + MaxAge: 600, + }) + hdlr := c.Handler(serveMux) + + go http.ListenAndServe(server.Addr, hdlr) + glog.V(logger.Info).Infof("Swarm HTTP proxy started on localhost:%s", server.Addr) } func handler(w http.ResponseWriter, r *http.Request, a *api.Api) { @@ -99,7 +119,7 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) { "[BZZ] Swarm: Protocol error in request `%s`.", uri, ) - http.Error(w, "BZZ protocol error", http.StatusBadRequest) + http.Error(w, "Invalid request URL: need access protocol (bzz:/, bzzr:/, bzzi:/) as first element in path.", http.StatusBadRequest) return } } @@ -187,6 +207,12 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) { reader := a.Retrieve(key) quitC := make(chan bool) size, err := reader.Size(quitC) + if err != nil { + glog.V(logger.Debug).Infof("Could not determine size: %v", err.Error()) + //An error on call to Size means we don't have the root chunk + http.Error(w, err.Error(), http.StatusNotFound) + return + } glog.V(logger.Debug).Infof("Reading %d bytes.", size) // setting mime type @@ -229,6 +255,12 @@ func handler(w http.ResponseWriter, r *http.Request, a *api.Api) { } quitC := make(chan bool) size, err := reader.Size(quitC) + if err != nil { + glog.V(logger.Debug).Infof("Could not determine size: %v", err.Error()) + //An error on call to Size means we don't have the root chunk + http.Error(w, err.Error(), http.StatusNotFound) + return + } glog.V(logger.Debug).Infof("Served '%s' (%d bytes) as '%s' (status code: %v)", uri, size, mimeType, status) http.ServeContent(w, r, path, forever(), reader) diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go index a42c148351..47fda005fb 100644 --- a/swarm/api/manifest.go +++ b/swarm/api/manifest.go @@ -62,6 +62,11 @@ func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dp // TODO check size for oversized manifests size, err := manifestReader.Size(quitC) + if err != nil { // size == 0 + // can't determine size means we don't have the root chunk + err = fmt.Errorf("Manifest not Found") + return + } manifestData := make([]byte, size) read, err := manifestReader.Read(manifestData) if int64(read) < size { diff --git a/swarm/network/kademlia/kademlia_test.go b/swarm/network/kademlia/kademlia_test.go index 66edfe6544..417ccecae6 100644 --- a/swarm/network/kademlia/kademlia_test.go +++ b/swarm/network/kademlia/kademlia_test.go @@ -58,9 +58,9 @@ func (n *testNode) LastActive() time.Time { } func TestOn(t *testing.T) { - addr, ok := gen(Address{}, quickrand).(Address) - other, ok := gen(Address{}, quickrand).(Address) - if !ok { + addr, ok1 := gen(Address{}, quickrand).(Address) + other, ok2 := gen(Address{}, quickrand).(Address) + if !ok1 || !ok2 { t.Errorf("oops") } kad := New(addr, NewKadParams()) diff --git a/swarm/network/protocol.go b/swarm/network/protocol.go index 42b9d27097..b90fbf6908 100644 --- a/swarm/network/protocol.go +++ b/swarm/network/protocol.go @@ -51,7 +51,7 @@ const ( Version = 0 ProtocolLength = uint64(8) ProtocolMaxMsgSize = 10 * 1024 * 1024 - NetworkId = 322 + NetworkId = 3 ) const ( @@ -538,13 +538,6 @@ func (self *bzz) protoError(code int, format string, params ...interface{}) (err return } -func (self *bzz) protoErrorDisconnect(err *errs.Error) { - err.Log(glog.V(logger.Info)) - if err.Fatal() { - self.peer.Disconnect(p2p.DiscSubprotocolError) - } -} - func (self *bzz) send(msg uint64, data interface{}) error { if self.hive.blockWrite { return fmt.Errorf("network write blocked") diff --git a/swarm/network/syncdb_test.go b/swarm/network/syncdb_test.go index 37db1d95f0..3b74065466 100644 --- a/swarm/network/syncdb_test.go +++ b/swarm/network/syncdb_test.go @@ -63,7 +63,7 @@ func newTestSyncDb(priority, bufferSize, batchSize int, dbdir string, t *testing dbdir: dbdir, t: t, } - h := crypto.Sha3Hash([]byte{0}) + h := crypto.Keccak256Hash([]byte{0}) key := storage.Key(h[:]) self.syncDb = newSyncDb(db, key, uint(priority), uint(bufferSize), uint(batchSize), self.deliver) // kick off db iterator right away, if no items on db this will allow @@ -79,7 +79,7 @@ func (self *testSyncDb) close() { func (self *testSyncDb) push(n int) { for i := 0; i < n; i++ { - self.buffer <- storage.Key(crypto.Sha3([]byte{byte(self.c)})) + self.buffer <- storage.Key(crypto.Keccak256([]byte{byte(self.c)})) self.sent = append(self.sent, self.c) self.c++ } @@ -126,7 +126,7 @@ func (self *testSyncDb) expect(n int, db bool) { if self.at+1 > len(self.delivered) { self.t.Fatalf("expected %v, got %v", self.at+1, len(self.delivered)) } - if len(self.sent) > self.at && !bytes.Equal(crypto.Sha3([]byte{byte(self.sent[self.at])}), self.delivered[self.at]) { + if len(self.sent) > self.at && !bytes.Equal(crypto.Keccak256([]byte{byte(self.sent[self.at])}), self.delivered[self.at]) { self.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db) glog.V(logger.Debug).Infof("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db) } @@ -195,7 +195,7 @@ func TestSaveSyncDb(t *testing.T) { go s.dbRead(false, 0, s.deliver) s.expect(amount, true) for i, key := range s.delivered { - expKey := crypto.Sha3([]byte{byte(i)}) + expKey := crypto.Keccak256([]byte{byte(i)}) if !bytes.Equal(key, expKey) { t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) } @@ -204,7 +204,7 @@ func TestSaveSyncDb(t *testing.T) { s.expect(amount, false) for i := amount; i < 2*amount; i++ { key := s.delivered[i] - expKey := crypto.Sha3([]byte{byte(i - amount)}) + expKey := crypto.Keccak256([]byte{byte(i - amount)}) if !bytes.Equal(key, expKey) { t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) } diff --git a/swarm/storage/chunker.go b/swarm/storage/chunker.go index c0f950de5c..d55875369d 100644 --- a/swarm/storage/chunker.go +++ b/swarm/storage/chunker.go @@ -483,8 +483,11 @@ func (s *LazyChunkReader) Seek(offset int64, whence int) (int64, error) { case 1: offset += s.off case 2: - if s.chunk == nil { - return 0, fmt.Errorf("seek from the end requires rootchunk for size. call Size first") + if s.chunk == nil { //seek from the end requires rootchunk for size. call Size first + _, err := s.Size(nil) + if err != nil { + return 0, fmt.Errorf("can't get size: %v", err) + } } offset += s.chunk.Size } diff --git a/swarm/storage/common_test.go b/swarm/storage/common_test.go index d377f96aed..d3c52022bd 100644 --- a/swarm/storage/common_test.go +++ b/swarm/storage/common_test.go @@ -80,7 +80,7 @@ func testStore(m ChunkStore, l int64, branches int64, t *testing.T) { Hash: defaultHash, }) swg := &sync.WaitGroup{} - key, err := chunker.Split(rand.Reader, l, chunkC, swg, nil) + key, _ := chunker.Split(rand.Reader, l, chunkC, swg, nil) swg.Wait() close(chunkC) chunkC = make(chan *Chunk) diff --git a/swarm/storage/dbstore.go b/swarm/storage/dbstore.go index 12b48a0355..cd9a5aff89 100644 --- a/swarm/storage/dbstore.go +++ b/swarm/storage/dbstore.go @@ -354,7 +354,7 @@ func (s *DbStore) Get(key Key) (chunk *Chunk, err error) { hasher := s.hashfunc() hasher.Write(data) hash := hasher.Sum(nil) - if bytes.Compare(hash, key) != 0 { + if !bytes.Equal(hash, key) { s.db.Delete(getDataKey(index.Idx)) err = fmt.Errorf("invalid chunk. hash=%x, key=%v", hash, key[:]) return diff --git a/swarm/storage/dbstore_test.go b/swarm/storage/dbstore_test.go index 841e63200b..0d0a4185b7 100644 --- a/swarm/storage/dbstore_test.go +++ b/swarm/storage/dbstore_test.go @@ -144,7 +144,7 @@ func TestDbStoreSyncIterator(t *testing.T) { t.Fatalf("unexpected error creating NewSyncIterator") } - it, err = m.NewSyncIterator(DbSyncState{ + it, _ = m.NewSyncIterator(DbSyncState{ Start: Key(common.Hex2Bytes("1000000000000000000000000000000000000000000000000000000000000000")), Stop: Key(common.Hex2Bytes("4000000000000000000000000000000000000000000000000000000000000000")), First: 2, @@ -168,7 +168,7 @@ func TestDbStoreSyncIterator(t *testing.T) { t.Fatalf("Expected %v chunk, got %v", keys[3], res[1]) } - it, err = m.NewSyncIterator(DbSyncState{ + it, _ = m.NewSyncIterator(DbSyncState{ Start: Key(common.Hex2Bytes("2000000000000000000000000000000000000000000000000000000000000000")), Stop: Key(common.Hex2Bytes("4000000000000000000000000000000000000000000000000000000000000000")), First: 2, diff --git a/swarm/storage/dpa_test.go b/swarm/storage/dpa_test.go index 1cde1c00e7..a23b9efebe 100644 --- a/swarm/storage/dpa_test.go +++ b/swarm/storage/dpa_test.go @@ -67,7 +67,7 @@ func TestDPArandom(t *testing.T) { ioutil.WriteFile("/tmp/result.bzz.16M", resultSlice, 0666) localStore.memStore = NewMemStore(dbStore, defaultCacheCapacity) resultReader = dpa.Retrieve(key) - for i, _ := range resultSlice { + for i := range resultSlice { resultSlice[i] = 0 } n, err = resultReader.ReadAt(resultSlice, 0) @@ -120,15 +120,14 @@ func TestDPA_capacity(t *testing.T) { // check whether it is, indeed, empty dpa.ChunkStore = memStore resultReader = dpa.Retrieve(key) - n, err = resultReader.ReadAt(resultSlice, 0) - if err == nil { + if _, err = resultReader.ReadAt(resultSlice, 0); err == nil { t.Errorf("Was able to read %d bytes from an empty memStore.", len(slice)) } // check how it works with localStore dpa.ChunkStore = localStore // localStore.dbStore.setCapacity(0) resultReader = dpa.Retrieve(key) - for i, _ := range resultSlice { + for i := range resultSlice { resultSlice[i] = 0 } n, err = resultReader.ReadAt(resultSlice, 0) diff --git a/swarm/storage/netstore.go b/swarm/storage/netstore.go index 4af08a9dc4..1291b755ac 100644 --- a/swarm/storage/netstore.go +++ b/swarm/storage/netstore.go @@ -99,7 +99,7 @@ func (self *NetStore) Put(entry *Chunk) { // handle deliveries if entry.Req != nil { glog.V(logger.Detail).Infof("NetStore.Put: localStore.Put %v hit existing request...delivering", entry.Key.Log()) - // closing C singals to other routines (local requests) + // closing C signals to other routines (local requests) // that the chunk is has been retrieved close(entry.Req.C) // deliver the chunk to requesters upstream diff --git a/swarm/storage/types.go b/swarm/storage/types.go index 177f66f315..7be6ec0fef 100644 --- a/swarm/storage/types.go +++ b/swarm/storage/types.go @@ -41,7 +41,7 @@ func (x Key) Size() uint { } func (x Key) isEqual(y Key) bool { - return bytes.Compare(x, y) == 0 + return bytes.Equal(x, y) } func (h Key) bits(i, j uint) uint { @@ -177,7 +177,7 @@ It relies on the underlying chunking model. When calling Split, the caller provides a channel (chan *Chunk) on which it receives chunks to store. The DPA delegates to storage layers (implementing ChunkStore interface). Split returns an error channel, which the caller can monitor. -After getting notified that all the data has been split (the error channel is closed), the caller can safely read or save the root key. Optionally it times out if not all chunks get stored or not the entire stream of data has been processed. By inspecting the errc channel the caller can check if any explicit errors (typically IO read/write failures) occured during splitting. +After getting notified that all the data has been split (the error channel is closed), the caller can safely read or save the root key. Optionally it times out if not all chunks get stored or not the entire stream of data has been processed. By inspecting the errc channel the caller can check if any explicit errors (typically IO read/write failures) occurred during splitting. When calling Join with a root key, the caller gets returned a seekable lazy reader. The caller again provides a channel on which the caller receives placeholder chunks with missing data. The DPA is supposed to forward this to the chunk stores and notify the chunker if the data has been delivered (i.e. retrieved from memory cache, disk-persisted db or cloud based swarm delivery). As the seekable reader is used, the chunker then puts these together the relevant parts on demand. */ diff --git a/swarm/swarm.go b/swarm/swarm.go index 15423e1cf2..603fb1d8f7 100644 --- a/swarm/swarm.go +++ b/swarm/swarm.go @@ -52,6 +52,7 @@ type Swarm struct { hive *network.Hive // the logistic manager backend chequebook.Backend // simple blockchain Backend privateKey *ecdsa.PrivateKey + corsString string swapEnabled bool } @@ -71,7 +72,7 @@ func (self *Swarm) API() *SwarmAPI { // creates a new swarm service instance // implements node.Service -func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config, swapEnabled, syncEnabled bool) (self *Swarm, err error) { +func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config, swapEnabled, syncEnabled bool, cors string) (self *Swarm, err error) { if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) { return nil, fmt.Errorf("empty public key") } @@ -84,6 +85,7 @@ func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api. swapEnabled: swapEnabled, backend: backend, privateKey: config.Swap.PrivateKey(), + corsString: cors, } glog.V(logger.Debug).Infof("Setting up Swarm service components") @@ -188,10 +190,16 @@ func (self *Swarm) Start(net *p2p.Server) error { // start swarm http proxy server if self.config.Port != "" { - go httpapi.StartHttpServer(self.api, self.config.Port) + addr := ":" + self.config.Port + go httpapi.StartHttpServer(self.api, &httpapi.Server{Addr: addr, CorsString: self.corsString}) } + glog.V(logger.Debug).Infof("Swarm http proxy started on port: %v", self.config.Port) + if self.corsString != "" { + glog.V(logger.Debug).Infof("Swarm http proxy started with corsdomain:", self.corsString) + } + return nil } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 2473db7113..5f5850c89d 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -552,9 +552,7 @@ func LoadBlockTests(file string) (map[string]*BlockTest, error) { // Nothing to see here, please move along... func prepInt(base int, s string) string { if base == 16 { - if strings.HasPrefix(s, "0x") { - s = s[2:] - } + s = strings.TrimPrefix(s, "0x") if len(s) == 0 { s = "00" } diff --git a/tests/files/ansible/test-files/docker-cpp/Dockerfile b/tests/files/ansible/test-files/docker-cpp/Dockerfile index a3b0e4ca6d..11c8bf5e70 100644 --- a/tests/files/ansible/test-files/docker-cpp/Dockerfile +++ b/tests/files/ansible/test-files/docker-cpp/Dockerfile @@ -10,7 +10,7 @@ RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcu RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons RUN apt-get install -qy libjsoncpp-dev libargtable2-dev -# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 ) +# NCurses based GUI (not optional though for a successful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 ) RUN apt-get install -qy libncurses5-dev # Qt-based GUI diff --git a/tests/files/ansible/test-files/docker-cppjit/Dockerfile b/tests/files/ansible/test-files/docker-cppjit/Dockerfile index 2b10727f05..6b37125559 100644 --- a/tests/files/ansible/test-files/docker-cppjit/Dockerfile +++ b/tests/files/ansible/test-files/docker-cppjit/Dockerfile @@ -10,7 +10,7 @@ RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcu RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons RUN apt-get install -qy libjsoncpp-dev libargtable2-dev -# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 ) +# NCurses based GUI (not optional though for a successful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 ) RUN apt-get install -qy libncurses5-dev # Qt-based GUI diff --git a/tests/init.go b/tests/init.go index 361be5f62d..7b0924bc38 100644 --- a/tests/init.go +++ b/tests/init.go @@ -87,11 +87,7 @@ func readJsonHttp(uri string, value interface{}) error { } defer resp.Body.Close() - err = readJson(resp.Body, value) - if err != nil { - return err - } - return nil + return readJson(resp.Body, value) } func readJsonFile(fn string, value interface{}) error { diff --git a/tests/state_test.go b/tests/state_test.go index 5dfd1cbe78..8887571649 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -237,6 +237,7 @@ func TestWallet(t *testing.T) { } func TestStateTestsRandom(t *testing.T) { + t.Skip() chainConfig := ¶ms.ChainConfig{ HomesteadBlock: big.NewInt(1150000), } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 649e663a96..fce0ad58e6 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -18,7 +18,6 @@ package tests import ( "bytes" - "encoding/hex" "fmt" "io" "math/big" @@ -30,8 +29,6 @@ import ( "github.com/ubiq/go-ubiq/core" "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/crypto" "github.com/ubiq/go-ubiq/ethdb" "github.com/ubiq/go-ubiq/logger/glog" "github.com/ubiq/go-ubiq/params" @@ -111,7 +108,7 @@ func runStateTests(chainConfig *params.ChainConfig, tests map[string]VmTest, ski } for name, test := range tests { - if skipTest[name] /*|| name != "EXP_Empty"*/ { + if skipTest[name] { glog.Infoln("Skipping state test", name) continue } @@ -149,7 +146,7 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error { ret []byte // gas *big.Int // err error - logs vm.Logs + logs []*types.Log ) ret, logs, _, _ = RunState(chainConfig, statedb, env, test.Transaction) @@ -162,7 +159,7 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error { } else { rexp = common.FromHex(test.Out) } - if bytes.Compare(rexp, ret) != 0 { + if !bytes.Equal(rexp, ret) { return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret) } @@ -206,40 +203,20 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error { return nil } -func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Logs, *big.Int, error) { - var ( - data = common.FromHex(tx["data"]) - gas = common.Big(tx["gasLimit"]) - price = common.Big(tx["gasPrice"]) - value = common.Big(tx["value"]) - nonce = common.Big(tx["nonce"]).Uint64() - ) - - var to *common.Address - if len(tx["to"]) > 2 { - t := common.HexToAddress(tx["to"]) - to = &t - } - // Set pre compiled contracts - vm.Precompiled = vm.PrecompiledContracts() +func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, []*types.Log, *big.Int, error) { + environment, msg := NewEVMEnvironment(false, chainConfig, statedb, env, tx) gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"])) - key, _ := hex.DecodeString(tx["secretKey"]) - addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey) - message := types.NewMessage(addr, to, nonce, value, gas, price, data, true) - vmenv := NewEnvFromMap(chainConfig, statedb, env, tx) - vmenv.origin = addr - root, _ := statedb.Commit(false) statedb.Reset(root) snapshot := statedb.Snapshot() - ret, _, err := core.ApplyMessage(vmenv, message, gaspool) + ret, gasUsed, err := core.ApplyMessage(environment, msg, gaspool) if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) { statedb.RevertToSnapshot(snapshot) } - statedb.Commit(chainConfig.IsEIP158(vmenv.BlockNumber())) + statedb.Commit(chainConfig.IsEIP158(environment.Context.BlockNumber)) - return ret, vmenv.state.Logs(), vmenv.Gas, err + return ret, statedb.Logs(), gasUsed, err } diff --git a/tests/util.go b/tests/util.go index 855fd22060..ee5116388d 100644 --- a/tests/util.go +++ b/tests/util.go @@ -18,6 +18,7 @@ package tests import ( "bytes" + "encoding/hex" "fmt" "math/big" "os" @@ -46,7 +47,7 @@ func init() { } } -func checkLogs(tlog []Log, logs vm.Logs) error { +func checkLogs(tlog []Log, logs []*types.Log) error { if len(tlog) != len(logs) { return fmt.Errorf("log length mismatch. Expected %d, got %d", len(tlog), len(logs)) @@ -69,7 +70,7 @@ func checkLogs(tlog []Log, logs vm.Logs) error { } } } - genBloom := common.LeftPadBytes(types.LogsBloom(vm.Logs{logs[i]}).Bytes(), 256) + genBloom := common.LeftPadBytes(types.LogsBloom([]*types.Log{logs[i]}).Bytes(), 256) if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) { return fmt.Errorf("bloom mismatch") @@ -148,137 +149,63 @@ type VmTest struct { PostStateRoot string } -type Env struct { - chainConfig *params.ChainConfig - depth int - state *state.StateDB - skipTransfer bool - initial bool - Gas *big.Int +func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *state.StateDB, envValues map[string]string, tx map[string]string) (*vm.EVM, core.Message) { + var ( + data = common.FromHex(tx["data"]) + gas = common.Big(tx["gasLimit"]) + price = common.Big(tx["gasPrice"]) + value = common.Big(tx["value"]) + nonce = common.Big(tx["nonce"]).Uint64() + ) - origin common.Address - parent common.Hash - coinbase common.Address - - number *big.Int - time *big.Int - difficulty *big.Int - gasLimit *big.Int - - vmTest bool - - evm *vm.EVM -} - -func NewEnv(chainConfig *params.ChainConfig, state *state.StateDB) *Env { - env := &Env{ - chainConfig: chainConfig, - state: state, + origin := common.HexToAddress(tx["caller"]) + if len(tx["secretKey"]) > 0 { + key, _ := hex.DecodeString(tx["secretKey"]) + origin = crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey) } - return env -} -func NewEnvFromMap(chainConfig *params.ChainConfig, state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env { - env := NewEnv(chainConfig, state) + var to *common.Address + if len(tx["to"]) > 2 { + t := common.HexToAddress(tx["to"]) + to = &t + } - env.origin = common.HexToAddress(exeValues["caller"]) - env.parent = common.HexToHash(envValues["previousHash"]) - env.coinbase = common.HexToAddress(envValues["currentCoinbase"]) - env.number = common.Big(envValues["currentNumber"]) - env.time = common.Big(envValues["currentTimestamp"]) - env.difficulty = common.Big(envValues["currentDifficulty"]) - env.gasLimit = common.Big(envValues["currentGasLimit"]) - env.Gas = new(big.Int) + msg := types.NewMessage(origin, to, nonce, value, gas, price, data, true) - env.evm = vm.New(env, vm.Config{ - EnableJit: EnableJit, - ForceJit: ForceJit, - }) - - return env -} - -func (self *Env) ChainConfig() *params.ChainConfig { return self.chainConfig } -func (self *Env) Vm() vm.Vm { return self.evm } -func (self *Env) Origin() common.Address { return self.origin } -func (self *Env) BlockNumber() *big.Int { return self.number } -func (self *Env) Coinbase() common.Address { return self.coinbase } -func (self *Env) Time() *big.Int { return self.time } -func (self *Env) Difficulty() *big.Int { return self.difficulty } -func (self *Env) Db() vm.Database { return self.state } -func (self *Env) GasLimit() *big.Int { return self.gasLimit } -func (self *Env) VmType() vm.Type { return vm.StdVmTy } -func (self *Env) GetHash(n uint64) common.Hash { - return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) -} -func (self *Env) AddLog(log *vm.Log) { - self.state.AddLog(log) -} -func (self *Env) Depth() int { return self.depth } -func (self *Env) SetDepth(i int) { self.depth = i } -func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool { - if self.skipTransfer { - if self.initial { - self.initial = false - return true + initialCall := true + canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool { + if vmTest { + if initialCall { + initialCall = false + return true + } } + return core.CanTransfer(db, address, amount) + } + transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { + if vmTest { + return + } + core.Transfer(db, sender, recipient, amount) } - return self.state.GetBalance(from).Cmp(balance) >= 0 -} -func (self *Env) SnapshotDatabase() int { - return self.state.Snapshot() -} -func (self *Env) RevertToSnapshot(snapshot int) { - self.state.RevertToSnapshot(snapshot) -} + context := vm.Context{ + CanTransfer: canTransfer, + Transfer: transfer, + GetHash: func(n uint64) common.Hash { + return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) + }, -func (self *Env) Transfer(from, to vm.Account, amount *big.Int) { - if self.skipTransfer { - return + Origin: origin, + Coinbase: common.HexToAddress(envValues["currentCoinbase"]), + BlockNumber: common.Big(envValues["currentNumber"]), + Time: common.Big(envValues["currentTimestamp"]), + GasLimit: common.Big(envValues["currentGasLimit"]), + Difficulty: common.Big(envValues["currentDifficulty"]), + GasPrice: price, } - core.Transfer(from, to, amount) -} - -func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - if self.vmTest && self.depth > 0 { - caller.ReturnGas(gas, price) - - return nil, nil - } - ret, err := core.Call(self, caller, addr, data, gas, price, value) - self.Gas = gas - - return ret, err - -} -func (self *Env) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { - if self.vmTest && self.depth > 0 { - caller.ReturnGas(gas, price) - - return nil, nil - } - return core.CallCode(self, caller, addr, data, gas, price, value) -} - -func (self *Env) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { - if self.vmTest && self.depth > 0 { - caller.ReturnGas(gas, price) - - return nil, nil - } - return core.DelegateCall(self, caller, addr, data, gas, price) -} - -func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { - if self.vmTest { - caller.ReturnGas(gas, price) - - nonce := self.state.GetNonce(caller.Address()) - obj := self.state.GetOrNewStateObject(crypto.CreateAddress(caller.Address(), nonce)) - - return nil, obj.Address(), nil - } else { - return core.Create(self, caller, data, gas, price, value) + if context.GasPrice == nil { + context.GasPrice = new(big.Int) } + return vm.NewEVM(context, statedb, chainConfig, vm.Config{NoRecursion: vmTest}), msg } diff --git a/tests/vm_test.go b/tests/vm_test.go index 34beb85e5f..b546007fb9 100644 --- a/tests/vm_test.go +++ b/tests/vm_test.go @@ -37,63 +37,63 @@ func BenchmarkVmFibonacci16Tests(b *testing.B) { } // I've created a new function for each tests so it's easier to identify where the problem lies if any of them fail. -func TestVMArithmetic(t *testing.T) { +func TestVmVMArithmetic(t *testing.T) { fn := filepath.Join(vmTestDir, "vmArithmeticTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestBitwiseLogicOperation(t *testing.T) { +func TestVmBitwiseLogicOperation(t *testing.T) { fn := filepath.Join(vmTestDir, "vmBitwiseLogicOperationTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestBlockInfo(t *testing.T) { +func TestVmBlockInfo(t *testing.T) { fn := filepath.Join(vmTestDir, "vmBlockInfoTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestEnvironmentalInfo(t *testing.T) { +func TestVmEnvironmentalInfo(t *testing.T) { fn := filepath.Join(vmTestDir, "vmEnvironmentalInfoTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestFlowOperation(t *testing.T) { +func TestVmFlowOperation(t *testing.T) { fn := filepath.Join(vmTestDir, "vmIOandFlowOperationsTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestLogTest(t *testing.T) { +func TestVmLogTest(t *testing.T) { fn := filepath.Join(vmTestDir, "vmLogTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestPerformance(t *testing.T) { +func TestVmPerformance(t *testing.T) { fn := filepath.Join(vmTestDir, "vmPerformanceTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestPushDupSwap(t *testing.T) { +func TestVmPushDupSwap(t *testing.T) { fn := filepath.Join(vmTestDir, "vmPushDupSwapTest.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestVMSha3(t *testing.T) { +func TestVmVMSha3(t *testing.T) { fn := filepath.Join(vmTestDir, "vmSha3Test.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) @@ -114,21 +114,21 @@ func TestVmLog(t *testing.T) { } } -func TestInputLimits(t *testing.T) { +func TestVmInputLimits(t *testing.T) { fn := filepath.Join(vmTestDir, "vmInputLimits.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestInputLimitsLight(t *testing.T) { +func TestVmInputLimitsLight(t *testing.T) { fn := filepath.Join(vmTestDir, "vmInputLimitsLight.json") if err := RunVmTest(fn, VmSkipTests); err != nil { t.Error(err) } } -func TestVMRandom(t *testing.T) { +func TestVmVMRandom(t *testing.T) { fns, _ := filepath.Glob(filepath.Join(baseDir, "RandomTests", "*")) for _, fn := range fns { if err := RunVmTest(fn, VmSkipTests); err != nil { diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index ca3aca58e9..d4d1b6828e 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -26,6 +26,7 @@ import ( "github.com/ubiq/go-ubiq/common" "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/ethdb" "github.com/ubiq/go-ubiq/logger/glog" @@ -128,9 +129,9 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error { } for name, test := range tests { - if skipTest[name] { + if skipTest[name] /*|| name != "loop_stacklimit_1021"*/ { glog.Infoln("Skipping VM test", name) - return nil + continue } if err := runVmTest(test); err != nil { @@ -164,20 +165,20 @@ func runVmTest(test VmTest) error { ret []byte gas *big.Int err error - logs vm.Logs + logs []*types.Log ) ret, logs, gas, err = RunVm(statedb, env, test.Exec) // Compare expected and actual return rexp := common.FromHex(test.Out) - if bytes.Compare(rexp, ret) != 0 { + if !bytes.Equal(rexp, ret) { return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret) } // Check gas usage if len(test.Gas) == 0 && err == nil { - return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successfull") + return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful") } else { gexp := common.Big(test.Gas) if gexp.Cmp(gas) != 0 { @@ -211,28 +212,23 @@ func runVmTest(test VmTest) error { return nil } -func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs, *big.Int, error) { +func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*types.Log, *big.Int, error) { + chainConfig := ¶ms.ChainConfig{ + HomesteadBlock: params.MainNetHomesteadBlock, + DAOForkBlock: params.MainNetDAOForkBlock, + DAOForkSupport: true, + } var ( to = common.HexToAddress(exec["address"]) from = common.HexToAddress(exec["caller"]) data = common.FromHex(exec["data"]) gas = common.Big(exec["gas"]) - price = common.Big(exec["gasPrice"]) value = common.Big(exec["value"]) ) - // Reset the pre-compiled contracts for VM tests. - vm.Precompiled = make(map[string]*vm.PrecompiledAccount) + caller := statedb.GetOrNewStateObject(from) + vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract) - caller := state.GetOrNewStateObject(from) - - chainConfig := ¶ms.ChainConfig{ - HomesteadBlock: params.MainNetHomesteadBlock, - } - vmenv := NewEnvFromMap(chainConfig, state, env, exec) - vmenv.vmTest = true - vmenv.skipTransfer = true - vmenv.initial = true - ret, err := vmenv.Call(caller, to, data, gas, price, value) - - return ret, vmenv.state.Logs(), vmenv.Gas, err + environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec) + ret, err := environment.Call(caller, to, data, gas, value) + return ret, statedb.Logs(), gas, err } diff --git a/trie/encoding.go b/trie/encoding.go index 761bad1889..2037118ddf 100644 --- a/trie/encoding.go +++ b/trie/encoding.go @@ -80,7 +80,7 @@ func compactHexEncode(nibbles []byte) []byte { } l := (nl + 1) / 2 var str = make([]byte, l) - for i, _ := range str { + for i := range str { b := nibbles[i*2] * 16 if nl > i*2 { b += nibbles[i*2+1] diff --git a/trie/hasher.go b/trie/hasher.go index 32ffe805f0..9131839aa2 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -52,7 +52,7 @@ func returnHasherToPool(h *hasher) { // hash collapses a node down into a hash node, also returning a copy of the // original node initialzied with the computed hash to replace the original one. func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) { - // If we're not storing the node, just hashing, use avaialble cached data + // If we're not storing the node, just hashing, use available cached data if hash, dirty := n.cache(); hash != nil { if db == nil { return hash, n, nil diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 6c27f21af8..84a7d3486e 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -105,7 +105,7 @@ func TestNodeIteratorCoverage(t *testing.T) { } } // Cross check the hashes and the database itself - for hash, _ := range hashes { + for hash := range hashes { if _, err := db.Get(hash.Bytes()); err != nil { t.Errorf("failed to retrieve reported node %x: %v", hash, err) } diff --git a/trie/sync.go b/trie/sync.go index d46202204d..01dec0be7c 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -21,7 +21,6 @@ import ( "fmt" "github.com/ubiq/go-ubiq/common" - "github.com/ubiq/go-ubiq/ethdb" "gopkg.in/karalabe/cookiejar.v2/collections/prque" ) @@ -58,13 +57,13 @@ type TrieSyncLeafCallback func(leaf []byte, parent common.Hash) error // unknown trie hashes to retrieve, accepts node data associated with said hashes // and reconstructs the trie step by step until all is done. type TrieSync struct { - database ethdb.Database // State database for storing all the assembled node data + database DatabaseReader requests map[common.Hash]*request // Pending requests pertaining to a key hash queue *prque.Prque // Priority queue with the pending requests } // NewTrieSync creates a new trie data download scheduler. -func NewTrieSync(root common.Hash, database ethdb.Database, callback TrieSyncLeafCallback) *TrieSync { +func NewTrieSync(root common.Hash, database DatabaseReader, callback TrieSyncLeafCallback) *TrieSync { ts := &TrieSync{ database: database, requests: make(map[common.Hash]*request), @@ -145,7 +144,7 @@ func (s *TrieSync) Missing(max int) []common.Hash { // Process injects a batch of retrieved trie nodes data, returning if something // was committed to the database and also the index of an entry if processing of // it failed. -func (s *TrieSync) Process(results []SyncResult) (bool, int, error) { +func (s *TrieSync) Process(results []SyncResult, dbw DatabaseWriter) (bool, int, error) { committed := false for i, item := range results { @@ -157,7 +156,7 @@ func (s *TrieSync) Process(results []SyncResult) (bool, int, error) { // If the item is a raw entry request, commit directly if request.raw { request.data = item.Data - s.commit(request, nil) + s.commit(request, dbw) committed = true continue } @@ -174,7 +173,7 @@ func (s *TrieSync) Process(results []SyncResult) (bool, int, error) { return committed, i, err } if len(requests) == 0 && request.deps == 0 { - s.commit(request, nil) + s.commit(request, dbw) committed = true continue } @@ -266,16 +265,9 @@ func (s *TrieSync) children(req *request, object node) ([]*request, error) { // commit finalizes a retrieval request and stores it into the database. If any // of the referencing parent requests complete due to this commit, they are also // committed themselves. -func (s *TrieSync) commit(req *request, batch ethdb.Batch) (err error) { - // Create a new batch if none was specified - if batch == nil { - batch = s.database.NewBatch() - defer func() { - err = batch.Write() - }() - } +func (s *TrieSync) commit(req *request, dbw DatabaseWriter) (err error) { // Write the node content to disk - if err := batch.Put(req.hash[:], req.data); err != nil { + if err := dbw.Put(req.hash[:], req.data); err != nil { return err } delete(s.requests, req.hash) @@ -284,7 +276,7 @@ func (s *TrieSync) commit(req *request, batch ethdb.Batch) (err error) { for _, parent := range req.parents { parent.deps-- if parent.deps == 0 { - if err := s.commit(parent, batch); err != nil { + if err := s.commit(parent, dbw); err != nil { return err } } diff --git a/trie/sync_test.go b/trie/sync_test.go index 5391210e79..6d7378e6eb 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -67,7 +67,7 @@ func checkTrieContents(t *testing.T, db Database, root []byte, content map[strin t.Fatalf("inconsistent trie at %x: %v", root, err) } for key, val := range content { - if have := trie.Get([]byte(key)); bytes.Compare(have, val) != 0 { + if have := trie.Get([]byte(key)); !bytes.Equal(have, val) { t.Errorf("entry %x: content mismatch: have %x, want %x", key, have, val) } } @@ -122,7 +122,7 @@ func testIterativeTrieSync(t *testing.T, batch int) { } results[i] = SyncResult{hash, data} } - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } queue = append(queue[:0], sched.Missing(batch)...) @@ -152,7 +152,7 @@ func TestIterativeDelayedTrieSync(t *testing.T) { } results[i] = SyncResult{hash, data} } - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } queue = append(queue[len(results):], sched.Missing(10000)...) @@ -182,7 +182,7 @@ func testIterativeRandomTrieSync(t *testing.T, batch int) { for len(queue) > 0 { // Fetch all the queued nodes in a random order results := make([]SyncResult, 0, len(queue)) - for hash, _ := range queue { + for hash := range queue { data, err := srcDb.Get(hash.Bytes()) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) @@ -190,7 +190,7 @@ func testIterativeRandomTrieSync(t *testing.T, batch int) { results = append(results, SyncResult{hash, data}) } // Feed the retrieved results back and queue new tasks - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } queue = make(map[common.Hash]struct{}) @@ -219,7 +219,7 @@ func TestIterativeRandomDelayedTrieSync(t *testing.T) { for len(queue) > 0 { // Sync only half of the scheduled nodes, even those in random order results := make([]SyncResult, 0, len(queue)/2+1) - for hash, _ := range queue { + for hash := range queue { data, err := srcDb.Get(hash.Bytes()) if err != nil { t.Fatalf("failed to retrieve node data for %x: %v", hash, err) @@ -231,7 +231,7 @@ func TestIterativeRandomDelayedTrieSync(t *testing.T) { } } // Feed the retrieved results back and queue new tasks - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } for _, result := range results { @@ -272,7 +272,7 @@ func TestDuplicateAvoidanceTrieSync(t *testing.T) { results[i] = SyncResult{hash, data} } - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } queue = append(queue[:0], sched.Missing(0)...) @@ -304,7 +304,7 @@ func TestIncompleteTrieSync(t *testing.T) { results[i] = SyncResult{hash, data} } // Process each of the trie nodes - if _, index, err := sched.Process(results); err != nil { + if _, index, err := sched.Process(results, dstDb); err != nil { t.Fatalf("failed to process result #%d: %v", index, err) } for _, result := range results { diff --git a/trie/trie.go b/trie/trie.go index 638a4da054..cadc679c0e 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -60,8 +60,12 @@ func init() { // Database must be implemented by backing stores for the trie. type Database interface { + DatabaseReader DatabaseWriter - // Get returns the value for key from the database. +} + +// DatabaseReader wraps the Get method of a backing store for the trie. +type DatabaseReader interface { Get(key []byte) (value []byte, err error) } diff --git a/trie/trie_test.go b/trie/trie_test.go index 753471c0c6..f6f429361f 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -56,9 +56,11 @@ func TestEmptyTrie(t *testing.T) { func TestNull(t *testing.T) { var trie Trie key := make([]byte, 32) - value := common.FromHex("0x823140710bf13990e4500136726d8b55") + value := []byte("test") trie.Update(key, value) - value = trie.Get(key) + if !bytes.Equal(trie.Get(key), value) { + t.Fatal("wrong value") + } } func TestMissingRoot(t *testing.T) { diff --git a/vendor.conf b/vendor.conf index 8e411b0f60..0453a5ec84 100644 --- a/vendor.conf +++ b/vendor.conf @@ -3,40 +3,41 @@ github.com/ubiq/go-ubiq # import github.com/Azure/azure-sdk-for-go v5.0.0-beta-5-gbd73d95 -github.com/aristanetworks/goarista ockafka-v0.0.2-7-g306a19f +github.com/aristanetworks/goarista ockafka-v0.0.2-21-g34c98d5 github.com/cespare/cp 165db2f -github.com/davecgh/go-spew v1.0.0-9-g346938d +github.com/davecgh/go-spew v1.1.0 github.com/ethereum/ethash v23.1-249-g214d4c0 -github.com/fatih/color v1.1.0-4-gbf82308 -github.com/gizak/termui d29684e +github.com/fatih/color v1.2-2-ge8e01ee +github.com/gizak/termui v2.1.1-9-gf63e0cd github.com/golang/snappy d9eb7a3 github.com/hashicorp/golang-lru 0a025b7 -github.com/huin/goupnp 949b8a7 +github.com/huin/goupnp 679507a github.com/jackpal/go-nat-pmp v1.0.1-4-g1fa385a -github.com/mattn/go-colorable v0.0.6-7-g6e26b35 -github.com/mattn/go-isatty 66b8e73 +github.com/maruel/panicparse ad66119 +github.com/mattn/go-colorable v0.0.6-9-gd228849 +github.com/mattn/go-isatty 30a891c github.com/mattn/go-runewidth v0.0.1-10-g737072b github.com/mitchellh/go-wordwrap ad45545 -github.com/nsf/termbox-go b6acae5 -github.com/pborman/uuid v1.0-17-g3d4f2ba +github.com/nsf/termbox-go abe82ce +github.com/pborman/uuid v1.0-19-g5007efa github.com/peterh/liner 3c5f577 -github.com/rcrowley/go-metrics ab2277b +github.com/rcrowley/go-metrics 1f30fe9 github.com/rjeczalik/notify 7e20c15 github.com/robertkrimen/otto bf1c379 github.com/rs/cors v1.0 github.com/rs/xhandler v1.0-1-ged27b6f -github.com/syndtr/goleveldb 6b4daa5 -golang.org/x/crypto 9477e0b -golang.org/x/net 4bb47a1 -golang.org/x/sys c200b10 -golang.org/x/text a8b3843 -golang.org/x/tools 1529f88 -gopkg.in/check.v1 4f90aea +github.com/syndtr/goleveldb 23851d9 +golang.org/x/crypto 7c6cc32 +golang.org/x/net 60c41d1 +golang.org/x/sys d75a526 +golang.org/x/text 44f4f65 +golang.org/x/tools 116266f6 +gopkg.in/check.v1 20d25e2 gopkg.in/fatih/set.v0 v0.1.0-3-g27c4092 gopkg.in/karalabe/cookiejar.v2 8dcd6a7 gopkg.in/natefinch/npipe.v2 c1b8fa8 gopkg.in/sourcemap.v1 v1.0.3 -gopkg.in/urfave/cli.v1 v1.18.1 +gopkg.in/urfave/cli.v1 v1.19.1 # exclude -golang.org/x/net/context diff --git a/vendor/github.com/aristanetworks/goarista/.travis.yml b/vendor/github.com/aristanetworks/goarista/.travis.yml index 534f444cae..1f34efa6b2 100644 --- a/vendor/github.com/aristanetworks/goarista/.travis.yml +++ b/vendor/github.com/aristanetworks/goarista/.travis.yml @@ -1,6 +1,6 @@ language: go go: -- 1.6.2 +- 1.7.3 - tip before_install: - go get -v github.com/golang/lint/golint @@ -13,3 +13,4 @@ script: notifications: slack: secure: MO/3LqbyALbi9vAY3pZetp/LfRuKEPAYEUya7XKmTWA3OFHYkTGqJWNosVkFJd6eSKwnc3HP4jlKADEBNVxADHzcA3uMPUQi1mIcNk/Ps1WWMNDv1liE2XOoOmHSHZ/8ksk6TNq83x+d17ZffYq8KAH6iKNKvllO1JzQPgJJdf+cNXQQlg6uPSe+ggMpjqVLkKcHqA4L3/BWo6fNcyvkqaN3uXcEzYPi7Nb2q9tl0ja6ToyZV4H6SinwitZmpedN3RkBcm4fKmGyw5ikzH93ycA5SvWrnXTh1dJvq6DU0FV7iwI6oqPTbAUc3FE5g7aEkK0qVR21s2j+KNaOLnuX10ZGQFwj2r3SW2REHq4j+qqFla/2EmSFZJt3GXYS+plmGCxqCgyjSw6tTi7LaGZ/mWBJEA9/EaXG1NkwlQYx5tdUMeGj77OczjXClynpb2hJ7MM2b32Rnp0JmNaXAh01SmClo+8nDWuksAsIdPtWsbF0/XHmEJiqpu8ojvVXOQIbPt43bjG7PS1t5jaRAU/N1n56SiCGgCSGd3Ui5eX5vmgWdpZMl8NG05G4LFsgmkdphRT5fru0C2PrhNZYRDGWs63XKapBxsvfqGzdHxTtYuaDjHjrI+9w0BC/8kEzSWoPmabQ5ci4wf4DeplcIay4tDMgMSo8pGAf52vrne4rmUo= + on_success: change diff --git a/vendor/github.com/aristanetworks/goarista/Dockerfile b/vendor/github.com/aristanetworks/goarista/Dockerfile index e8a0f41793..0322e564e1 100644 --- a/vendor/github.com/aristanetworks/goarista/Dockerfile +++ b/vendor/github.com/aristanetworks/goarista/Dockerfile @@ -3,7 +3,7 @@ # that can be found in the COPYING file. # TODO: move this to cmd/ockafka (https://github.com/docker/hub-feedback/issues/292) -FROM golang:1.6 +FROM golang:1.7.3 RUN mkdir -p /go/src/github.com/aristanetworks/goarista/cmd WORKDIR /go/src/github.com/aristanetworks/goarista diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md index 6e39e919f7..7c8eea20e3 100644 --- a/vendor/github.com/fatih/color/README.md +++ b/vendor/github.com/fatih/color/README.md @@ -56,6 +56,16 @@ whiteBackground := red.Add(color.BgWhite) whiteBackground.Println("Red text with white background.") ``` +### Use your own output (io.Writer) + +```go +// Use your own io.Writer output +color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + +blue := color.New(color.FgBlue) +blue.Fprint(writer, "This will print text in blue.") +``` + ### Custom print functions (PrintFunc) ```go @@ -69,6 +79,17 @@ notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() notice("Don't forget this...") ``` +### Custom fprint functions (FprintFunc) + +```go +blue := color.New(FgBlue).FprintfFunc() +blue(myWriter, "important notice: %s", stars) + +// Mix up with multiple attributes +success := color.New(color.Bold, color.FgGreen).FprintlnFunc() +success(myWriter, don't forget this...") +``` + ### Insert into noncolor strings (SprintFunc) ```go diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index 06f4867f7f..dba8f211e4 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -2,6 +2,7 @@ package color import ( "fmt" + "io" "os" "strconv" "strings" @@ -11,11 +12,22 @@ import ( "github.com/mattn/go-isatty" ) -// NoColor defines if the output is colorized or not. It's dynamically set to -// false or true based on the stdout's file descriptor referring to a terminal -// or not. This is a global option and affects all colors. For more control -// over each color block use the methods DisableColor() individually. -var NoColor = !isatty.IsTerminal(os.Stdout.Fd()) +var ( + // NoColor defines if the output is colorized or not. It's dynamically set to + // false or true based on the stdout's file descriptor referring to a terminal + // or not. This is a global option and affects all colors. For more control + // over each color block use the methods DisableColor() individually. + NoColor = !isatty.IsTerminal(os.Stdout.Fd()) || os.Getenv("TERM") == "dumb" + + // Output defines the standard output of the print functions. By default + // os.Stdout is used. + Output = colorable.NewColorableStdout() + + // colorsCache is used to reduce the count of created Color objects and + // allows to reuse already created objects with required Attribute. + colorsCache = make(map[Attribute]*Color) + colorsCacheMu sync.Mutex // protects colorsCache +) // Color defines a custom color object which is defined by SGR parameters. type Color struct { @@ -133,6 +145,27 @@ func (c *Color) unset() { Unset() } +func (c *Color) setWriter(w io.Writer) *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(w, c.format()) + return c +} + +func (c *Color) unsetWriter(w io.Writer) { + if c.isNoColorSet() { + return + } + + if NoColor { + return + } + + fmt.Fprintf(w, "%s[%dm", escape, Reset) +} + // Add is used to chain SGR parameters. Use as many as parameters to combine // and create custom color objects. Example: Add(color.FgRed, color.Underline). func (c *Color) Add(value ...Attribute) *Color { @@ -146,9 +179,17 @@ func (c *Color) prepend(value Attribute) { c.params[0] = value } -// Output defines the standard output of the print functions. By default -// os.Stdout is used. -var Output = colorable.NewColorableStdout() +// Fprint formats using the default formats for its operands and writes to w. +// Spaces are added between operands when neither is a string. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprint(w, a...) +} // Print formats using the default formats for its operands and writes to // standard output. Spaces are added between operands when neither is a @@ -162,6 +203,17 @@ func (c *Color) Print(a ...interface{}) (n int, err error) { return fmt.Fprint(Output, a...) } +// Fprintf formats according to a format specifier and writes to w. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintf(w, format, a...) +} + // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. // This is the standard fmt.Printf() method wrapped with the given color. @@ -172,6 +224,17 @@ func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { return fmt.Fprintf(Output, format, a...) } +// Fprintln formats using the default formats for its operands and writes to w. +// Spaces are always added between operands and a newline is appended. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintln(w, a...) +} + // Println formats using the default formats for its operands and writes to // standard output. Spaces are always added between operands and a newline is // appended. It returns the number of bytes written and any write error @@ -184,27 +247,57 @@ func (c *Color) Println(a ...interface{}) (n int, err error) { return fmt.Fprintln(Output, a...) } +// FprintFunc returns a new function that prints the passed arguments as +// colorized with color.Fprint(). +func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprint(w, a...) + } +} + // PrintFunc returns a new function that prints the passed arguments as // colorized with color.Print(). func (c *Color) PrintFunc() func(a ...interface{}) { - return func(a ...interface{}) { c.Print(a...) } + return func(a ...interface{}) { + c.Print(a...) + } +} + +// FprintfFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintf(). +func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { + return func(w io.Writer, format string, a ...interface{}) { + c.Fprintf(w, format, a...) + } } // PrintfFunc returns a new function that prints the passed arguments as // colorized with color.Printf(). func (c *Color) PrintfFunc() func(format string, a ...interface{}) { - return func(format string, a ...interface{}) { c.Printf(format, a...) } + return func(format string, a ...interface{}) { + c.Printf(format, a...) + } +} + +// FprintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintln(). +func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprintln(w, a...) + } } // PrintlnFunc returns a new function that prints the passed arguments as // colorized with color.Println(). func (c *Color) PrintlnFunc() func(a ...interface{}) { - return func(a ...interface{}) { c.Println(a...) } + return func(a ...interface{}) { + c.Println(a...) + } } // SprintFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprint(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output, example: +// string. Windows users should use this in conjunction with color.Output, example: // // put := New(FgYellow).SprintFunc() // fmt.Fprintf(color.Output, "This is a %s", put("warning")) @@ -216,7 +309,7 @@ func (c *Color) SprintFunc() func(a ...interface{}) string { // SprintfFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprintf(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output. +// string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { return func(format string, a ...interface{}) string { return c.wrap(fmt.Sprintf(format, a...)) @@ -225,7 +318,7 @@ func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { // SprintlnFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprintln(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output. +// string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintlnFunc() func(a ...interface{}) string { return func(a ...interface{}) string { return c.wrap(fmt.Sprintln(a...)) @@ -268,7 +361,7 @@ func (c *Color) DisableColor() { c.noColor = boolPtr(true) } -// EnableColor enables the color output. Use it in conjuction with +// EnableColor enables the color output. Use it in conjunction with // DisableColor(). Otherwise this method has no side effects. func (c *Color) EnableColor() { c.noColor = boolPtr(false) @@ -313,12 +406,6 @@ func boolPtr(v bool) *bool { return &v } -// colorsCache is used to reduce the count of created Color objects and -// allows to reuse already created objects with required Attribute. -var colorsCache = make(map[Attribute]*Color) - -var colorsCacheMu = new(sync.Mutex) // protects colorsCache - func getCachedColor(p Attribute) *Color { colorsCacheMu.Lock() defer colorsCacheMu.Unlock() diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index 17908787c9..1e57812d7c 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -37,6 +37,11 @@ separate color object. whiteBackground := red.Add(color.BgWhite) whiteBackground.Println("Red text with White background.") + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") You can create PrintXxx functions to simplify even more: @@ -49,6 +54,15 @@ You can create PrintXxx functions to simplify even more: notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() notice("don't forget this...") +You can also FprintXxx functions to pass your own io.Writer: + + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") + Or create SprintXxx functions to mix strings with other non-colorized strings: diff --git a/vendor/github.com/gizak/termui/barchart.go b/vendor/github.com/gizak/termui/barchart.go index 9e2a10689e..1102f3416e 100644 --- a/vendor/github.com/gizak/termui/barchart.go +++ b/vendor/github.com/gizak/termui/barchart.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/block.go b/vendor/github.com/gizak/termui/block.go index 418738c8d4..43a4c4039b 100644 --- a/vendor/github.com/gizak/termui/block.go +++ b/vendor/github.com/gizak/termui/block.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/block_common.go b/vendor/github.com/gizak/termui/block_common.go index 0f972cbbdd..aa4a92a7dd 100644 --- a/vendor/github.com/gizak/termui/block_common.go +++ b/vendor/github.com/gizak/termui/block_common.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/block_windows.go b/vendor/github.com/gizak/termui/block_windows.go index 4dbc017de9..50480e55b3 100644 --- a/vendor/github.com/gizak/termui/block_windows.go +++ b/vendor/github.com/gizak/termui/block_windows.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/buffer.go b/vendor/github.com/gizak/termui/buffer.go index 60e77863a5..cbbab6f501 100644 --- a/vendor/github.com/gizak/termui/buffer.go +++ b/vendor/github.com/gizak/termui/buffer.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. @@ -46,7 +46,7 @@ func (b Buffer) Bounds() image.Rectangle { y0 = p.Y } } - return image.Rect(x0, y0, x1, y1) + return image.Rect(x0, y0, x1+1, y1+1) } // SetArea assigns a new rect area to Buffer b. @@ -56,7 +56,7 @@ func (b *Buffer) SetArea(r image.Rectangle) { } // Sync sets drawing area to the buffer's bound -func (b Buffer) Sync() { +func (b *Buffer) Sync() { b.SetArea(b.Bounds()) } diff --git a/vendor/github.com/gizak/termui/canvas.go b/vendor/github.com/gizak/termui/canvas.go index 4173780f3a..911a6787f2 100644 --- a/vendor/github.com/gizak/termui/canvas.go +++ b/vendor/github.com/gizak/termui/canvas.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/config b/vendor/github.com/gizak/termui/config deleted file mode 100755 index 18fd6a4016..0000000000 --- a/vendor/github.com/gizak/termui/config +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env perl6 - -use v6; - -my $copyright = '// Copyright 2016 Zack Guo . All rights reserved. -// Use of this source code is governed by a MIT license that can -// be found in the LICENSE file. - -'; - -sub MAIN('update-docstr', Str $srcp) { - if $srcp.IO.f { - $_ = $srcp.IO.slurp; - if m/^ \/\/\s Copyright .+? \n\n/ { - unless ~$/ eq $copyright { - s/^ \/\/\s Copyright .+? \n\n /$copyright/; - spurt $srcp, $_; - say "[updated] doc string for:"~$srcp; - } - } else { - say "[added] doc string for "~$srcp~" (no match found)"; - $_ = $copyright ~ $_; - spurt $srcp, $_; - } - } -} diff --git a/vendor/github.com/gizak/termui/config.py b/vendor/github.com/gizak/termui/config.py new file mode 100644 index 0000000000..9152bf517c --- /dev/null +++ b/vendor/github.com/gizak/termui/config.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 + +# use v6; +# +# my $copyright = '// Copyright 2016 Zack Guo . All rights reserved. +# // Use of this source code is governed by a MIT license that can +# // be found in the LICENSE file. +# +# '; +# +# sub MAIN('update-docstr', Str $srcp) { +# if $srcp.IO.f { +# $_ = $srcp.IO.slurp; +# if m/^ \/\/\s Copyright .+? \n\n/ { +# unless ~$/ eq $copyright { +# s/^ \/\/\s Copyright .+? \n\n /$copyright/; +# spurt $srcp, $_; +# say "[updated] doc string for:"~$srcp; +# } +# } else { +# say "[added] doc string for "~$srcp~" (no match found)"; +# $_ = $copyright ~ $_; +# spurt $srcp, $_; +# } +# } +# } + +import re +import os +import io + +copyright = """// Copyright 2016 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +""" + +exclude_dirs = [".git", "_docs"] +exclude_files = [] +include_dirs = [".", "debug", "extra", "test", "_example"] + + +def is_target(fpath): + if os.path.splitext(fpath)[-1] == ".go": + return True + return False + + +def update_copyright(fpath): + print("processing " + fpath) + f = io.open(fpath, 'r', encoding='utf-8') + fstr = f.read() + f.close() + + # remove old + m = re.search('^// Copyright .+?\r?\n\r?\n', fstr, re.MULTILINE|re.DOTALL) + if m: + fstr = fstr[m.end():] + + # add new + fstr = copyright + fstr + f = io.open(fpath, 'w',encoding='utf-8') + f.write(fstr) + f.close() + + +def main(): + for d in include_dirs: + files = [ + os.path.join(d, f) for f in os.listdir(d) + if os.path.isfile(os.path.join(d, f)) + ] + for f in files: + if is_target(f): + update_copyright(f) + + +if __name__ == '__main__': + main() diff --git a/vendor/github.com/gizak/termui/doc.go b/vendor/github.com/gizak/termui/doc.go index 0d7108d308..fdf7dd079a 100644 --- a/vendor/github.com/gizak/termui/doc.go +++ b/vendor/github.com/gizak/termui/doc.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/events.go b/vendor/github.com/gizak/termui/events.go index 6627f8942f..5ba5263c02 100644 --- a/vendor/github.com/gizak/termui/events.go +++ b/vendor/github.com/gizak/termui/events.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/gauge.go b/vendor/github.com/gizak/termui/gauge.go index 01af0ea7c3..a143111ea5 100644 --- a/vendor/github.com/gizak/termui/gauge.go +++ b/vendor/github.com/gizak/termui/gauge.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/glide.lock b/vendor/github.com/gizak/termui/glide.lock index 798e944d39..be5952d466 100644 --- a/vendor/github.com/gizak/termui/glide.lock +++ b/vendor/github.com/gizak/termui/glide.lock @@ -1,14 +1,30 @@ -hash: 67a478802ee1d122cf1df063c52458d074864900c96a5cc25dc6be4b7638eb1c -updated: 2016-04-06T21:16:00.849048757-04:00 +hash: 7a754ba100256404a978b2fc8738aee337beb822458e4b6060399fb89ebd215c +updated: 2016-11-03T17:39:24.323773674-04:00 imports: +- name: github.com/maruel/panicparse + version: ad661195ed0e88491e0f14be6613304e3b1141d6 + subpackages: + - stack - name: github.com/mattn/go-runewidth - version: d6bea18f789704b5f83375793155289da36a3c7f + version: 737072b4e32b7a5018b4a7125da8d12de90e8045 - name: github.com/mitchellh/go-wordwrap version: ad45545899c7b13c020ea92b2072220eefad42b8 - name: github.com/nsf/termbox-go - version: 362329b0aa6447eadd52edd8d660ec1dff470295 + version: b6acae516ace002cb8105a89024544a1480655a5 - name: golang.org/x/net - version: af4fee9d05b66edc24197d189e6118f8ebce8c2b + version: 569280fa63be4e201b975e5411e30a92178f0118 subpackages: - websocket -devImports: [] +testImports: +- name: github.com/davecgh/go-spew + version: 346938d642f2ec3594ed81d874461961cd0faa76 + subpackages: + - spew +- name: github.com/pmezard/go-difflib + version: d8ed2627bdf02c080bf22230dbb337003b7aba2d + subpackages: + - difflib +- name: github.com/stretchr/testify + version: 976c720a22c8eb4eb6a0b4348ad85ad12491a506 + subpackages: + - assert diff --git a/vendor/github.com/gizak/termui/glide.yaml b/vendor/github.com/gizak/termui/glide.yaml index d8e4452548..a6812317f7 100644 --- a/vendor/github.com/gizak/termui/glide.yaml +++ b/vendor/github.com/gizak/termui/glide.yaml @@ -6,3 +6,4 @@ import: - package: golang.org/x/net subpackages: - websocket +- package: github.com/maruel/panicparse diff --git a/vendor/github.com/gizak/termui/grid.go b/vendor/github.com/gizak/termui/grid.go index 364442e02e..679b825b70 100644 --- a/vendor/github.com/gizak/termui/grid.go +++ b/vendor/github.com/gizak/termui/grid.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/helper.go b/vendor/github.com/gizak/termui/helper.go index 308f6c1db0..5870bac947 100644 --- a/vendor/github.com/gizak/termui/helper.go +++ b/vendor/github.com/gizak/termui/helper.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/linechart.go b/vendor/github.com/gizak/termui/linechart.go index 81834efdbc..1886114961 100644 --- a/vendor/github.com/gizak/termui/linechart.go +++ b/vendor/github.com/gizak/termui/linechart.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/linechart_others.go b/vendor/github.com/gizak/termui/linechart_others.go index 7e2e66b3e5..fad7a80b17 100644 --- a/vendor/github.com/gizak/termui/linechart_others.go +++ b/vendor/github.com/gizak/termui/linechart_others.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/linechart_windows.go b/vendor/github.com/gizak/termui/linechart_windows.go index 1478b5ce35..9c9917ba87 100644 --- a/vendor/github.com/gizak/termui/linechart_windows.go +++ b/vendor/github.com/gizak/termui/linechart_windows.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/list.go b/vendor/github.com/gizak/termui/list.go index 0029d26228..492b62d543 100644 --- a/vendor/github.com/gizak/termui/list.go +++ b/vendor/github.com/gizak/termui/list.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/mbarchart.go b/vendor/github.com/gizak/termui/mbarchart.go index 6828e65336..fa6d54ca1d 100644 --- a/vendor/github.com/gizak/termui/mbarchart.go +++ b/vendor/github.com/gizak/termui/mbarchart.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/par.go b/vendor/github.com/gizak/termui/par.go index 78bffd0918..14d6b4d346 100644 --- a/vendor/github.com/gizak/termui/par.go +++ b/vendor/github.com/gizak/termui/par.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/pos.go b/vendor/github.com/gizak/termui/pos.go index 2046dce5a7..a0359af7c2 100644 --- a/vendor/github.com/gizak/termui/pos.go +++ b/vendor/github.com/gizak/termui/pos.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/render.go b/vendor/github.com/gizak/termui/render.go index 36544f0632..be3bf464e6 100644 --- a/vendor/github.com/gizak/termui/render.go +++ b/vendor/github.com/gizak/termui/render.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. @@ -6,9 +6,19 @@ package termui import ( "image" + "io" "sync" "time" + "fmt" + + "os" + + "runtime/debug" + + "bytes" + + "github.com/maruel/panicparse/stack" tm "github.com/nsf/termbox-go" ) @@ -89,7 +99,26 @@ func TermHeight() int { // Render renders all Bufferer in the given order from left to right, // right could overlap on left ones. func render(bs ...Bufferer) { - + defer func() { + if e := recover(); e != nil { + Close() + fmt.Fprintf(os.Stderr, "Captured a panic(value=%v) when rendering Bufferer. Exit termui and clean terminal...\nPrint stack trace:\n\n", e) + //debug.PrintStack() + gs, err := stack.ParseDump(bytes.NewReader(debug.Stack()), os.Stderr) + if err != nil { + debug.PrintStack() + os.Exit(1) + } + p := &stack.Palette{} + buckets := stack.SortBuckets(stack.Bucketize(gs, stack.AnyValue)) + srcLen, pkgLen := stack.CalcLengths(buckets, false) + for _, bucket := range buckets { + io.WriteString(os.Stdout, p.BucketHeader(&bucket, false, len(buckets) > 1)) + io.WriteString(os.Stdout, p.StackLines(&bucket.Signature, srcLen, pkgLen, false)) + } + os.Exit(1) + } + }() for _, b := range bs { buf := b.Buffer() diff --git a/vendor/github.com/gizak/termui/sparkline.go b/vendor/github.com/gizak/termui/sparkline.go index 312ad9563d..e127b52e13 100644 --- a/vendor/github.com/gizak/termui/sparkline.go +++ b/vendor/github.com/gizak/termui/sparkline.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/table.go b/vendor/github.com/gizak/termui/table.go new file mode 100644 index 0000000000..319b897014 --- /dev/null +++ b/vendor/github.com/gizak/termui/table.go @@ -0,0 +1,170 @@ +package termui + +import "strings" + +/* + table := termui.NewTable() + table.Rows = rows + table.FgColor = termui.ColorWhite + table.BgColor = termui.ColorDefault + table.Height = 7 + table.Width = 62 + table.Y = 0 + table.X = 0 + table.Border = true +*/ + +type Table struct { + Block + Rows [][]string + CellWidth []int + FgColor Attribute + BgColor Attribute + FgColors []Attribute + BgColors []Attribute + Seperator bool + TextAlign Align +} + +func NewTable() *Table { + table := &Table{Block: *NewBlock()} + table.FgColor = ColorWhite + table.BgColor = ColorDefault + table.Seperator = true + return table +} + +func (table *Table) Analysis() { + length := len(table.Rows) + if length < 1 { + return + } + + if len(table.FgColors) == 0 { + table.FgColors = make([]Attribute, len(table.Rows)) + } + if len(table.BgColors) == 0 { + table.BgColors = make([]Attribute, len(table.Rows)) + } + + row_width := len(table.Rows[0]) + cellWidthes := make([]int, row_width) + + for index, row := range table.Rows { + for i, str := range row { + if cellWidthes[i] < len(str) { + cellWidthes[i] = len(str) + } + } + + if table.FgColors[index] == 0 { + table.FgColors[index] = table.FgColor + } + + if table.BgColors[index] == 0 { + table.BgColors[index] = table.BgColor + } + } + + table.CellWidth = cellWidthes + + //width_sum := 2 + //for i, width := range cellWidthes { + // width_sum += (width + 2) + // for u, row := range table.Rows { + // switch table.TextAlign { + // case "right": + // row[i] = fmt.Sprintf(" %*s ", width, table.Rows[u][i]) + // case "center": + // word_width := len(table.Rows[u][i]) + // offset := (width - word_width) / 2 + // row[i] = fmt.Sprintf(" %*s ", width, fmt.Sprintf("%-*s", offset+word_width, table.Rows[u][i])) + // default: // left + // row[i] = fmt.Sprintf(" %-*s ", width, table.Rows[u][i]) + // } + // } + //} + + //if table.Width == 0 { + // table.Width = width_sum + //} +} + +func (table *Table) SetSize() { + length := len(table.Rows) + if table.Seperator { + table.Height = length*2 + 1 + } else { + table.Height = length + 2 + } + table.Width = 2 + if length != 0 { + for _, cell_width := range table.CellWidth { + table.Width += cell_width + 3 + } + } +} + +func (table *Table) CalculatePosition(x int, y int, x_coordinate *int, y_coordibate *int, cell_beginning *int) { + if table.Seperator { + *y_coordibate = table.innerArea.Min.Y + y*2 + } else { + *y_coordibate = table.innerArea.Min.Y + y + } + if x == 0 { + *cell_beginning = table.innerArea.Min.X + } else { + *cell_beginning += table.CellWidth[x-1] + 3 + } + + switch table.TextAlign { + case AlignRight: + *x_coordinate = *cell_beginning + (table.CellWidth[x] - len(table.Rows[y][x])) + 2 + case AlignCenter: + *x_coordinate = *cell_beginning + (table.CellWidth[x]-len(table.Rows[y][x]))/2 + 2 + default: + *x_coordinate = *cell_beginning + 2 + } +} + +func (table *Table) Buffer() Buffer { + buffer := table.Block.Buffer() + table.Analysis() + + pointer_x := table.innerArea.Min.X + 2 + pointer_y := table.innerArea.Min.Y + border_pointer_x := table.innerArea.Min.X + for y, row := range table.Rows { + for x, cell := range row { + table.CalculatePosition(x, y, &pointer_x, &pointer_y, &border_pointer_x) + backgraound := DefaultTxBuilder.Build(strings.Repeat(" ", table.CellWidth[x]+3), table.BgColors[y], table.BgColors[y]) + cells := DefaultTxBuilder.Build(cell, table.FgColors[y], table.BgColors[y]) + + for i, back := range backgraound { + buffer.Set(border_pointer_x+i, pointer_y, back) + } + + coordinate_x := pointer_x + for _, printer := range cells { + buffer.Set(coordinate_x, pointer_y, printer) + coordinate_x += printer.Width() + } + + if x != 0 { + devidors := DefaultTxBuilder.Build("|", table.FgColors[y], table.BgColors[y]) + for _, devidor := range devidors { + buffer.Set(border_pointer_x, pointer_y, devidor) + } + } + } + + if table.Seperator { + border := DefaultTxBuilder.Build(strings.Repeat("─", table.Width-2), table.FgColor, table.BgColor) + for i, cell := range border { + buffer.Set(i+1, pointer_y+1, cell) + } + } + } + + return buffer +} diff --git a/vendor/github.com/gizak/termui/textbuilder.go b/vendor/github.com/gizak/termui/textbuilder.go index 06a019beda..818a40022f 100644 --- a/vendor/github.com/gizak/termui/textbuilder.go +++ b/vendor/github.com/gizak/termui/textbuilder.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/theme.go b/vendor/github.com/gizak/termui/theme.go index c3ccda5591..9632ae791c 100644 --- a/vendor/github.com/gizak/termui/theme.go +++ b/vendor/github.com/gizak/termui/theme.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/gizak/termui/widget.go b/vendor/github.com/gizak/termui/widget.go index 35cf143a39..f14aa8602c 100644 --- a/vendor/github.com/gizak/termui/widget.go +++ b/vendor/github.com/gizak/termui/widget.go @@ -1,4 +1,4 @@ -// Copyright 2016 Zack Guo . All rights reserved. +// Copyright 2016 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. diff --git a/vendor/github.com/huin/goupnp/README.md b/vendor/github.com/huin/goupnp/README.md index a228ccea64..433ba5c682 100644 --- a/vendor/github.com/huin/goupnp/README.md +++ b/vendor/github.com/huin/goupnp/README.md @@ -8,18 +8,18 @@ Run `go get -u github.com/huin/goupnp`. Documentation ------------- -All doc links below are for ![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg). - Supported DCPs (you probably want to start with one of these): -* [av1](https://godoc.org/github.com/huin/goupnp/dcps/av1) - Client for UPnP Device Control Protocol MediaServer v1 and MediaRenderer v1. -* [internetgateway1](https://godoc.org/github.com/huin/goupnp/dcps/internetgateway1) - Client for UPnP Device Control Protocol Internet Gateway Device v1. -* [internetgateway2](https://godoc.org/github.com/huin/goupnp/dcps/internetgateway2) - Client for UPnP Device Control Protocol Internet Gateway Device v2. + +* [![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg) av1](https://godoc.org/github.com/huin/goupnp/dcps/av1) - Client for UPnP Device Control Protocol MediaServer v1 and MediaRenderer v1. +* [![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg) internetgateway1](https://godoc.org/github.com/huin/goupnp/dcps/internetgateway1) - Client for UPnP Device Control Protocol Internet Gateway Device v1. +* [![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg) internetgateway2](https://godoc.org/github.com/huin/goupnp/dcps/internetgateway2) - Client for UPnP Device Control Protocol Internet Gateway Device v2. Core components: -* [(goupnp)](https://godoc.org/github.com/huin/goupnp) core library - contains datastructures and utilities typically used by the implemented DCPs. -* [httpu](https://godoc.org/github.com/huin/goupnp/httpu) HTTPU implementation, underlies SSDP. -* [ssdp](https://godoc.org/github.com/huin/goupnp/ssdp) SSDP client implementation (simple service discovery protocol) - used to discover UPnP services on a network. -* [soap](https://godoc.org/github.com/huin/goupnp/soap) SOAP client implementation (simple object access protocol) - used to communicate with discovered services. + +* [![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg) (goupnp)](https://godoc.org/github.com/huin/goupnp) core library - contains datastructures and utilities typically used by the implemented DCPs. +* [![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg) httpu](https://godoc.org/github.com/huin/goupnp/httpu) HTTPU implementation, underlies SSDP. +* [![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg) ssdp](https://godoc.org/github.com/huin/goupnp/ssdp) SSDP client implementation (simple service discovery protocol) - used to discover UPnP services on a network. +* [![GoDoc](https://godoc.org/github.com/huin/goupnp?status.svg) soap](https://godoc.org/github.com/huin/goupnp/soap) SOAP client implementation (simple object access protocol) - used to communicate with discovered services. Regenerating dcps generated source code: diff --git a/vendor/github.com/maruel/panicparse/.travis.yml b/vendor/github.com/maruel/panicparse/.travis.yml new file mode 100644 index 0000000000..c6da8f0b8c --- /dev/null +++ b/vendor/github.com/maruel/panicparse/.travis.yml @@ -0,0 +1,15 @@ +# Copyright 2014 Marc-Antoine Ruel. All rights reserved. +# Use of this source code is governed under the Apache License, Version 2.0 +# that can be found in the LICENSE file. + +sudo: false +language: go + +go: +- tip + +before_install: + - go get github.com/maruel/pre-commit-go/cmd/pcg + +script: + - pcg diff --git a/vendor/github.com/maruel/panicparse/LICENSE b/vendor/github.com/maruel/panicparse/LICENSE new file mode 100644 index 0000000000..b76840c258 --- /dev/null +++ b/vendor/github.com/maruel/panicparse/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 Marc-Antoine Ruel + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/maruel/panicparse/README.md b/vendor/github.com/maruel/panicparse/README.md new file mode 100644 index 0000000000..9fc039cd9c --- /dev/null +++ b/vendor/github.com/maruel/panicparse/README.md @@ -0,0 +1,123 @@ +panicparse +========== + +Parses panic stack traces, densifies and deduplicates goroutines with similar +stack traces. Helps debugging crashes and deadlocks in heavily parallelized +process. + +[![Build Status](https://travis-ci.org/maruel/panicparse.svg?branch=master)](https://travis-ci.org/maruel/panicparse) + +panicparse helps make sense of Go crash dumps: + +![Screencast](https://raw.githubusercontent.com/wiki/maruel/panicparse/parse.gif "Screencast") + + +Features +-------- + + * >50% more compact output than original stack dump yet more readable. + * Exported symbols are bold, private symbols are darker. + * Stdlib is green, main is yellow, rest is red. + * Deduplicates redundant goroutine stacks. Useful for large server crashes. + * Arguments as pointer IDs instead of raw pointer values. + * Pushes stdlib-only stacks at the bottom to help focus on important code. + * Usable as a library! + [![GoDoc](https://godoc.org/github.com/maruel/panicparse/stack?status.svg)](https://godoc.org/github.com/maruel/panicparse/stack) + * Warning: please pin the version (e.g. vendor it). Breaking changes are + not planned but may happen. + * Parses the source files if available to augment the output. + * Works on Windows. + + +Installation +------------ + + go get github.com/maruel/panicparse/cmd/pp + + +Usage +----- + +### Piping a stack trace from another process + +#### TL;DR + + * Ubuntu (bash v4 or zsh): `|&` + * OSX, [install bash 4+](README.md#updating-bash-on-osx), then: `|&` + * Windows _or_ OSX with stock bash v3: `2>&1 |` + * [Fish](http://fishshell.com/) shell: `^|` + + +#### Longer version + +`pp` streams its stdin to stdout as long as it doesn't detect any panic. +`panic()` and Go's native deadlock detector [print to +stderr](https://golang.org/src/runtime/panic1.go) via the native [`print()` +function](https://golang.org/pkg/builtin/#print). + + +**Bash v4** or **zsh**: `|&` tells the shell to redirect stderr to stdout, +it's an alias for `2>&1 |` ([bash +v4](https://www.gnu.org/software/bash/manual/bash.html#Pipelines), +[zsh](http://zsh.sourceforge.net/Doc/Release/Shell-Grammar.html#Simple-Commands-_0026-Pipelines)): + + go test -v |&pp + + +**Windows or OSX native bash** [(which is +3.2.57)](http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/): They don't +have this shortcut, so use the long form: + + go test -v 2>&1 | pp + + +**Fish**: It uses [^ for stderr +redirection](http://fishshell.com/docs/current/tutorial.html#tut_pipes_and_redirections) +so the shortcut is `^|`: + + go test -v ^|pp + + +**PowerShell**: [It has broken `2>&1` redirection](https://connect.microsoft.com/PowerShell/feedback/details/765551/in-powershell-v3-you-cant-redirect-stderr-to-stdout-without-generating-error-records). The workaround is to shell out to cmd.exe. :( + + +### Investigate deadlock + +On POSIX, use `Ctrl-\` to send SIGQUIT to your process, `pp` will ignore +the signal and will parse the stack trace. + + +### Parsing from a file + +To dump to a file then parse, pass the file path of a stack trace + + go test 2> stack.txt + pp stack.txt + + +Tips +---- + +### GOTRACEBACK + +Starting with Go 1.6, [`GOTRACEBACK`](https://golang.org/pkg/runtime/) defaults +to `single` instead of `all` / `1` that was used in 1.5 and before. To get all +goroutines trace and not just the crashing one, set the environment variable: + + export GOTRACEBACK=all + +or `set GOTRACEBACK=all` on Windows. Probably worth to put it in your `.bashrc`. + + +### Updating bash on OSX + +Install bash v4+ on OSX via [homebrew](http://brew.sh) or +[macports](https://www.macports.org/). Your future self will appreciate having +done that. + + +### If you have `/usr/bin/pp` installed + +You may have the Perl PAR Packager installed. Use long name `panicparse` then; + + go get github.com/maruel/panicparse diff --git a/vendor/github.com/maruel/panicparse/stack/source.go b/vendor/github.com/maruel/panicparse/stack/source.go new file mode 100644 index 0000000000..f09e67336a --- /dev/null +++ b/vendor/github.com/maruel/panicparse/stack/source.go @@ -0,0 +1,291 @@ +// Copyright 2015 Marc-Antoine Ruel. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +// This file contains the code to process sources, to be able to deduct the +// original types. + +package stack + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/token" + "io/ioutil" + "log" + "math" + "strings" +) + +// cache is a cache of sources on the file system. +type cache struct { + files map[string][]byte + parsed map[string]*parsedFile +} + +// Augment processes source files to improve calls to be more descriptive. +// +// It modifies goroutines in place. +func Augment(goroutines []Goroutine) { + c := &cache{} + for i := range goroutines { + c.augmentGoroutine(&goroutines[i]) + } +} + +// augmentGoroutine processes source files to improve call to be more +// descriptive. +// +// It modifies the routine. +func (c *cache) augmentGoroutine(goroutine *Goroutine) { + if c.files == nil { + c.files = map[string][]byte{} + } + if c.parsed == nil { + c.parsed = map[string]*parsedFile{} + } + // For each call site, look at the next call and populate it. Then we can + // walk back and reformat things. + for i := range goroutine.Stack.Calls { + c.load(goroutine.Stack.Calls[i].SourcePath) + } + + // Once all loaded, we can look at the next call when available. + for i := 1; i < len(goroutine.Stack.Calls); i++ { + // Get the AST from the previous call and process the call line with it. + if f := c.getFuncAST(&goroutine.Stack.Calls[i]); f != nil { + processCall(&goroutine.Stack.Calls[i], f) + } + } +} + +// Private stuff. + +// load loads a source file and parses the AST tree. Failures are ignored. +func (c *cache) load(fileName string) { + if _, ok := c.parsed[fileName]; ok { + return + } + c.parsed[fileName] = nil + if !strings.HasSuffix(fileName, ".go") { + // Ignore C and assembly. + c.files[fileName] = nil + return + } + log.Printf("load(%s)", fileName) + if _, ok := c.files[fileName]; !ok { + var err error + if c.files[fileName], err = ioutil.ReadFile(fileName); err != nil { + log.Printf("Failed to read %s: %s", fileName, err) + c.files[fileName] = nil + return + } + } + fset := token.NewFileSet() + src := c.files[fileName] + parsed, err := parser.ParseFile(fset, fileName, src, 0) + if err != nil { + log.Printf("Failed to parse %s: %s", fileName, err) + return + } + // Convert the line number into raw file offset. + offsets := []int{0, 0} + start := 0 + for l := 1; start < len(src); l++ { + start += bytes.IndexByte(src[start:], '\n') + 1 + offsets = append(offsets, start) + } + c.parsed[fileName] = &parsedFile{offsets, parsed} +} + +func (c *cache) getFuncAST(call *Call) *ast.FuncDecl { + if p := c.parsed[call.SourcePath]; p != nil { + return p.getFuncAST(call.Func.Name(), call.Line) + } + return nil +} + +type parsedFile struct { + lineToByteOffset []int + parsed *ast.File +} + +// getFuncAST gets the callee site function AST representation for the code +// inside the function f at line l. +func (p *parsedFile) getFuncAST(f string, l int) (d *ast.FuncDecl) { + // Walk the AST to find the lineToByteOffset that fits the line number. + var lastFunc *ast.FuncDecl + var found ast.Node + // Inspect() goes depth first. This means for example that a function like: + // func a() { + // b := func() {} + // c() + // } + // + // Were we are looking at the c() call can return confused values. It is + // important to look at the actual ast.Node hierarchy. + ast.Inspect(p.parsed, func(n ast.Node) bool { + if d != nil { + return false + } + if n == nil { + return true + } + if found != nil { + // We are walking up. + } + if int(n.Pos()) >= p.lineToByteOffset[l] { + // We are expecting a ast.CallExpr node. It can be harder to figure out + // when there are multiple calls on a single line, as the stack trace + // doesn't have file byte offset information, only line based. + // gofmt will always format to one function call per line but there can + // be edge cases, like: + // a = A{Foo(), Bar()} + d = lastFunc + //p.processNode(call, n) + return false + } else if f, ok := n.(*ast.FuncDecl); ok { + lastFunc = f + } + return true + }) + return +} + +func name(n ast.Node) string { + if _, ok := n.(*ast.InterfaceType); ok { + return "interface{}" + } + if i, ok := n.(*ast.Ident); ok { + return i.Name + } + if _, ok := n.(*ast.FuncType); ok { + return "func" + } + if s, ok := n.(*ast.SelectorExpr); ok { + return s.Sel.Name + } + // TODO(maruel): Implement anything missing. + return "" +} + +// fieldToType returns the type name and whether if it's an ellipsis. +func fieldToType(f *ast.Field) (string, bool) { + switch arg := f.Type.(type) { + case *ast.ArrayType: + return "[]" + name(arg.Elt), false + case *ast.Ellipsis: + return name(arg.Elt), true + case *ast.FuncType: + // Do not print the function signature to not overload the trace. + return "func", false + case *ast.Ident: + return arg.Name, false + case *ast.InterfaceType: + return "interface{}", false + case *ast.SelectorExpr: + return arg.Sel.Name, false + case *ast.StarExpr: + return "*" + name(arg.X), false + default: + // TODO(maruel): Implement anything missing. + return "", false + } +} + +// extractArgumentsType returns the name of the type of each input argument. +func extractArgumentsType(f *ast.FuncDecl) ([]string, bool) { + var fields []*ast.Field + if f.Recv != nil { + if len(f.Recv.List) != 1 { + panic("Expect only one receiver; please fix panicparse's code") + } + // If it is an object receiver (vs a pointer receiver), its address is not + // printed in the stack trace so it needs to be ignored. + if _, ok := f.Recv.List[0].Type.(*ast.StarExpr); ok { + fields = append(fields, f.Recv.List[0]) + } + } + var types []string + extra := false + for _, arg := range append(fields, f.Type.Params.List...) { + // Assert that extra is only set on the last item of fields? + var t string + t, extra = fieldToType(arg) + mult := len(arg.Names) + if mult == 0 { + mult = 1 + } + for i := 0; i < mult; i++ { + types = append(types, t) + } + } + return types, extra +} + +// processCall walks the function and populate call accordingly. +func processCall(call *Call, f *ast.FuncDecl) { + values := make([]uint64, len(call.Args.Values)) + for i := range call.Args.Values { + values[i] = call.Args.Values[i].Value + } + index := 0 + pop := func() uint64 { + if len(values) != 0 { + x := values[0] + values = values[1:] + index++ + return x + } + return 0 + } + popName := func() string { + n := call.Args.Values[index].Name + v := pop() + if len(n) == 0 { + return fmt.Sprintf("0x%x", v) + } + return n + } + + types, extra := extractArgumentsType(f) + for i := 0; len(values) != 0; i++ { + var t string + if i >= len(types) { + if !extra { + // These are unexpected value! Print them as hex. + call.Args.Processed = append(call.Args.Processed, popName()) + continue + } + t = types[len(types)-1] + } else { + t = types[i] + } + switch t { + case "float32": + call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%g", math.Float32frombits(uint32(pop())))) + case "float64": + call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%g", math.Float64frombits(pop()))) + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64": + call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%d", pop())) + case "string": + call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s, len=%d)", t, popName(), pop())) + default: + if strings.HasPrefix(t, "*") { + call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s)", t, popName())) + } else if strings.HasPrefix(t, "[]") { + call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s len=%d cap=%d)", t, popName(), pop(), pop())) + } else { + // Assumes it's an interface. For now, discard the object value, which + // is probably not a good idea. + call.Args.Processed = append(call.Args.Processed, fmt.Sprintf("%s(%s)", t, popName())) + pop() + } + } + if len(values) == 0 && call.Args.Elided { + return + } + } +} diff --git a/vendor/github.com/maruel/panicparse/stack/stack.go b/vendor/github.com/maruel/panicparse/stack/stack.go new file mode 100644 index 0000000000..cfb502e663 --- /dev/null +++ b/vendor/github.com/maruel/panicparse/stack/stack.go @@ -0,0 +1,832 @@ +// Copyright 2015 Marc-Antoine Ruel. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +// Package stack analyzes stack dump of Go processes and simplifies it. +// +// It is mostly useful on servers will large number of identical goroutines, +// making the crash dump harder to read than strictly necesary. +package stack + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "math" + "net/url" + "os" + "path/filepath" + "regexp" + "runtime" + "sort" + "strconv" + "strings" + "unicode" + "unicode/utf8" +) + +const lockedToThread = "locked to thread" + +var ( + // TODO(maruel): Handle corrupted stack cases: + // - missed stack barrier + // - found next stack barrier at 0x123; expected + // - runtime: unexpected return pc for FUNC_NAME called from 0x123 + + reRoutineHeader = regexp.MustCompile("^goroutine (\\d+) \\[([^\\]]+)\\]\\:\n$") + reMinutes = regexp.MustCompile("^(\\d+) minutes$") + reUnavail = regexp.MustCompile("^(?:\t| +)goroutine running on other thread; stack unavailable") + // See gentraceback() in src/runtime/traceback.go for more information. + // - Sometimes the source file comes up as "". It is the + // compiler than generated these, not the runtime. + // - The tab may be replaced with spaces when a user copy-paste it, handle + // this transparently. + // - "runtime.gopanic" is explicitly replaced with "panic" by gentraceback(). + // - The +0x123 byte offset is printed when frame.pc > _func.entry. _func is + // generated by the linker. + // - The +0x123 byte offset is not included with generated code, e.g. unnamed + // functions "func·006()" which is generally go func() { ... }() + // statements. Since the _func is generated at runtime, it's probably why + // _func.entry is not set. + // - C calls may have fp=0x123 sp=0x123 appended. I think it normally happens + // when a signal is not correctly handled. It is printed with m.throwing>0. + // These are discarded. + // - For cgo, the source file may be "??". + reFile = regexp.MustCompile("^(?:\t| +)(\\?\\?|\\|.+\\.(?:c|go|s))\\:(\\d+)(?:| \\+0x[0-9a-f]+)(?:| fp=0x[0-9a-f]+ sp=0x[0-9a-f]+)\n$") + // Sadly, it doesn't note the goroutine number so we could cascade them per + // parenthood. + reCreated = regexp.MustCompile("^created by (.+)\n$") + reFunc = regexp.MustCompile("^(.+)\\((.*)\\)\n$") + reElided = regexp.MustCompile("^\\.\\.\\.additional frames elided\\.\\.\\.\n$") + // Include frequent GOROOT value on Windows, distro provided and user + // installed path. This simplifies the user's life when processing a trace + // generated on another VM. + // TODO(maruel): Guess the path automatically via traces containing the + // 'runtime' package, which is very frequent. This would be "less bad" than + // throwing up random values at the parser. + goroots = []string{runtime.GOROOT(), "c:/go", "/usr/lib/go", "/usr/local/go"} +) + +// Similarity is the level at which two call lines arguments must match to be +// considered similar enough to coalesce them. +type Similarity int + +const ( + // ExactFlags requires same bits (e.g. Locked). + ExactFlags Similarity = iota + // ExactLines requests the exact same arguments on the call line. + ExactLines + // AnyPointer considers different pointers a similar call line. + AnyPointer + // AnyValue accepts any value as similar call line. + AnyValue +) + +// Function is a function call. +// +// Go stack traces print a mangled function call, this wrapper unmangle the +// string before printing and adds other filtering methods. +type Function struct { + Raw string +} + +// String is the fully qualified function name. +// +// Sadly Go is a bit confused when the package name doesn't match the directory +// containing the source file and will use the directory name instead of the +// real package name. +func (f Function) String() string { + s, _ := url.QueryUnescape(f.Raw) + return s +} + +// Name is the naked function name. +func (f Function) Name() string { + parts := strings.SplitN(filepath.Base(f.Raw), ".", 2) + if len(parts) == 1 { + return parts[0] + } + return parts[1] +} + +// PkgName is the package name for this function reference. +func (f Function) PkgName() string { + parts := strings.SplitN(filepath.Base(f.Raw), ".", 2) + if len(parts) == 1 { + return "" + } + s, _ := url.QueryUnescape(parts[0]) + return s +} + +// PkgDotName returns "." format. +func (f Function) PkgDotName() string { + parts := strings.SplitN(filepath.Base(f.Raw), ".", 2) + s, _ := url.QueryUnescape(parts[0]) + if len(parts) == 1 { + return parts[0] + } + if s != "" || parts[1] != "" { + return s + "." + parts[1] + } + return "" +} + +// IsExported returns true if the function is exported. +func (f Function) IsExported() bool { + name := f.Name() + parts := strings.Split(name, ".") + r, _ := utf8.DecodeRuneInString(parts[len(parts)-1]) + if unicode.ToUpper(r) == r { + return true + } + return f.PkgName() == "main" && name == "main" +} + +// Arg is an argument on a Call. +type Arg struct { + Value uint64 // Value is the raw value as found in the stack trace + Name string // Name is a pseudo name given to the argument +} + +// IsPtr returns true if we guess it's a pointer. It's only a guess, it can be +// easily be confused by a bitmask. +func (a *Arg) IsPtr() bool { + // Assumes all pointers are above 16Mb and positive. + return a.Value > 16*1024*1024 && a.Value < math.MaxInt64 +} + +func (a Arg) String() string { + if a.Name != "" { + return a.Name + } + if a.Value == 0 { + return "0" + } + return fmt.Sprintf("0x%x", a.Value) +} + +// Args is a series of function call arguments. +type Args struct { + Values []Arg // Values is the arguments as shown on the stack trace. They are mangled via simplification. + Processed []string // Processed is the arguments generated from processing the source files. It can have a length lower than Values. + Elided bool // If set, it means there was a trailing ", ..." +} + +func (a Args) String() string { + var v []string + if len(a.Processed) != 0 { + v = make([]string, 0, len(a.Processed)) + for _, item := range a.Processed { + v = append(v, item) + } + } else { + v = make([]string, 0, len(a.Values)) + for _, item := range a.Values { + v = append(v, item.String()) + } + } + if a.Elided { + v = append(v, "...") + } + return strings.Join(v, ", ") +} + +// Equal returns true only if both arguments are exactly equal. +func (a *Args) Equal(r *Args) bool { + if a.Elided != r.Elided || len(a.Values) != len(r.Values) { + return false + } + for i, l := range a.Values { + if l != r.Values[i] { + return false + } + } + return true +} + +// Similar returns true if the two Args are equal or almost but not quite +// equal. +func (a *Args) Similar(r *Args, similar Similarity) bool { + if a.Elided != r.Elided || len(a.Values) != len(r.Values) { + return false + } + if similar == AnyValue { + return true + } + for i, l := range a.Values { + switch similar { + case ExactFlags, ExactLines: + if l != r.Values[i] { + return false + } + default: + if l.IsPtr() != r.Values[i].IsPtr() || (!l.IsPtr() && l != r.Values[i]) { + return false + } + } + } + return true +} + +// Merge merges two similar Args, zapping out differences. +func (a *Args) Merge(r *Args) Args { + out := Args{ + Values: make([]Arg, len(a.Values)), + Elided: a.Elided, + } + for i, l := range a.Values { + if l != r.Values[i] { + out.Values[i].Name = "*" + out.Values[i].Value = l.Value + } else { + out.Values[i] = l + } + } + return out +} + +// Call is an item in the stack trace. +type Call struct { + SourcePath string // Full path name of the source file + Line int // Line number + Func Function // Fully qualified function name (encoded). + Args Args // Call arguments +} + +// Equal returns true only if both calls are exactly equal. +func (c *Call) Equal(r *Call) bool { + return c.SourcePath == r.SourcePath && c.Line == r.Line && c.Func == r.Func && c.Args.Equal(&r.Args) +} + +// Similar returns true if the two Call are equal or almost but not quite +// equal. +func (c *Call) Similar(r *Call, similar Similarity) bool { + return c.SourcePath == r.SourcePath && c.Line == r.Line && c.Func == r.Func && c.Args.Similar(&r.Args, similar) +} + +// Merge merges two similar Call, zapping out differences. +func (c *Call) Merge(r *Call) Call { + return Call{ + SourcePath: c.SourcePath, + Line: c.Line, + Func: c.Func, + Args: c.Args.Merge(&r.Args), + } +} + +// SourceName returns the base file name of the source file. +func (c *Call) SourceName() string { + return filepath.Base(c.SourcePath) +} + +// SourceLine returns "source.go:line", including only the base file name. +func (c *Call) SourceLine() string { + return fmt.Sprintf("%s:%d", c.SourceName(), c.Line) +} + +// FullSourceLine returns "/path/to/source.go:line". +func (c *Call) FullSourceLine() string { + return fmt.Sprintf("%s:%d", c.SourcePath, c.Line) +} + +// PkgSource is one directory plus the file name of the source file. +func (c *Call) PkgSource() string { + return filepath.Join(filepath.Base(filepath.Dir(c.SourcePath)), c.SourceName()) +} + +const testMainSource = "_test" + string(os.PathSeparator) + "_testmain.go" + +// IsStdlib returns true if it is a Go standard library function. This includes +// the 'go test' generated main executable. +func (c *Call) IsStdlib() bool { + for _, goroot := range goroots { + if strings.HasPrefix(c.SourcePath, goroot) { + return true + } + } + // Consider _test/_testmain.go as stdlib since it's injected by "go test". + return c.PkgSource() == testMainSource +} + +// IsPkgMain returns true if it is in the main package. +func (c *Call) IsPkgMain() bool { + return c.Func.PkgName() == "main" +} + +// Stack is a call stack. +type Stack struct { + Calls []Call // Call stack. First is original function, last is leaf function. + Elided bool // Happens when there's >100 items in Stack, currently hardcoded in package runtime. +} + +// Equal returns true on if both call stacks are exactly equal. +func (s *Stack) Equal(r *Stack) bool { + if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided { + return false + } + for i := range s.Calls { + if !s.Calls[i].Equal(&r.Calls[i]) { + return false + } + } + return true +} + +// Similar returns true if the two Stack are equal or almost but not quite +// equal. +func (s *Stack) Similar(r *Stack, similar Similarity) bool { + if len(s.Calls) != len(r.Calls) || s.Elided != r.Elided { + return false + } + for i := range s.Calls { + if !s.Calls[i].Similar(&r.Calls[i], similar) { + return false + } + } + return true +} + +// Merge merges two similar Stack, zapping out differences. +func (s *Stack) Merge(r *Stack) *Stack { + // Assumes similar stacks have the same length. + out := &Stack{ + Calls: make([]Call, len(s.Calls)), + Elided: s.Elided, + } + for i := range s.Calls { + out.Calls[i] = s.Calls[i].Merge(&r.Calls[i]) + } + return out +} + +// Less compares two Stack, where the ones that are less are more +// important, so they come up front. A Stack with more private functions is +// 'less' so it is at the top. Inversely, a Stack with only public +// functions is 'more' so it is at the bottom. +func (s *Stack) Less(r *Stack) bool { + lStdlib := 0 + lPrivate := 0 + for _, c := range s.Calls { + if c.IsStdlib() { + lStdlib++ + } else { + lPrivate++ + } + } + rStdlib := 0 + rPrivate := 0 + for _, s := range r.Calls { + if s.IsStdlib() { + rStdlib++ + } else { + rPrivate++ + } + } + if lPrivate > rPrivate { + return true + } + if lPrivate < rPrivate { + return false + } + if lStdlib > rStdlib { + return false + } + if lStdlib < rStdlib { + return true + } + + // Stack lengths are the same. + for x := range s.Calls { + if s.Calls[x].Func.Raw < r.Calls[x].Func.Raw { + return true + } + if s.Calls[x].Func.Raw > r.Calls[x].Func.Raw { + return true + } + if s.Calls[x].PkgSource() < r.Calls[x].PkgSource() { + return true + } + if s.Calls[x].PkgSource() > r.Calls[x].PkgSource() { + return true + } + if s.Calls[x].Line < r.Calls[x].Line { + return true + } + if s.Calls[x].Line > r.Calls[x].Line { + return true + } + } + return false +} + +// Signature represents the signature of one or multiple goroutines. +// +// It is effectively the stack trace plus the goroutine internal bits, like +// it's state, if it is thread locked, which call site created this goroutine, +// etc. +type Signature struct { + // Use git grep 'gopark(|unlock)\(' to find them all plus everything listed + // in runtime/traceback.go. Valid values includes: + // - chan send, chan receive, select + // - finalizer wait, mark wait (idle), + // - Concurrent GC wait, GC sweep wait, force gc (idle) + // - IO wait, panicwait + // - semacquire, semarelease + // - sleep, timer goroutine (idle) + // - trace reader (blocked) + // Stuck cases: + // - chan send (nil chan), chan receive (nil chan), select (no cases) + // Runnable states: + // - idle, runnable, running, syscall, waiting, dead, enqueue, copystack, + // Scan states: + // - scan, scanrunnable, scanrunning, scansyscall, scanwaiting, scandead, + // scanenqueue + State string + CreatedBy Call // Which other goroutine which created this one. + SleepMin int // Wait time in minutes, if applicable. + SleepMax int // Wait time in minutes, if applicable. + Stack Stack + Locked bool // Locked to an OS thread. +} + +// Equal returns true only if both signatures are exactly equal. +func (s *Signature) Equal(r *Signature) bool { + if s.State != r.State || !s.CreatedBy.Equal(&r.CreatedBy) || s.Locked != r.Locked || s.SleepMin != r.SleepMin || s.SleepMax != r.SleepMax { + return false + } + return s.Stack.Equal(&r.Stack) +} + +// Similar returns true if the two Signature are equal or almost but not quite +// equal. +func (s *Signature) Similar(r *Signature, similar Similarity) bool { + if s.State != r.State || !s.CreatedBy.Similar(&r.CreatedBy, similar) { + return false + } + if similar == ExactFlags && s.Locked != r.Locked { + return false + } + return s.Stack.Similar(&r.Stack, similar) +} + +// Merge merges two similar Signature, zapping out differences. +func (s *Signature) Merge(r *Signature) *Signature { + min := s.SleepMin + if r.SleepMin < min { + min = r.SleepMin + } + max := s.SleepMax + if r.SleepMax > max { + max = r.SleepMax + } + return &Signature{ + State: s.State, // Drop right side. + CreatedBy: s.CreatedBy, // Drop right side. + SleepMin: min, + SleepMax: max, + Stack: *s.Stack.Merge(&r.Stack), + Locked: s.Locked || r.Locked, // TODO(maruel): This is weirdo. + } +} + +// Less compares two Signature, where the ones that are less are more +// important, so they come up front. A Signature with more private functions is +// 'less' so it is at the top. Inversely, a Signature with only public +// functions is 'more' so it is at the bottom. +func (s *Signature) Less(r *Signature) bool { + if s.Stack.Less(&r.Stack) { + return true + } + if r.Stack.Less(&s.Stack) { + return false + } + if s.Locked && !r.Locked { + return true + } + if r.Locked && !s.Locked { + return false + } + if s.State < r.State { + return true + } + if s.State > r.State { + return false + } + return false +} + +// Goroutine represents the state of one goroutine, including the stack trace. +type Goroutine struct { + Signature // It's stack trace, internal bits, state, which call site created it, etc. + ID int // Goroutine ID. + First bool // First is the goroutine first printed, normally the one that crashed. +} + +// Bucketize returns the number of similar goroutines. +func Bucketize(goroutines []Goroutine, similar Similarity) map[*Signature][]Goroutine { + out := map[*Signature][]Goroutine{} + // O(n²). Fix eventually. + for _, routine := range goroutines { + found := false + for key := range out { + // When a match is found, this effectively drops the other goroutine ID. + if key.Similar(&routine.Signature, similar) { + found = true + if !key.Equal(&routine.Signature) { + // Almost but not quite equal. There's different pointers passed + // around but the same values. Zap out the different values. + newKey := key.Merge(&routine.Signature) + out[newKey] = append(out[key], routine) + delete(out, key) + } else { + out[key] = append(out[key], routine) + } + break + } + } + if !found { + key := &Signature{} + *key = routine.Signature + out[key] = []Goroutine{routine} + } + } + return out +} + +// Bucket is a stack trace signature and the list of goroutines that fits this +// signature. +type Bucket struct { + Signature + Routines []Goroutine +} + +// First returns true if it contains the first goroutine, e.g. the ones that +// likely generated the panic() call, if any. +func (b *Bucket) First() bool { + for _, r := range b.Routines { + if r.First { + return true + } + } + return false +} + +// Less does reverse sort. +func (b *Bucket) Less(r *Bucket) bool { + if b.First() { + return true + } + if r.First() { + return false + } + return b.Signature.Less(&r.Signature) +} + +// Buckets is a list of Bucket sorted by repeation count. +type Buckets []Bucket + +func (b Buckets) Len() int { + return len(b) +} + +func (b Buckets) Less(i, j int) bool { + return b[i].Less(&b[j]) +} + +func (b Buckets) Swap(i, j int) { + b[j], b[i] = b[i], b[j] +} + +// SortBuckets creates a list of Bucket from each goroutine stack trace count. +func SortBuckets(buckets map[*Signature][]Goroutine) Buckets { + out := make(Buckets, 0, len(buckets)) + for signature, count := range buckets { + out = append(out, Bucket{*signature, count}) + } + sort.Sort(out) + return out +} + +// scanLines is similar to bufio.ScanLines except that it: +// - doesn't drop '\n' +// - doesn't strip '\r' +// - returns when the data is bufio.MaxScanTokenSize bytes +func scanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { + if atEOF && len(data) == 0 { + return 0, nil, nil + } + if i := bytes.IndexByte(data, '\n'); i >= 0 { + return i + 1, data[0 : i+1], nil + } + if atEOF { + return len(data), data, nil + } + if len(data) >= bufio.MaxScanTokenSize { + // Returns the line even if it is not at EOF nor has a '\n', otherwise the + // scanner will return bufio.ErrTooLong which is definitely not what we + // want. + return len(data), data, nil + } + return 0, nil, nil +} + +// ParseDump processes the output from runtime.Stack(). +// +// It supports piping from another command and assumes there is junk before the +// actual stack trace. The junk is streamed to out. +func ParseDump(r io.Reader, out io.Writer) ([]Goroutine, error) { + goroutines := make([]Goroutine, 0, 16) + var goroutine *Goroutine + scanner := bufio.NewScanner(r) + scanner.Split(scanLines) + // TODO(maruel): Use a formal state machine. Patterns follows: + // - reRoutineHeader + // Either: + // - reUnavail + // - reFunc + reFile in a loop + // - reElided + // Optionally ends with: + // - reCreated + reFile + // Between each goroutine stack dump: an empty line + created := false + // firstLine is the first line after the reRoutineHeader header line. + firstLine := false + for scanner.Scan() { + line := scanner.Text() + if line == "\n" { + if goroutine != nil { + goroutine = nil + continue + } + } else if line[len(line)-1] == '\n' { + if goroutine == nil { + if match := reRoutineHeader.FindStringSubmatch(line); match != nil { + if id, err := strconv.Atoi(match[1]); err == nil { + // See runtime/traceback.go. + // ", \d+ minutes, locked to thread" + items := strings.Split(match[2], ", ") + sleep := 0 + locked := false + for i := 1; i < len(items); i++ { + if items[i] == lockedToThread { + locked = true + continue + } + // Look for duration, if any. + if match2 := reMinutes.FindStringSubmatch(items[i]); match2 != nil { + sleep, _ = strconv.Atoi(match2[1]) + } + } + goroutines = append(goroutines, Goroutine{ + Signature: Signature{ + State: items[0], + SleepMin: sleep, + SleepMax: sleep, + Locked: locked, + }, + ID: id, + First: len(goroutines) == 0, + }) + goroutine = &goroutines[len(goroutines)-1] + firstLine = true + continue + } + } + } else { + if firstLine { + firstLine = false + if match := reUnavail.FindStringSubmatch(line); match != nil { + // Generate a fake stack entry. + goroutine.Stack.Calls = []Call{{SourcePath: ""}} + continue + } + } + + if match := reFile.FindStringSubmatch(line); match != nil { + // Triggers after a reFunc or a reCreated. + num, err := strconv.Atoi(match[2]) + if err != nil { + return goroutines, fmt.Errorf("failed to parse int on line: \"%s\"", line) + } + if created { + created = false + goroutine.CreatedBy.SourcePath = match[1] + goroutine.CreatedBy.Line = num + } else { + i := len(goroutine.Stack.Calls) - 1 + if i < 0 { + return goroutines, errors.New("unexpected order") + } + goroutine.Stack.Calls[i].SourcePath = match[1] + goroutine.Stack.Calls[i].Line = num + } + continue + } + + if match := reCreated.FindStringSubmatch(line); match != nil { + created = true + goroutine.CreatedBy.Func.Raw = match[1] + continue + } + + if match := reFunc.FindStringSubmatch(line); match != nil { + args := Args{} + for _, a := range strings.Split(match[2], ", ") { + if a == "..." { + args.Elided = true + continue + } + if a == "" { + // Remaining values were dropped. + break + } + v, err := strconv.ParseUint(a, 0, 64) + if err != nil { + return goroutines, fmt.Errorf("failed to parse int on line: \"%s\"", line) + } + args.Values = append(args.Values, Arg{Value: v}) + } + goroutine.Stack.Calls = append(goroutine.Stack.Calls, Call{Func: Function{match[1]}, Args: args}) + continue + } + + if match := reElided.FindStringSubmatch(line); match != nil { + goroutine.Stack.Elided = true + continue + } + } + } + _, _ = io.WriteString(out, line) + goroutine = nil + } + nameArguments(goroutines) + return goroutines, scanner.Err() +} + +// Private stuff. + +func nameArguments(goroutines []Goroutine) { + // Set a name for any pointer occuring more than once. + type object struct { + args []*Arg + inPrimary bool + id int + } + objects := map[uint64]object{} + // Enumerate all the arguments. + for i := range goroutines { + for j := range goroutines[i].Stack.Calls { + for k := range goroutines[i].Stack.Calls[j].Args.Values { + arg := goroutines[i].Stack.Calls[j].Args.Values[k] + if arg.IsPtr() { + objects[arg.Value] = object{ + args: append(objects[arg.Value].args, &goroutines[i].Stack.Calls[j].Args.Values[k]), + inPrimary: objects[arg.Value].inPrimary || i == 0, + } + } + } + } + // CreatedBy.Args is never set. + } + order := uint64Slice{} + for k, obj := range objects { + if len(obj.args) > 1 && obj.inPrimary { + order = append(order, k) + } + } + sort.Sort(order) + nextID := 1 + for _, k := range order { + for _, arg := range objects[k].args { + arg.Name = fmt.Sprintf("#%d", nextID) + } + nextID++ + } + + // Now do the rest. This is done so the output is deterministic. + order = uint64Slice{} + for k := range objects { + order = append(order, k) + } + sort.Sort(order) + for _, k := range order { + // Process the remaining pointers, they were not referenced by primary + // thread so will have higher IDs. + if objects[k].inPrimary { + continue + } + for _, arg := range objects[k].args { + arg.Name = fmt.Sprintf("#%d", nextID) + } + nextID++ + } +} + +type uint64Slice []uint64 + +func (a uint64Slice) Len() int { return len(a) } +func (a uint64Slice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a uint64Slice) Less(i, j int) bool { return a[i] < a[j] } diff --git a/vendor/github.com/maruel/panicparse/stack/ui.go b/vendor/github.com/maruel/panicparse/stack/ui.go new file mode 100644 index 0000000000..b125fc9406 --- /dev/null +++ b/vendor/github.com/maruel/panicparse/stack/ui.go @@ -0,0 +1,139 @@ +// Copyright 2016 Marc-Antoine Ruel. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package stack + +import ( + "fmt" + "strings" +) + +// Palette defines the color used. +// +// An empty object Palette{} can be used to disable coloring. +type Palette struct { + EOLReset string + + // Routine header. + RoutineFirst string // The first routine printed. + Routine string // Following routines. + CreatedBy string + + // Call line. + Package string + SourceFile string + FunctionStdLib string + FunctionStdLibExported string + FunctionMain string + FunctionOther string + FunctionOtherExported string + Arguments string +} + +// CalcLengths returns the maximum length of the source lines and package names. +func CalcLengths(buckets Buckets, fullPath bool) (int, int) { + srcLen := 0 + pkgLen := 0 + for _, bucket := range buckets { + for _, line := range bucket.Signature.Stack.Calls { + l := 0 + if fullPath { + l = len(line.FullSourceLine()) + } else { + l = len(line.SourceLine()) + } + if l > srcLen { + srcLen = l + } + l = len(line.Func.PkgName()) + if l > pkgLen { + pkgLen = l + } + } + } + return srcLen, pkgLen +} + +// functionColor returns the color to be used for the function name based on +// the type of package the function is in. +func (p *Palette) functionColor(line *Call) string { + if line.IsStdlib() { + if line.Func.IsExported() { + return p.FunctionStdLibExported + } + return p.FunctionStdLib + } else if line.IsPkgMain() { + return p.FunctionMain + } else if line.Func.IsExported() { + return p.FunctionOtherExported + } + return p.FunctionOther +} + +// routineColor returns the color for the header of the goroutines bucket. +func (p *Palette) routineColor(bucket *Bucket, multipleBuckets bool) string { + if bucket.First() && multipleBuckets { + return p.RoutineFirst + } + return p.Routine +} + +// BucketHeader prints the header of a goroutine signature. +func (p *Palette) BucketHeader(bucket *Bucket, fullPath, multipleBuckets bool) string { + extra := "" + if bucket.SleepMax != 0 { + if bucket.SleepMin != bucket.SleepMax { + extra += fmt.Sprintf(" [%d~%d minutes]", bucket.SleepMin, bucket.SleepMax) + } else { + extra += fmt.Sprintf(" [%d minutes]", bucket.SleepMax) + } + } + if bucket.Locked { + extra += " [locked]" + } + created := bucket.CreatedBy.Func.PkgDotName() + if created != "" { + created += " @ " + if fullPath { + created += bucket.CreatedBy.FullSourceLine() + } else { + created += bucket.CreatedBy.SourceLine() + } + extra += p.CreatedBy + " [Created by " + created + "]" + } + return fmt.Sprintf( + "%s%d: %s%s%s\n", + p.routineColor(bucket, multipleBuckets), len(bucket.Routines), + bucket.State, extra, + p.EOLReset) +} + +// callLine prints one stack line. +func (p *Palette) callLine(line *Call, srcLen, pkgLen int, fullPath bool) string { + src := "" + if fullPath { + src = line.FullSourceLine() + } else { + src = line.SourceLine() + } + return fmt.Sprintf( + " %s%-*s %s%-*s %s%s%s(%s)%s", + p.Package, pkgLen, line.Func.PkgName(), + p.SourceFile, srcLen, src, + p.functionColor(line), line.Func.Name(), + p.Arguments, line.Args, + p.EOLReset) +} + +// StackLines prints one complete stack trace, without the header. +func (p *Palette) StackLines(signature *Signature, srcLen, pkgLen int, fullPath bool) string { + out := make([]string, len(signature.Stack.Calls)) + for i := range signature.Stack.Calls { + out[i] = p.callLine(&signature.Stack.Calls[i], srcLen, pkgLen, fullPath) + } + if signature.Stack.Elided { + out = append(out, " (...)") + } + return strings.Join(out, "\n") + "\n" +} diff --git a/vendor/github.com/maruel/panicparse/vendor.yml b/vendor/github.com/maruel/panicparse/vendor.yml new file mode 100644 index 0000000000..ff3d43f5f2 --- /dev/null +++ b/vendor/github.com/maruel/panicparse/vendor.yml @@ -0,0 +1,17 @@ +vendors: +- path: github.com/kr/pretty + rev: 737b74a46c4bf788349f72cb256fed10aea4d0ac +- path: github.com/kr/text + rev: 7cafcd837844e784b526369c9bce262804aebc60 +- path: github.com/maruel/ut + rev: a9c9f15ccfa6f8b90182a53df32f4745586fbae3 +- path: github.com/mattn/go-colorable + rev: 9056b7a9f2d1f2d96498d6d146acd1f9d5ed3d59 +- path: github.com/mattn/go-isatty + rev: 56b76bdf51f7708750eac80fa38b952bb9f32639 +- path: github.com/mgutz/ansi + rev: c286dcecd19ff979eeb73ea444e479b903f2cfcb +- path: github.com/pmezard/go-difflib + rev: 792786c7400a136282c1664665ae0a8db921c6c2 +- path: golang.org/x/sys + rev: a646d33e2ee3172a661fc09bca23bb4889a41bc8 diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go index 52d6653b34..a7fe19a8ca 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_others.go +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -7,6 +7,7 @@ import ( "os" ) +// NewColorable return new instance of Writer which handle escape sequence. func NewColorable(file *os.File) io.Writer { if file == nil { panic("nil passed instead of *os.File to NewColorable()") @@ -15,10 +16,12 @@ func NewColorable(file *os.File) io.Writer { return file } +// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. func NewColorableStdout() io.Writer { return os.Stdout } +// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. func NewColorableStderr() io.Writer { return os.Stderr } diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index 448277f563..628ad904e5 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -75,6 +75,7 @@ type Writer struct { oldpos coord } +// NewColorable return new instance of Writer which handle escape sequence from File. func NewColorable(file *os.File) io.Writer { if file == nil { panic("nil passed instead of *os.File to NewColorable()") @@ -90,10 +91,12 @@ func NewColorable(file *os.File) io.Writer { } } +// NewColorableStdout return new instance of Writer which handle escape sequence for stdout. func NewColorableStdout() io.Writer { return NewColorable(os.Stdout) } +// NewColorableStderr return new instance of Writer which handle escape sequence for stderr. func NewColorableStderr() io.Writer { return NewColorable(os.Stderr) } @@ -357,6 +360,7 @@ var color256 = map[int]int{ 255: 0xeeeeee, } +// Write write data on console func (w *Writer) Write(data []byte) (n int, err error) { var csbi consoleScreenBufferInfo procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go index b60801dcd5..ca588c78ac 100644 --- a/vendor/github.com/mattn/go-colorable/noncolorable.go +++ b/vendor/github.com/mattn/go-colorable/noncolorable.go @@ -5,15 +5,18 @@ import ( "io" ) +// NonColorable hold writer but remove escape sequence. type NonColorable struct { out io.Writer lastbuf bytes.Buffer } +// NewNonColorable return new instance of Writer which remove escape sequence from Writer. func NewNonColorable(w io.Writer) io.Writer { return &NonColorable{out: w} } +// Write write data on console func (w *NonColorable) Write(data []byte) (n int, err error) { er := bytes.NewReader(data) var bw [1]byte diff --git a/vendor/github.com/nsf/termbox-go/README.md b/vendor/github.com/nsf/termbox-go/README.md index d152da4073..e7c57a9368 100644 --- a/vendor/github.com/nsf/termbox-go/README.md +++ b/vendor/github.com/nsf/termbox-go/README.md @@ -24,6 +24,7 @@ There are also some interesting projects using termbox-go: - [snake-game](https://github.com/DyegoCosta/snake-game) is an implementation of the Snake game. - [gone](https://github.com/guillaumebreton/gone) is a CLI pomodoro® timer. - [Spoof.go](https://github.com/sabey/spoofgo) controllable movement spoofing from the cli + - [lf](https://github.com/gokcehan/lf) is a terminal file manager ### API reference [godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go) diff --git a/vendor/github.com/nsf/termbox-go/api.go b/vendor/github.com/nsf/termbox-go/api.go index b339e532f8..b242ddcf3a 100644 --- a/vendor/github.com/nsf/termbox-go/api.go +++ b/vendor/github.com/nsf/termbox-go/api.go @@ -343,7 +343,6 @@ func PollEvent() Event { return event } } - panic("unreachable") } // Returns the size of the internal back buffer (which is mostly the same as diff --git a/vendor/github.com/nsf/termbox-go/termbox.go b/vendor/github.com/nsf/termbox-go/termbox.go index 6e5ba6c8fa..c2d86c6584 100644 --- a/vendor/github.com/nsf/termbox-go/termbox.go +++ b/vendor/github.com/nsf/termbox-go/termbox.go @@ -233,10 +233,7 @@ func send_char(x, y int, ch rune) { func flush() error { _, err := io.Copy(out, &outbuf) outbuf.Reset() - if err != nil { - return err - } - return nil + return err } func send_clear() error { diff --git a/vendor/github.com/pborman/uuid/README.md b/vendor/github.com/pborman/uuid/README.md index f023d47ca8..b0396b2747 100644 --- a/vendor/github.com/pborman/uuid/README.md +++ b/vendor/github.com/pborman/uuid/README.md @@ -1,7 +1,7 @@ This project was automatically exported from code.google.com/p/go-uuid # uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master) -The uuid package generates and inspects UUIDs based on [RFC 412](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services. +The uuid package generates and inspects UUIDs based on [RFC 4122](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services. ###### Install `go get github.com/pborman/uuid` diff --git a/vendor/github.com/rcrowley/go-metrics/gauge.go b/vendor/github.com/rcrowley/go-metrics/gauge.go index d618c45533..cb57a93889 100644 --- a/vendor/github.com/rcrowley/go-metrics/gauge.go +++ b/vendor/github.com/rcrowley/go-metrics/gauge.go @@ -44,7 +44,6 @@ func NewFunctionalGauge(f func() int64) Gauge { return &FunctionalGauge{value: f} } - // NewRegisteredFunctionalGauge constructs and registers a new StandardGauge. func NewRegisteredFunctionalGauge(name string, r Registry, f func() int64) Gauge { c := NewFunctionalGauge(f) @@ -101,6 +100,7 @@ func (g *StandardGauge) Update(v int64) { func (g *StandardGauge) Value() int64 { return atomic.LoadInt64(&g.value) } + // FunctionalGauge returns value from given function type FunctionalGauge struct { value func() int64 @@ -117,4 +117,4 @@ func (g FunctionalGauge) Snapshot() Gauge { return GaugeSnapshot(g.Value()) } // Update panics. func (FunctionalGauge) Update(int64) { panic("Update called on a FunctionalGauge") -} \ No newline at end of file +} diff --git a/vendor/github.com/rcrowley/go-metrics/registry.go b/vendor/github.com/rcrowley/go-metrics/registry.go index 9086dcbdd1..2bb7a1e7d0 100644 --- a/vendor/github.com/rcrowley/go-metrics/registry.go +++ b/vendor/github.com/rcrowley/go-metrics/registry.go @@ -167,9 +167,9 @@ func NewPrefixedChildRegistry(parent Registry, prefix string) Registry { // Call the given function for each registered metric. func (r *PrefixedRegistry) Each(fn func(string, interface{})) { - wrappedFn := func (prefix string) func(string, interface{}) { + wrappedFn := func(prefix string) func(string, interface{}) { return func(name string, iface interface{}) { - if strings.HasPrefix(name,prefix) { + if strings.HasPrefix(name, prefix) { fn(name, iface) } else { return @@ -184,7 +184,7 @@ func (r *PrefixedRegistry) Each(fn func(string, interface{})) { func findPrefix(registry Registry, prefix string) (Registry, string) { switch r := registry.(type) { case *PrefixedRegistry: - return findPrefix(r.underlying, r.prefix + prefix) + return findPrefix(r.underlying, r.prefix+prefix) case *StandardRegistry: return r, prefix } diff --git a/vendor/github.com/rcrowley/go-metrics/sample.go b/vendor/github.com/rcrowley/go-metrics/sample.go index 5f6a37788e..fecee5ef68 100644 --- a/vendor/github.com/rcrowley/go-metrics/sample.go +++ b/vendor/github.com/rcrowley/go-metrics/sample.go @@ -33,7 +33,7 @@ type Sample interface { // priority reservoir. See Cormode et al's "Forward Decay: A Practical Time // Decay Model for Streaming Systems". // -// +// type ExpDecaySample struct { alpha float64 count int64 @@ -302,6 +302,13 @@ type SampleSnapshot struct { values []int64 } +func NewSampleSnapshot(count int64, values []int64) *SampleSnapshot { + return &SampleSnapshot{ + count: count, + values: values, + } +} + // Clear panics. func (*SampleSnapshot) Clear() { panic("Clear called on a SampleSnapshot") diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/session.go b/vendor/github.com/syndtr/goleveldb/leveldb/session.go index f3e7477018..ad68a87039 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/session.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/session.go @@ -47,6 +47,7 @@ type session struct { o *cachedOptions icmp *iComparer tops *tOps + fileRef map[int64]int manifest *journal.Writer manifestWriter storage.Writer @@ -69,6 +70,7 @@ func newSession(stor storage.Storage, o *opt.Options) (s *session, err error) { s = &session{ stor: stor, storLock: storLock, + fileRef: make(map[int64]int), } s.setOptions(o) s.tops = newTableOps(s) diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go b/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go index 34ad617984..92328933cc 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/session_util.go @@ -39,6 +39,18 @@ func (s *session) newTemp() storage.FileDesc { return storage.FileDesc{storage.TypeTemp, num} } +func (s *session) addFileRef(fd storage.FileDesc, ref int) int { + ref += s.fileRef[fd.Num] + if ref > 0 { + s.fileRef[fd.Num] = ref + } else if ref == 0 { + delete(s.fileRef, fd.Num) + } else { + panic(fmt.Sprintf("negative ref: %v", fd)) + } + return ref +} + // Session state. // Get current version. This will incr version ref, must call @@ -46,7 +58,7 @@ func (s *session) newTemp() storage.FileDesc { func (s *session) version() *version { s.vmu.Lock() defer s.vmu.Unlock() - s.stVersion.ref++ + s.stVersion.incref() return s.stVersion } @@ -59,14 +71,15 @@ func (s *session) tLen(level int) int { // Set current version to v. func (s *session) setVersion(v *version) { s.vmu.Lock() - v.ref = 1 // Holds by session. - if old := s.stVersion; old != nil { - v.ref++ // Holds by old version. - old.next = v - old.releaseNB() + defer s.vmu.Unlock() + // Hold by session. It is important to call this first before releasing + // current version, otherwise the still used files might get released. + v.incref() + if s.stVersion != nil { + // Release current version. + s.stVersion.releaseNB() } s.stVersion = v - s.vmu.Unlock() } // Get current unused file number. diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/version.go b/vendor/github.com/syndtr/goleveldb/leveldb/version.go index c60f12c20b..73f272af5f 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/version.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/version.go @@ -34,44 +34,48 @@ type version struct { cSeek unsafe.Pointer - closing bool - ref int - // Succeeding version. - next *version + closing bool + ref int + released bool } func newVersion(s *session) *version { return &version{s: s} } +func (v *version) incref() { + if v.released { + panic("already released") + } + + v.ref++ + if v.ref == 1 { + // Incr file ref. + for _, tt := range v.levels { + for _, t := range tt { + v.s.addFileRef(t.fd, 1) + } + } + } +} + func (v *version) releaseNB() { v.ref-- if v.ref > 0 { return - } - if v.ref < 0 { + } else if v.ref < 0 { panic("negative version ref") } - nextTables := make(map[int64]bool) - for _, tt := range v.next.levels { - for _, t := range tt { - num := t.fd.Num - nextTables[num] = true - } - } - for _, tt := range v.levels { for _, t := range tt { - num := t.fd.Num - if _, ok := nextTables[num]; !ok { + if v.s.addFileRef(t.fd, -1) == 0 { v.s.tops.remove(t) } } } - v.next.releaseNB() - v.next = nil + v.released = true } func (v *version) release() { diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go index fd9bbd29b3..68b14c6ae6 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ b/vendor/golang.org/x/crypto/openpgp/keys.go @@ -307,8 +307,6 @@ func readToNextPublicKey(packets *packet.Reader) (err error) { return } } - - panic("unreachable") } // ReadEntity reads an entity (public key, identities, subkeys etc) from the diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go index e2bde1111e..3eded93f04 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go @@ -273,8 +273,6 @@ func consumeAll(r io.Reader) (n int64, err error) { return } } - - panic("unreachable") } // packetType represents the numeric ids of the different OpenPGP packet types. See diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go index c769933cee..ead26233dd 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go @@ -540,7 +540,6 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro default: return errors.SignatureError("Unsupported public key algorithm used in signature") } - panic("unreachable") } // VerifySignatureV3 returns nil iff sig is a valid signature, made by this @@ -585,7 +584,6 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err default: panic("shouldn't happen") } - panic("unreachable") } // keySignatureHash returns a Hash of the message that needs to be signed for diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go index 26337f5aaf..5daf7b6cfd 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go @@ -216,7 +216,6 @@ func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (er // V3 public keys only support RSA. panic("shouldn't happen") } - panic("unreachable") } // VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this diff --git a/vendor/golang.org/x/net/websocket/websocket.go b/vendor/golang.org/x/net/websocket/websocket.go index a7731d9c97..e242c89a7a 100644 --- a/vendor/golang.org/x/net/websocket/websocket.go +++ b/vendor/golang.org/x/net/websocket/websocket.go @@ -4,6 +4,12 @@ // Package websocket implements a client and server for the WebSocket protocol // as specified in RFC 6455. +// +// This package currently lacks some features found in an alternative +// and more actively maintained WebSocket package: +// +// https://godoc.org/github.com/gorilla/websocket +// package websocket // import "golang.org/x/net/websocket" import ( diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s new file mode 100644 index 0000000000..2ea425755e --- /dev/null +++ b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s @@ -0,0 +1,31 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build mips mipsle +// +build !gccgo + +#include "textflag.h" + +// +// System calls for mips, Linux +// + +// Just jump to package syscall's implementation for all these functions. +// The runtime may know about them. + +TEXT ·Syscall(SB),NOSPLIT,$0-28 + JMP syscall·Syscall(SB) + +TEXT ·Syscall6(SB),NOSPLIT,$0-40 + JMP syscall·Syscall6(SB) + +TEXT ·Syscall9(SB),NOSPLIT,$0-52 + JMP syscall·Syscall9(SB) + +TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + JMP syscall·RawSyscall(SB) + +TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + JMP syscall·RawSyscall6(SB) diff --git a/vendor/golang.org/x/sys/unix/flock_linux_32bit.go b/vendor/golang.org/x/sys/unix/flock_linux_32bit.go index 362831c3f7..fc0e50e037 100644 --- a/vendor/golang.org/x/sys/unix/flock_linux_32bit.go +++ b/vendor/golang.org/x/sys/unix/flock_linux_32bit.go @@ -1,4 +1,4 @@ -// +build linux,386 linux,arm +// +build linux,386 linux,arm linux,mips linux,mipsle // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 33b7922bdd..7e6276b9c3 100755 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -128,6 +128,7 @@ includes_Linux=' #include #include #include +#include #include #include @@ -339,6 +340,7 @@ ccflags="$@" $2 !~ /^(BPF_TIMEVAL)$/ && $2 ~ /^(BPF|DLT)_/ || $2 ~ /^CLOCK_/ || + $2 ~ /^CAN_/ || $2 !~ "WMESGLEN" && $2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)} $2 ~ /^__WCOREFLAG$/ {next} diff --git a/vendor/golang.org/x/sys/unix/mksysnum_linux.pl b/vendor/golang.org/x/sys/unix/mksysnum_linux.pl index 4d4017deb2..52b16139e3 100755 --- a/vendor/golang.org/x/sys/unix/mksysnum_linux.pl +++ b/vendor/golang.org/x/sys/unix/mksysnum_linux.pl @@ -23,6 +23,8 @@ package unix const( EOF +my $offset = 0; + sub fmt { my ($name, $num) = @_; if($num > 999){ @@ -31,13 +33,18 @@ sub fmt { return; } $name =~ y/a-z/A-Z/; + $num = $num + $offset; print " SYS_$name = $num;\n"; } my $prev; open(GCC, "gcc -E -dD $ARGV[0] |") || die "can't run gcc"; while(){ - if(/^#define __NR_syscalls\s+/) { + if(/^#define __NR_Linux\s+([0-9]+)/){ + # mips/mips64: extract offset + $offset = $1; + } + elsif(/^#define __NR_syscalls\s+/) { # ignore redefinitions of __NR_syscalls } elsif(/^#define __NR_(\w+)\s+([0-9]+)/){ @@ -51,6 +58,9 @@ while(){ elsif(/^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)/){ fmt($1, $prev+$2) } + elsif(/^#define __NR_(\w+)\s+\(__NR_Linux \+ ([0-9]+)/){ + fmt($1, $2); + } } print < 0 && buf[n-1] == '\x00' { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index cfac4a4409..01c569ad5f 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -411,6 +411,47 @@ func (sa *SockaddrHCI) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), SizeofSockaddrHCI, nil } +// SockaddrCAN implements the Sockaddr interface for AF_CAN type sockets. +// The RxID and TxID fields are used for transport protocol addressing in +// (CAN_TP16, CAN_TP20, CAN_MCNET, and CAN_ISOTP), they can be left with +// zero values for CAN_RAW and CAN_BCM sockets as they have no meaning. +// +// The SockaddrCAN struct must be bound to the socket file descriptor +// using Bind before the CAN socket can be used. +// +// // Read one raw CAN frame +// fd, _ := Socket(AF_CAN, SOCK_RAW, CAN_RAW) +// addr := &SockaddrCAN{Ifindex: index} +// Bind(fd, addr) +// frame := make([]byte, 16) +// Read(fd, frame) +// +// The full SocketCAN documentation can be found in the linux kernel +// archives at: https://www.kernel.org/doc/Documentation/networking/can.txt +type SockaddrCAN struct { + Ifindex int + RxID uint32 + TxID uint32 + raw RawSockaddrCAN +} + +func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) { + if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff { + return nil, 0, EINVAL + } + sa.raw.Family = AF_CAN + sa.raw.Ifindex = int32(sa.Ifindex) + rx := (*[4]byte)(unsafe.Pointer(&sa.RxID)) + for i := 0; i < 4; i++ { + sa.raw.Addr[i] = rx[i] + } + tx := (*[4]byte)(unsafe.Pointer(&sa.TxID)) + for i := 0; i < 4; i++ { + sa.raw.Addr[i+4] = tx[i] + } + return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil +} + func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) { switch rsa.Addr.Family { case AF_NETLINK: @@ -899,6 +940,7 @@ func Getpgrp() (pid int) { //sysnb Getppid() (ppid int) //sys Getpriority(which int, who int) (prio int, err error) //sysnb Getrusage(who int, rusage *Rusage) (err error) +//sysnb Getsid(pid int) (sid int, err error) //sysnb Gettid() (tid int) //sys Getxattr(path string, attr string, dest []byte) (sz int, err error) //sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) @@ -911,7 +953,7 @@ func Getpgrp() (pid int) { //sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error) //sys Nanosleep(time *Timespec, leftover *Timespec) (err error) //sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT -//sysnb prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) = SYS_PRLIMIT64 +//sysnb prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 //sys Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) //sys read(fd int, p []byte) (n int, err error) //sys Removexattr(path string, attr string) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go index 18911c2d98..9516a3fd7e 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go @@ -6,8 +6,6 @@ package unix -import "syscall" - //sys Dup2(oldfd int, newfd int) (err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 @@ -63,9 +61,6 @@ import "syscall" //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) -//go:noescape -func gettimeofday(tv *Timeval) (err syscall.Errno) - func Gettimeofday(tv *Timeval) (err error) { errno := gettimeofday(tv) if errno != 0 { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go new file mode 100644 index 0000000000..21a4946ba5 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go @@ -0,0 +1,13 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,linux +// +build !gccgo + +package unix + +import "syscall" + +//go:noescape +func gettimeofday(tv *Timeval) (err syscall.Errno) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go new file mode 100644 index 0000000000..5ed801369d --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go @@ -0,0 +1,241 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build mips mipsle + +package unix + +import ( + "syscall" + "unsafe" +) + +func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) + +//sys Dup2(oldfd int, newfd int) (err error) +//sys Fchown(fd int, uid int, gid int) (err error) +//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 +//sysnb Getegid() (egid int) +//sysnb Geteuid() (euid int) +//sysnb Getgid() (gid int) +//sysnb Getuid() (uid int) +//sys Lchown(path string, uid int, gid int) (err error) +//sys Listen(s int, n int) (err error) +//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64 +//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64 +//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT +//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64 +//sys Setfsgid(gid int) (err error) +//sys Setfsuid(uid int) (err error) +//sysnb Setregid(rgid int, egid int) (err error) +//sysnb Setresgid(rgid int, egid int, sgid int) (err error) +//sysnb Setresuid(ruid int, euid int, suid int) (err error) + +//sysnb Setreuid(ruid int, euid int) (err error) +//sys Shutdown(fd int, how int) (err error) +//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) + +//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) +//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 +//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) +//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) +//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) +//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) +//sysnb setgroups(n int, list *_Gid_t) (err error) +//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) +//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) +//sysnb socket(domain int, typ int, proto int) (fd int, err error) +//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) +//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) +//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) +//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) +//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) +//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) + +//sysnb InotifyInit() (fd int, err error) +//sys Ioperm(from int, num int, on int) (err error) +//sys Iopl(level int) (err error) + +//sysnb Gettimeofday(tv *Timeval) (err error) +//sysnb Time(t *Time_t) (tt Time_t, err error) + +//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 +//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 +//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 + +//sys Utime(path string, buf *Utimbuf) (err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) +//sys Pause() (err error) + +func Fstatfs(fd int, buf *Statfs_t) (err error) { + _, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) + use(unsafe.Pointer(buf)) + if e != 0 { + err = errnoErr(e) + } + return +} + +func Statfs(path string, buf *Statfs_t) (err error) { + p, err := BytePtrFromString(path) + if err != nil { + return err + } + _, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(p)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) + use(unsafe.Pointer(p)) + if e != 0 { + err = errnoErr(e) + } + return +} + +func Seek(fd int, offset int64, whence int) (off int64, err error) { + _, _, e := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offset>>32), uintptr(offset), uintptr(unsafe.Pointer(&off)), uintptr(whence), 0) + if e != 0 { + err = errnoErr(e) + } + return +} + +func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } + +func NsecToTimespec(nsec int64) (ts Timespec) { + ts.Sec = int32(nsec / 1e9) + ts.Nsec = int32(nsec % 1e9) + return +} + +func NsecToTimeval(nsec int64) (tv Timeval) { + nsec += 999 // round up to microsecond + tv.Sec = int32(nsec / 1e9) + tv.Usec = int32(nsec % 1e9 / 1e3) + return +} + +//sysnb pipe2(p *[2]_C_int, flags int) (err error) + +func Pipe2(p []int, flags int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe2(&pp, flags) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +func Pipe(p []int) (err error) { + if len(p) != 2 { + return EINVAL + } + var pp [2]_C_int + err = pipe2(&pp, 0) + p[0] = int(pp[0]) + p[1] = int(pp[1]) + return +} + +//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) + +func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { + page := uintptr(offset / 4096) + if offset != int64(page)*4096 { + return 0, EINVAL + } + return mmap2(addr, length, prot, flags, fd, page) +} + +const rlimInf32 = ^uint32(0) +const rlimInf64 = ^uint64(0) + +type rlimit32 struct { + Cur uint32 + Max uint32 +} + +//sysnb getrlimit(resource int, rlim *rlimit32) (err error) = SYS_GETRLIMIT + +func Getrlimit(resource int, rlim *Rlimit) (err error) { + err = prlimit(0, resource, nil, rlim) + if err != ENOSYS { + return err + } + + rl := rlimit32{} + err = getrlimit(resource, &rl) + if err != nil { + return + } + + if rl.Cur == rlimInf32 { + rlim.Cur = rlimInf64 + } else { + rlim.Cur = uint64(rl.Cur) + } + + if rl.Max == rlimInf32 { + rlim.Max = rlimInf64 + } else { + rlim.Max = uint64(rl.Max) + } + return +} + +//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT + +func Setrlimit(resource int, rlim *Rlimit) (err error) { + err = prlimit(0, resource, rlim, nil) + if err != ENOSYS { + return err + } + + rl := rlimit32{} + if rlim.Cur == rlimInf64 { + rl.Cur = rlimInf32 + } else if rlim.Cur < uint64(rlimInf32) { + rl.Cur = uint32(rlim.Cur) + } else { + return EINVAL + } + if rlim.Max == rlimInf64 { + rl.Max = rlimInf32 + } else if rlim.Max < uint64(rlimInf32) { + rl.Max = uint32(rlim.Max) + } else { + return EINVAL + } + + return setrlimit(resource, &rl) +} + +func (r *PtraceRegs) PC() uint64 { return uint64(r.Regs[64]) } + +func (r *PtraceRegs) SetPC(pc uint64) { r.Regs[64] = uint32(pc) } + +func (iov *Iovec) SetLen(length int) { + iov.Len = uint32(length) +} + +func (msghdr *Msghdr) SetControllen(length int) { + msghdr.Controllen = uint32(length) +} + +func (cmsg *Cmsghdr) SetLen(length int) { + cmsg.Len = uint32(length) +} + +//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) + +func Poll(fds []PollFd, timeout int) (n int, err error) { + if len(fds) == 0 { + return poll(nil, 0, timeout) + } + return poll(&fds[0], len(fds), timeout) +} + +func Getpagesize() int { return 4096 } diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go index b46b25028c..8a5237de8a 100644 --- a/vendor/golang.org/x/sys/unix/syscall_unix.go +++ b/vendor/golang.org/x/sys/unix/syscall_unix.go @@ -49,11 +49,6 @@ func errnoErr(e syscall.Errno) error { return e } -func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) -func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) -func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) -func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) - // Mmap manager, for use by operating system-specific implementations. type mmapper struct { diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_gc.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go new file mode 100644 index 0000000000..4cb8e8edf1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris +// +build !gccgo + +package unix + +import "syscall" + +func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) +func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) +func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) +func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) diff --git a/vendor/golang.org/x/sys/unix/types_linux.go b/vendor/golang.org/x/sys/unix/types_linux.go index de80e2c8c0..f3d8f90ee2 100644 --- a/vendor/golang.org/x/sys/unix/types_linux.go +++ b/vendor/golang.org/x/sys/unix/types_linux.go @@ -58,6 +58,7 @@ package unix #include #include #include +#include #ifdef TCSETS2 // On systems that have "struct termios2" use this as type Termios. @@ -125,7 +126,7 @@ typedef struct {} ptracePer; // The real epoll_event is a union, and godefs doesn't handle it well. struct my_epoll_event { uint32_t events; -#if defined(__ARM_EABI__) || defined(__aarch64__) +#if defined(__ARM_EABI__) || defined(__aarch64__) || (defined(__mips__) && _MIPS_SIM == _ABIO32) // padding is not specified in linux/eventpoll.h but added to conform to the // alignment requirements of EABI int32_t padFd; @@ -218,6 +219,8 @@ type RawSockaddrNetlink C.struct_sockaddr_nl type RawSockaddrHCI C.struct_sockaddr_hci +type RawSockaddrCAN C.struct_sockaddr_can + type RawSockaddr C.struct_sockaddr type RawSockaddrAny C.struct_sockaddr_any @@ -258,6 +261,7 @@ const ( SizeofSockaddrLinklayer = C.sizeof_struct_sockaddr_ll SizeofSockaddrNetlink = C.sizeof_struct_sockaddr_nl SizeofSockaddrHCI = C.sizeof_struct_sockaddr_hci + SizeofSockaddrCAN = C.sizeof_struct_sockaddr_can SizeofLinger = C.sizeof_struct_linger SizeofIPMreq = C.sizeof_struct_ip_mreq SizeofIPMreqn = C.sizeof_struct_ip_mreqn diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 8f920124b8..b40d0299b5 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -190,6 +190,25 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 49b6c35467..9f0600ccbd 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -190,6 +190,25 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index f036758f92..647a796e39 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -186,6 +186,25 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 16dcbc9cb2..a6d1e1fa34 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -196,6 +196,25 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go new file mode 100644 index 0000000000..e4fb9ad579 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -0,0 +1,1814 @@ +// mkerrors.sh +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// +build mips,linux + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs -- _const.go + +package unix + +import "syscall" + +const ( + AF_ALG = 0x26 + AF_APPLETALK = 0x5 + AF_ASH = 0x12 + AF_ATMPVC = 0x8 + AF_ATMSVC = 0x14 + AF_AX25 = 0x3 + AF_BLUETOOTH = 0x1f + AF_BRIDGE = 0x7 + AF_CAIF = 0x25 + AF_CAN = 0x1d + AF_DECnet = 0xc + AF_ECONET = 0x13 + AF_FILE = 0x1 + AF_IEEE802154 = 0x24 + AF_INET = 0x2 + AF_INET6 = 0xa + AF_IPX = 0x4 + AF_IRDA = 0x17 + AF_ISDN = 0x22 + AF_IUCV = 0x20 + AF_KEY = 0xf + AF_LLC = 0x1a + AF_LOCAL = 0x1 + AF_MAX = 0x27 + AF_NETBEUI = 0xd + AF_NETLINK = 0x10 + AF_NETROM = 0x6 + AF_PACKET = 0x11 + AF_PHONET = 0x23 + AF_PPPOX = 0x18 + AF_RDS = 0x15 + AF_ROSE = 0xb + AF_ROUTE = 0x10 + AF_RXRPC = 0x21 + AF_SECURITY = 0xe + AF_SNA = 0x16 + AF_TIPC = 0x1e + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + AF_WANPIPE = 0x19 + AF_X25 = 0x9 + ARPHRD_ADAPT = 0x108 + ARPHRD_APPLETLK = 0x8 + ARPHRD_ARCNET = 0x7 + ARPHRD_ASH = 0x30d + ARPHRD_ATM = 0x13 + ARPHRD_AX25 = 0x3 + ARPHRD_BIF = 0x307 + ARPHRD_CAIF = 0x336 + ARPHRD_CAN = 0x118 + ARPHRD_CHAOS = 0x5 + ARPHRD_CISCO = 0x201 + ARPHRD_CSLIP = 0x101 + ARPHRD_CSLIP6 = 0x103 + ARPHRD_DDCMP = 0x205 + ARPHRD_DLCI = 0xf + ARPHRD_ECONET = 0x30e + ARPHRD_EETHER = 0x2 + ARPHRD_ETHER = 0x1 + ARPHRD_EUI64 = 0x1b + ARPHRD_FCAL = 0x311 + ARPHRD_FCFABRIC = 0x313 + ARPHRD_FCPL = 0x312 + ARPHRD_FCPP = 0x310 + ARPHRD_FDDI = 0x306 + ARPHRD_FRAD = 0x302 + ARPHRD_HDLC = 0x201 + ARPHRD_HIPPI = 0x30c + ARPHRD_HWX25 = 0x110 + ARPHRD_IEEE1394 = 0x18 + ARPHRD_IEEE802 = 0x6 + ARPHRD_IEEE80211 = 0x321 + ARPHRD_IEEE80211_PRISM = 0x322 + ARPHRD_IEEE80211_RADIOTAP = 0x323 + ARPHRD_IEEE802154 = 0x324 + ARPHRD_IEEE802_TR = 0x320 + ARPHRD_INFINIBAND = 0x20 + ARPHRD_IPDDP = 0x309 + ARPHRD_IPGRE = 0x30a + ARPHRD_IRDA = 0x30f + ARPHRD_LAPB = 0x204 + ARPHRD_LOCALTLK = 0x305 + ARPHRD_LOOPBACK = 0x304 + ARPHRD_METRICOM = 0x17 + ARPHRD_NETROM = 0x0 + ARPHRD_NONE = 0xfffe + ARPHRD_PHONET = 0x334 + ARPHRD_PHONET_PIPE = 0x335 + ARPHRD_PIMREG = 0x30b + ARPHRD_PPP = 0x200 + ARPHRD_PRONET = 0x4 + ARPHRD_RAWHDLC = 0x206 + ARPHRD_ROSE = 0x10e + ARPHRD_RSRVD = 0x104 + ARPHRD_SIT = 0x308 + ARPHRD_SKIP = 0x303 + ARPHRD_SLIP = 0x100 + ARPHRD_SLIP6 = 0x102 + ARPHRD_TUNNEL = 0x300 + ARPHRD_TUNNEL6 = 0x301 + ARPHRD_VOID = 0xffff + ARPHRD_X25 = 0x10f + B0 = 0x0 + B1000000 = 0x1008 + B110 = 0x3 + B115200 = 0x1002 + B1152000 = 0x1009 + B1200 = 0x9 + B134 = 0x4 + B150 = 0x5 + B1500000 = 0x100a + B1800 = 0xa + B19200 = 0xe + B200 = 0x6 + B2000000 = 0x100b + B230400 = 0x1003 + B2400 = 0xb + B2500000 = 0x100c + B300 = 0x7 + B3000000 = 0x100d + B3500000 = 0x100e + B38400 = 0xf + B4000000 = 0x100f + B460800 = 0x1004 + B4800 = 0xc + B50 = 0x1 + B500000 = 0x1005 + B57600 = 0x1001 + B576000 = 0x1006 + B600 = 0x8 + B75 = 0x2 + B921600 = 0x1007 + B9600 = 0xd + BOTHER = 0x1000 + BPF_A = 0x10 + BPF_ABS = 0x20 + BPF_ADD = 0x0 + BPF_ALU = 0x4 + BPF_AND = 0x50 + BPF_B = 0x10 + BPF_DIV = 0x30 + BPF_H = 0x8 + BPF_IMM = 0x0 + BPF_IND = 0x40 + BPF_JA = 0x0 + BPF_JEQ = 0x10 + BPF_JGE = 0x30 + BPF_JGT = 0x20 + BPF_JMP = 0x5 + BPF_JSET = 0x40 + BPF_K = 0x0 + BPF_LD = 0x0 + BPF_LDX = 0x1 + BPF_LEN = 0x80 + BPF_LSH = 0x60 + BPF_MAJOR_VERSION = 0x1 + BPF_MAXINSNS = 0x1000 + BPF_MEM = 0x60 + BPF_MEMWORDS = 0x10 + BPF_MINOR_VERSION = 0x1 + BPF_MISC = 0x7 + BPF_MSH = 0xa0 + BPF_MUL = 0x20 + BPF_NEG = 0x80 + BPF_OR = 0x40 + BPF_RET = 0x6 + BPF_RSH = 0x70 + BPF_ST = 0x2 + BPF_STX = 0x3 + BPF_SUB = 0x10 + BPF_TAX = 0x0 + BPF_TXA = 0x80 + BPF_W = 0x0 + BPF_X = 0x8 + BRKINT = 0x2 + BS0 = 0x0 + BS1 = 0x2000 + BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MCNET = 0x5 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 + CBAUD = 0x100f + CBAUDEX = 0x1000 + CFLUSH = 0xf + CIBAUD = 0x100f0000 + CLOCAL = 0x800 + CLOCK_DEFAULT = 0x0 + CLOCK_EXT = 0x1 + CLOCK_INT = 0x2 + CLOCK_MONOTONIC = 0x1 + CLOCK_MONOTONIC_COARSE = 0x6 + CLOCK_MONOTONIC_RAW = 0x4 + CLOCK_PROCESS_CPUTIME_ID = 0x2 + CLOCK_REALTIME = 0x0 + CLOCK_REALTIME_COARSE = 0x5 + CLOCK_THREAD_CPUTIME_ID = 0x3 + CLOCK_TXFROMRX = 0x4 + CLOCK_TXINT = 0x3 + CLONE_CHILD_CLEARTID = 0x200000 + CLONE_CHILD_SETTID = 0x1000000 + CLONE_DETACHED = 0x400000 + CLONE_FILES = 0x400 + CLONE_FS = 0x200 + CLONE_IO = 0x80000000 + CLONE_NEWIPC = 0x8000000 + CLONE_NEWNET = 0x40000000 + CLONE_NEWNS = 0x20000 + CLONE_NEWPID = 0x20000000 + CLONE_NEWUSER = 0x10000000 + CLONE_NEWUTS = 0x4000000 + CLONE_PARENT = 0x8000 + CLONE_PARENT_SETTID = 0x100000 + CLONE_PTRACE = 0x2000 + CLONE_SETTLS = 0x80000 + CLONE_SIGHAND = 0x800 + CLONE_SYSVSEM = 0x40000 + CLONE_THREAD = 0x10000 + CLONE_UNTRACED = 0x800000 + CLONE_VFORK = 0x4000 + CLONE_VM = 0x100 + CMSPAR = 0x40000000 + CR0 = 0x0 + CR1 = 0x200 + CR2 = 0x400 + CR3 = 0x600 + CRDLY = 0x600 + CREAD = 0x80 + CRTSCTS = 0x80000000 + CS5 = 0x0 + CS6 = 0x10 + CS7 = 0x20 + CS8 = 0x30 + CSIGNAL = 0xff + CSIZE = 0x30 + CSTART = 0x11 + CSTATUS = 0x0 + CSTOP = 0x13 + CSTOPB = 0x40 + CSUSP = 0x1a + DT_BLK = 0x6 + DT_CHR = 0x2 + DT_DIR = 0x4 + DT_FIFO = 0x1 + DT_LNK = 0xa + DT_REG = 0x8 + DT_SOCK = 0xc + DT_UNKNOWN = 0x0 + DT_WHT = 0xe + ECHO = 0x8 + ECHOCTL = 0x200 + ECHOE = 0x10 + ECHOK = 0x20 + ECHOKE = 0x800 + ECHONL = 0x40 + ECHOPRT = 0x400 + ENCODING_DEFAULT = 0x0 + ENCODING_FM_MARK = 0x3 + ENCODING_FM_SPACE = 0x4 + ENCODING_MANCHESTER = 0x5 + ENCODING_NRZ = 0x1 + ENCODING_NRZI = 0x2 + EPOLLERR = 0x8 + EPOLLET = -0x80000000 + EPOLLHUP = 0x10 + EPOLLIN = 0x1 + EPOLLMSG = 0x400 + EPOLLONESHOT = 0x40000000 + EPOLLOUT = 0x4 + EPOLLPRI = 0x2 + EPOLLRDBAND = 0x80 + EPOLLRDHUP = 0x2000 + EPOLLRDNORM = 0x40 + EPOLLWRBAND = 0x200 + EPOLLWRNORM = 0x100 + EPOLL_CLOEXEC = 0x80000 + EPOLL_CTL_ADD = 0x1 + EPOLL_CTL_DEL = 0x2 + EPOLL_CTL_MOD = 0x3 + EPOLL_NONBLOCK = 0x80 + ETH_P_1588 = 0x88f7 + ETH_P_8021AD = 0x88a8 + ETH_P_8021AH = 0x88e7 + ETH_P_8021Q = 0x8100 + ETH_P_802_2 = 0x4 + ETH_P_802_3 = 0x1 + ETH_P_AARP = 0x80f3 + ETH_P_AF_IUCV = 0xfbfb + ETH_P_ALL = 0x3 + ETH_P_AOE = 0x88a2 + ETH_P_ARCNET = 0x1a + ETH_P_ARP = 0x806 + ETH_P_ATALK = 0x809b + ETH_P_ATMFATE = 0x8884 + ETH_P_ATMMPOA = 0x884c + ETH_P_AX25 = 0x2 + ETH_P_BPQ = 0x8ff + ETH_P_CAIF = 0xf7 + ETH_P_CAN = 0xc + ETH_P_CONTROL = 0x16 + ETH_P_CUST = 0x6006 + ETH_P_DDCMP = 0x6 + ETH_P_DEC = 0x6000 + ETH_P_DIAG = 0x6005 + ETH_P_DNA_DL = 0x6001 + ETH_P_DNA_RC = 0x6002 + ETH_P_DNA_RT = 0x6003 + ETH_P_DSA = 0x1b + ETH_P_ECONET = 0x18 + ETH_P_EDSA = 0xdada + ETH_P_FCOE = 0x8906 + ETH_P_FIP = 0x8914 + ETH_P_HDLC = 0x19 + ETH_P_IEEE802154 = 0xf6 + ETH_P_IEEEPUP = 0xa00 + ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IP = 0x800 + ETH_P_IPV6 = 0x86dd + ETH_P_IPX = 0x8137 + ETH_P_IRDA = 0x17 + ETH_P_LAT = 0x6004 + ETH_P_LINK_CTL = 0x886c + ETH_P_LOCALTALK = 0x9 + ETH_P_LOOP = 0x60 + ETH_P_MOBITEX = 0x15 + ETH_P_MPLS_MC = 0x8848 + ETH_P_MPLS_UC = 0x8847 + ETH_P_PAE = 0x888e + ETH_P_PAUSE = 0x8808 + ETH_P_PHONET = 0xf5 + ETH_P_PPPTALK = 0x10 + ETH_P_PPP_DISC = 0x8863 + ETH_P_PPP_MP = 0x8 + ETH_P_PPP_SES = 0x8864 + ETH_P_PUP = 0x200 + ETH_P_PUPAT = 0x201 + ETH_P_QINQ1 = 0x9100 + ETH_P_QINQ2 = 0x9200 + ETH_P_QINQ3 = 0x9300 + ETH_P_RARP = 0x8035 + ETH_P_SCA = 0x6007 + ETH_P_SLOW = 0x8809 + ETH_P_SNAP = 0x5 + ETH_P_TDLS = 0x890d + ETH_P_TEB = 0x6558 + ETH_P_TIPC = 0x88ca + ETH_P_TRAILER = 0x1c + ETH_P_TR_802_2 = 0x11 + ETH_P_WAN_PPP = 0x7 + ETH_P_WCCP = 0x883e + ETH_P_X25 = 0x805 + EXTA = 0xe + EXTB = 0xf + EXTPROC = 0x10000 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0x400 + FF0 = 0x0 + FF1 = 0x8000 + FFDLY = 0x8000 + FLUSHO = 0x2000 + F_DUPFD = 0x0 + F_DUPFD_CLOEXEC = 0x406 + F_EXLCK = 0x4 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLEASE = 0x401 + F_GETLK = 0x21 + F_GETLK64 = 0x21 + F_GETOWN = 0x17 + F_GETOWN_EX = 0x10 + F_GETPIPE_SZ = 0x408 + F_GETSIG = 0xb + F_LOCK = 0x1 + F_NOTIFY = 0x402 + F_OK = 0x0 + F_RDLCK = 0x0 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLEASE = 0x400 + F_SETLK = 0x22 + F_SETLK64 = 0x22 + F_SETLKW = 0x23 + F_SETLKW64 = 0x23 + F_SETOWN = 0x18 + F_SETOWN_EX = 0xf + F_SETPIPE_SZ = 0x407 + F_SETSIG = 0xa + F_SHLCK = 0x8 + F_TEST = 0x3 + F_TLOCK = 0x2 + F_ULOCK = 0x0 + F_UNLCK = 0x2 + F_WRLCK = 0x1 + HUPCL = 0x400 + IBSHIFT = 0x10 + ICANON = 0x2 + ICMPV6_FILTER = 0x1 + ICRNL = 0x100 + IEXTEN = 0x100 + IFA_F_DADFAILED = 0x8 + IFA_F_DEPRECATED = 0x20 + IFA_F_HOMEADDRESS = 0x10 + IFA_F_NODAD = 0x2 + IFA_F_OPTIMISTIC = 0x4 + IFA_F_PERMANENT = 0x80 + IFA_F_SECONDARY = 0x1 + IFA_F_TEMPORARY = 0x1 + IFA_F_TENTATIVE = 0x40 + IFA_MAX = 0x7 + IFF_802_1Q_VLAN = 0x1 + IFF_ALLMULTI = 0x200 + IFF_AUTOMEDIA = 0x4000 + IFF_BONDING = 0x20 + IFF_BRIDGE_PORT = 0x4000 + IFF_BROADCAST = 0x2 + IFF_DEBUG = 0x4 + IFF_DISABLE_NETPOLL = 0x1000 + IFF_DONT_BRIDGE = 0x800 + IFF_DORMANT = 0x20000 + IFF_DYNAMIC = 0x8000 + IFF_EBRIDGE = 0x2 + IFF_ECHO = 0x40000 + IFF_ISATAP = 0x80 + IFF_LOOPBACK = 0x8 + IFF_LOWER_UP = 0x10000 + IFF_MACVLAN_PORT = 0x2000 + IFF_MASTER = 0x400 + IFF_MASTER_8023AD = 0x8 + IFF_MASTER_ALB = 0x10 + IFF_MASTER_ARPMON = 0x100 + IFF_MULTICAST = 0x1000 + IFF_NOARP = 0x80 + IFF_NOTRAILERS = 0x20 + IFF_NO_PI = 0x1000 + IFF_ONE_QUEUE = 0x2000 + IFF_OVS_DATAPATH = 0x8000 + IFF_POINTOPOINT = 0x10 + IFF_PORTSEL = 0x2000 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SLAVE = 0x800 + IFF_SLAVE_INACTIVE = 0x4 + IFF_SLAVE_NEEDARP = 0x40 + IFF_TAP = 0x2 + IFF_TUN = 0x1 + IFF_TUN_EXCL = 0x8000 + IFF_TX_SKB_SHARING = 0x10000 + IFF_UNICAST_FLT = 0x20000 + IFF_UP = 0x1 + IFF_VNET_HDR = 0x4000 + IFF_VOLATILE = 0x70c5a + IFF_WAN_HDLC = 0x200 + IFF_XMIT_DST_RELEASE = 0x400 + IFNAMSIZ = 0x10 + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x2000 + INLCR = 0x40 + INPCK = 0x10 + IN_ACCESS = 0x1 + IN_ALL_EVENTS = 0xfff + IN_ATTRIB = 0x4 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLOEXEC = 0x80000 + IN_CLOSE = 0x18 + IN_CLOSE_NOWRITE = 0x10 + IN_CLOSE_WRITE = 0x8 + IN_CREATE = 0x100 + IN_DELETE = 0x200 + IN_DELETE_SELF = 0x400 + IN_DONT_FOLLOW = 0x2000000 + IN_EXCL_UNLINK = 0x4000000 + IN_IGNORED = 0x8000 + IN_ISDIR = 0x40000000 + IN_LOOPBACKNET = 0x7f + IN_MASK_ADD = 0x20000000 + IN_MODIFY = 0x2 + IN_MOVE = 0xc0 + IN_MOVED_FROM = 0x40 + IN_MOVED_TO = 0x80 + IN_MOVE_SELF = 0x800 + IN_NONBLOCK = 0x80 + IN_ONESHOT = 0x80000000 + IN_ONLYDIR = 0x1000000 + IN_OPEN = 0x20 + IN_Q_OVERFLOW = 0x4000 + IN_UNMOUNT = 0x2000 + IPPROTO_AH = 0x33 + IPPROTO_COMP = 0x6c + IPPROTO_DCCP = 0x21 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_ENCAP = 0x62 + IPPROTO_ESP = 0x32 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GRE = 0x2f + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IGMP = 0x2 + IPPROTO_IP = 0x0 + IPPROTO_IPIP = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_MTP = 0x5c + IPPROTO_NONE = 0x3b + IPPROTO_PIM = 0x67 + IPPROTO_PUP = 0xc + IPPROTO_RAW = 0xff + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_SCTP = 0x84 + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_UDP = 0x11 + IPPROTO_UDPLITE = 0x88 + IPV6_2292DSTOPTS = 0x4 + IPV6_2292HOPLIMIT = 0x8 + IPV6_2292HOPOPTS = 0x3 + IPV6_2292PKTINFO = 0x2 + IPV6_2292PKTOPTIONS = 0x6 + IPV6_2292RTHDR = 0x5 + IPV6_ADDRFORM = 0x1 + IPV6_ADD_MEMBERSHIP = 0x14 + IPV6_AUTHHDR = 0xa + IPV6_CHECKSUM = 0x7 + IPV6_DROP_MEMBERSHIP = 0x15 + IPV6_DSTOPTS = 0x3b + IPV6_HOPLIMIT = 0x34 + IPV6_HOPOPTS = 0x36 + IPV6_IPSEC_POLICY = 0x22 + IPV6_JOIN_ANYCAST = 0x1b + IPV6_JOIN_GROUP = 0x14 + IPV6_LEAVE_ANYCAST = 0x1c + IPV6_LEAVE_GROUP = 0x15 + IPV6_MTU = 0x18 + IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_HOPS = 0x12 + IPV6_MULTICAST_IF = 0x11 + IPV6_MULTICAST_LOOP = 0x13 + IPV6_NEXTHOP = 0x9 + IPV6_PKTINFO = 0x32 + IPV6_PMTUDISC_DO = 0x2 + IPV6_PMTUDISC_DONT = 0x0 + IPV6_PMTUDISC_PROBE = 0x3 + IPV6_PMTUDISC_WANT = 0x1 + IPV6_RECVDSTOPTS = 0x3a + IPV6_RECVERR = 0x19 + IPV6_RECVHOPLIMIT = 0x33 + IPV6_RECVHOPOPTS = 0x35 + IPV6_RECVPKTINFO = 0x31 + IPV6_RECVRTHDR = 0x38 + IPV6_RECVTCLASS = 0x42 + IPV6_ROUTER_ALERT = 0x16 + IPV6_RTHDR = 0x39 + IPV6_RTHDRDSTOPTS = 0x37 + IPV6_RTHDR_LOOSE = 0x0 + IPV6_RTHDR_STRICT = 0x1 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_RXDSTOPTS = 0x3b + IPV6_RXHOPOPTS = 0x36 + IPV6_TCLASS = 0x43 + IPV6_UNICAST_HOPS = 0x10 + IPV6_V6ONLY = 0x1a + IPV6_XFRM_POLICY = 0x23 + IP_ADD_MEMBERSHIP = 0x23 + IP_ADD_SOURCE_MEMBERSHIP = 0x27 + IP_BLOCK_SOURCE = 0x26 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DROP_MEMBERSHIP = 0x24 + IP_DROP_SOURCE_MEMBERSHIP = 0x28 + IP_FREEBIND = 0xf + IP_HDRINCL = 0x3 + IP_IPSEC_POLICY = 0x10 + IP_MAXPACKET = 0xffff + IP_MAX_MEMBERSHIPS = 0x14 + IP_MF = 0x2000 + IP_MINTTL = 0x15 + IP_MSFILTER = 0x29 + IP_MSS = 0x240 + IP_MTU = 0xe + IP_MTU_DISCOVER = 0xa + IP_MULTICAST_IF = 0x20 + IP_MULTICAST_LOOP = 0x22 + IP_MULTICAST_TTL = 0x21 + IP_OFFMASK = 0x1fff + IP_OPTIONS = 0x4 + IP_ORIGDSTADDR = 0x14 + IP_PASSSEC = 0x12 + IP_PKTINFO = 0x8 + IP_PKTOPTIONS = 0x9 + IP_PMTUDISC = 0xa + IP_PMTUDISC_DO = 0x2 + IP_PMTUDISC_DONT = 0x0 + IP_PMTUDISC_PROBE = 0x3 + IP_PMTUDISC_WANT = 0x1 + IP_RECVERR = 0xb + IP_RECVOPTS = 0x6 + IP_RECVORIGDSTADDR = 0x14 + IP_RECVRETOPTS = 0x7 + IP_RECVTOS = 0xd + IP_RECVTTL = 0xc + IP_RETOPTS = 0x7 + IP_RF = 0x8000 + IP_ROUTER_ALERT = 0x5 + IP_TOS = 0x1 + IP_TRANSPARENT = 0x13 + IP_TTL = 0x2 + IP_UNBLOCK_SOURCE = 0x25 + IP_XFRM_POLICY = 0x11 + ISIG = 0x1 + ISTRIP = 0x20 + IUCLC = 0x200 + IUTF8 = 0x4000 + IXANY = 0x800 + IXOFF = 0x1000 + IXON = 0x400 + LINUX_REBOOT_CMD_CAD_OFF = 0x0 + LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef + LINUX_REBOOT_CMD_HALT = 0xcdef0123 + LINUX_REBOOT_CMD_KEXEC = 0x45584543 + LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc + LINUX_REBOOT_CMD_RESTART = 0x1234567 + LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4 + LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2 + LINUX_REBOOT_MAGIC1 = 0xfee1dead + LINUX_REBOOT_MAGIC2 = 0x28121969 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_DOFORK = 0xb + MADV_DONTFORK = 0xa + MADV_DONTNEED = 0x4 + MADV_HUGEPAGE = 0xe + MADV_HWPOISON = 0x64 + MADV_MERGEABLE = 0xc + MADV_NOHUGEPAGE = 0xf + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_REMOVE = 0x9 + MADV_SEQUENTIAL = 0x2 + MADV_UNMERGEABLE = 0xd + MADV_WILLNEED = 0x3 + MAP_ANON = 0x800 + MAP_ANONYMOUS = 0x800 + MAP_DENYWRITE = 0x2000 + MAP_EXECUTABLE = 0x4000 + MAP_FILE = 0x0 + MAP_FIXED = 0x10 + MAP_GROWSDOWN = 0x1000 + MAP_LOCKED = 0x8000 + MAP_NONBLOCK = 0x20000 + MAP_NORESERVE = 0x400 + MAP_POPULATE = 0x10000 + MAP_PRIVATE = 0x2 + MAP_RENAME = 0x800 + MAP_SHARED = 0x1 + MAP_TYPE = 0xf + MCL_CURRENT = 0x1 + MCL_FUTURE = 0x2 + MNT_DETACH = 0x2 + MNT_EXPIRE = 0x4 + MNT_FORCE = 0x1 + MSG_CMSG_CLOEXEC = 0x40000000 + MSG_CONFIRM = 0x800 + MSG_CTRUNC = 0x8 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x40 + MSG_EOR = 0x80 + MSG_ERRQUEUE = 0x2000 + MSG_FASTOPEN = 0x20000000 + MSG_FIN = 0x200 + MSG_MORE = 0x8000 + MSG_NOSIGNAL = 0x4000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_PROXY = 0x10 + MSG_RST = 0x1000 + MSG_SYN = 0x400 + MSG_TRUNC = 0x20 + MSG_TRYHARD = 0x4 + MSG_WAITALL = 0x100 + MSG_WAITFORONE = 0x10000 + MS_ACTIVE = 0x40000000 + MS_ASYNC = 0x1 + MS_BIND = 0x1000 + MS_DIRSYNC = 0x80 + MS_INVALIDATE = 0x2 + MS_I_VERSION = 0x800000 + MS_KERNMOUNT = 0x400000 + MS_MANDLOCK = 0x40 + MS_MGC_MSK = 0xffff0000 + MS_MGC_VAL = 0xc0ed0000 + MS_MOVE = 0x2000 + MS_NOATIME = 0x400 + MS_NODEV = 0x4 + MS_NODIRATIME = 0x800 + MS_NOEXEC = 0x8 + MS_NOSUID = 0x2 + MS_NOUSER = -0x80000000 + MS_POSIXACL = 0x10000 + MS_PRIVATE = 0x40000 + MS_RDONLY = 0x1 + MS_REC = 0x4000 + MS_RELATIME = 0x200000 + MS_REMOUNT = 0x20 + MS_RMT_MASK = 0x800051 + MS_SHARED = 0x100000 + MS_SILENT = 0x8000 + MS_SLAVE = 0x80000 + MS_STRICTATIME = 0x1000000 + MS_SYNC = 0x4 + MS_SYNCHRONOUS = 0x10 + MS_UNBINDABLE = 0x20000 + NAME_MAX = 0xff + NETLINK_ADD_MEMBERSHIP = 0x1 + NETLINK_AUDIT = 0x9 + NETLINK_BROADCAST_ERROR = 0x4 + NETLINK_CONNECTOR = 0xb + NETLINK_CRYPTO = 0x15 + NETLINK_DNRTMSG = 0xe + NETLINK_DROP_MEMBERSHIP = 0x2 + NETLINK_ECRYPTFS = 0x13 + NETLINK_FIB_LOOKUP = 0xa + NETLINK_FIREWALL = 0x3 + NETLINK_GENERIC = 0x10 + NETLINK_INET_DIAG = 0x4 + NETLINK_IP6_FW = 0xd + NETLINK_ISCSI = 0x8 + NETLINK_KOBJECT_UEVENT = 0xf + NETLINK_NETFILTER = 0xc + NETLINK_NFLOG = 0x5 + NETLINK_NO_ENOBUFS = 0x5 + NETLINK_PKTINFO = 0x3 + NETLINK_RDMA = 0x14 + NETLINK_ROUTE = 0x0 + NETLINK_SCSITRANSPORT = 0x12 + NETLINK_SELINUX = 0x7 + NETLINK_UNUSED = 0x1 + NETLINK_USERSOCK = 0x2 + NETLINK_XFRM = 0x6 + NL0 = 0x0 + NL1 = 0x100 + NLA_ALIGNTO = 0x4 + NLA_F_NESTED = 0x8000 + NLA_F_NET_BYTEORDER = 0x4000 + NLA_HDRLEN = 0x4 + NLDLY = 0x100 + NLMSG_ALIGNTO = 0x4 + NLMSG_DONE = 0x3 + NLMSG_ERROR = 0x2 + NLMSG_HDRLEN = 0x10 + NLMSG_MIN_TYPE = 0x10 + NLMSG_NOOP = 0x1 + NLMSG_OVERRUN = 0x4 + NLM_F_ACK = 0x4 + NLM_F_APPEND = 0x800 + NLM_F_ATOMIC = 0x400 + NLM_F_CREATE = 0x400 + NLM_F_DUMP = 0x300 + NLM_F_DUMP_INTR = 0x10 + NLM_F_ECHO = 0x8 + NLM_F_EXCL = 0x200 + NLM_F_MATCH = 0x200 + NLM_F_MULTI = 0x2 + NLM_F_REPLACE = 0x100 + NLM_F_REQUEST = 0x1 + NLM_F_ROOT = 0x100 + NOFLSH = 0x80 + OCRNL = 0x8 + OFDEL = 0x80 + OFILL = 0x40 + OLCUC = 0x2 + ONLCR = 0x4 + ONLRET = 0x20 + ONOCR = 0x10 + OPOST = 0x1 + O_ACCMODE = 0x3 + O_APPEND = 0x8 + O_ASYNC = 0x1000 + O_CLOEXEC = 0x80000 + O_CREAT = 0x100 + O_DIRECT = 0x8000 + O_DIRECTORY = 0x10000 + O_DSYNC = 0x10 + O_EXCL = 0x400 + O_FSYNC = 0x4010 + O_LARGEFILE = 0x2000 + O_NDELAY = 0x80 + O_NOATIME = 0x40000 + O_NOCTTY = 0x800 + O_NOFOLLOW = 0x20000 + O_NONBLOCK = 0x80 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_RSYNC = 0x4010 + O_SYNC = 0x4010 + O_TRUNC = 0x200 + O_WRONLY = 0x1 + PACKET_ADD_MEMBERSHIP = 0x1 + PACKET_AUXDATA = 0x8 + PACKET_BROADCAST = 0x1 + PACKET_COPY_THRESH = 0x7 + PACKET_DROP_MEMBERSHIP = 0x2 + PACKET_FANOUT = 0x12 + PACKET_FANOUT_CPU = 0x2 + PACKET_FANOUT_FLAG_DEFRAG = 0x8000 + PACKET_FANOUT_HASH = 0x0 + PACKET_FANOUT_LB = 0x1 + PACKET_FASTROUTE = 0x6 + PACKET_HDRLEN = 0xb + PACKET_HOST = 0x0 + PACKET_LOOPBACK = 0x5 + PACKET_LOSS = 0xe + PACKET_MR_ALLMULTI = 0x2 + PACKET_MR_MULTICAST = 0x0 + PACKET_MR_PROMISC = 0x1 + PACKET_MR_UNICAST = 0x3 + PACKET_MULTICAST = 0x2 + PACKET_ORIGDEV = 0x9 + PACKET_OTHERHOST = 0x3 + PACKET_OUTGOING = 0x4 + PACKET_RECV_OUTPUT = 0x3 + PACKET_RESERVE = 0xc + PACKET_RX_RING = 0x5 + PACKET_STATISTICS = 0x6 + PACKET_TIMESTAMP = 0x11 + PACKET_TX_RING = 0xd + PACKET_TX_TIMESTAMP = 0x10 + PACKET_VERSION = 0xa + PACKET_VNET_HDR = 0xf + PARENB = 0x100 + PARITY_CRC16_PR0 = 0x2 + PARITY_CRC16_PR0_CCITT = 0x4 + PARITY_CRC16_PR1 = 0x3 + PARITY_CRC16_PR1_CCITT = 0x5 + PARITY_CRC32_PR0_CCITT = 0x6 + PARITY_CRC32_PR1_CCITT = 0x7 + PARITY_DEFAULT = 0x0 + PARITY_NONE = 0x1 + PARMRK = 0x8 + PARODD = 0x200 + PENDIN = 0x4000 + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROT_EXEC = 0x4 + PROT_GROWSDOWN = 0x1000000 + PROT_GROWSUP = 0x2000000 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + PR_CAPBSET_DROP = 0x18 + PR_CAPBSET_READ = 0x17 + PR_ENDIAN_BIG = 0x0 + PR_ENDIAN_LITTLE = 0x1 + PR_ENDIAN_PPC_LITTLE = 0x2 + PR_FPEMU_NOPRINT = 0x1 + PR_FPEMU_SIGFPE = 0x2 + PR_FP_EXC_ASYNC = 0x2 + PR_FP_EXC_DISABLED = 0x0 + PR_FP_EXC_DIV = 0x10000 + PR_FP_EXC_INV = 0x100000 + PR_FP_EXC_NONRECOV = 0x1 + PR_FP_EXC_OVF = 0x20000 + PR_FP_EXC_PRECISE = 0x3 + PR_FP_EXC_RES = 0x80000 + PR_FP_EXC_SW_ENABLE = 0x80 + PR_FP_EXC_UND = 0x40000 + PR_GET_DUMPABLE = 0x3 + PR_GET_ENDIAN = 0x13 + PR_GET_FPEMU = 0x9 + PR_GET_FPEXC = 0xb + PR_GET_KEEPCAPS = 0x7 + PR_GET_NAME = 0x10 + PR_GET_PDEATHSIG = 0x2 + PR_GET_SECCOMP = 0x15 + PR_GET_SECUREBITS = 0x1b + PR_GET_TIMERSLACK = 0x1e + PR_GET_TIMING = 0xd + PR_GET_TSC = 0x19 + PR_GET_UNALIGN = 0x5 + PR_MCE_KILL = 0x21 + PR_MCE_KILL_CLEAR = 0x0 + PR_MCE_KILL_DEFAULT = 0x2 + PR_MCE_KILL_EARLY = 0x1 + PR_MCE_KILL_GET = 0x22 + PR_MCE_KILL_LATE = 0x0 + PR_MCE_KILL_SET = 0x1 + PR_SET_DUMPABLE = 0x4 + PR_SET_ENDIAN = 0x14 + PR_SET_FPEMU = 0xa + PR_SET_FPEXC = 0xc + PR_SET_KEEPCAPS = 0x8 + PR_SET_NAME = 0xf + PR_SET_PDEATHSIG = 0x1 + PR_SET_SECCOMP = 0x16 + PR_SET_SECUREBITS = 0x1c + PR_SET_TIMERSLACK = 0x1d + PR_SET_TIMING = 0xe + PR_SET_TSC = 0x1a + PR_SET_UNALIGN = 0x6 + PR_TASK_PERF_EVENTS_DISABLE = 0x1f + PR_TASK_PERF_EVENTS_ENABLE = 0x20 + PR_TIMING_STATISTICAL = 0x0 + PR_TIMING_TIMESTAMP = 0x1 + PR_TSC_ENABLE = 0x1 + PR_TSC_SIGSEGV = 0x2 + PR_UNALIGN_NOPRINT = 0x1 + PR_UNALIGN_SIGBUS = 0x2 + PTRACE_ATTACH = 0x10 + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0x11 + PTRACE_EVENT_CLONE = 0x3 + PTRACE_EVENT_EXEC = 0x4 + PTRACE_EVENT_EXIT = 0x6 + PTRACE_EVENT_FORK = 0x1 + PTRACE_EVENT_STOP = 0x7 + PTRACE_EVENT_VFORK = 0x2 + PTRACE_EVENT_VFORK_DONE = 0x5 + PTRACE_GETEVENTMSG = 0x4201 + PTRACE_GETFPREGS = 0xe + PTRACE_GETREGS = 0xc + PTRACE_GETREGSET = 0x4204 + PTRACE_GETSIGINFO = 0x4202 + PTRACE_GET_THREAD_AREA = 0x19 + PTRACE_GET_THREAD_AREA_3264 = 0xc4 + PTRACE_GET_WATCH_REGS = 0xd0 + PTRACE_INTERRUPT = 0x4207 + PTRACE_KILL = 0x8 + PTRACE_LISTEN = 0x4208 + PTRACE_OLDSETOPTIONS = 0x15 + PTRACE_O_MASK = 0x7f + PTRACE_O_TRACECLONE = 0x8 + PTRACE_O_TRACEEXEC = 0x10 + PTRACE_O_TRACEEXIT = 0x40 + PTRACE_O_TRACEFORK = 0x2 + PTRACE_O_TRACESYSGOOD = 0x1 + PTRACE_O_TRACEVFORK = 0x4 + PTRACE_O_TRACEVFORKDONE = 0x20 + PTRACE_PEEKDATA = 0x2 + PTRACE_PEEKDATA_3264 = 0xc1 + PTRACE_PEEKTEXT = 0x1 + PTRACE_PEEKTEXT_3264 = 0xc0 + PTRACE_PEEKUSR = 0x3 + PTRACE_POKEDATA = 0x5 + PTRACE_POKEDATA_3264 = 0xc3 + PTRACE_POKETEXT = 0x4 + PTRACE_POKETEXT_3264 = 0xc2 + PTRACE_POKEUSR = 0x6 + PTRACE_SEIZE = 0x4206 + PTRACE_SEIZE_DEVEL = 0x80000000 + PTRACE_SETFPREGS = 0xf + PTRACE_SETOPTIONS = 0x4200 + PTRACE_SETREGS = 0xd + PTRACE_SETREGSET = 0x4205 + PTRACE_SETSIGINFO = 0x4203 + PTRACE_SET_THREAD_AREA = 0x1a + PTRACE_SET_WATCH_REGS = 0xd1 + PTRACE_SINGLESTEP = 0x9 + PTRACE_SYSCALL = 0x18 + PTRACE_TRACEME = 0x0 + RLIMIT_AS = 0x6 + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_NOFILE = 0x5 + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0x7fffffffffffffff + RTAX_ADVMSS = 0x8 + RTAX_CWND = 0x7 + RTAX_FEATURES = 0xc + RTAX_FEATURE_ALLFRAG = 0x8 + RTAX_FEATURE_ECN = 0x1 + RTAX_FEATURE_SACK = 0x2 + RTAX_FEATURE_TIMESTAMP = 0x4 + RTAX_HOPLIMIT = 0xa + RTAX_INITCWND = 0xb + RTAX_INITRWND = 0xe + RTAX_LOCK = 0x1 + RTAX_MAX = 0xe + RTAX_MTU = 0x2 + RTAX_REORDERING = 0x9 + RTAX_RTO_MIN = 0xd + RTAX_RTT = 0x4 + RTAX_RTTVAR = 0x5 + RTAX_SSTHRESH = 0x6 + RTAX_UNSPEC = 0x0 + RTAX_WINDOW = 0x3 + RTA_ALIGNTO = 0x4 + RTA_MAX = 0x10 + RTCF_DIRECTSRC = 0x4000000 + RTCF_DOREDIRECT = 0x1000000 + RTCF_LOG = 0x2000000 + RTCF_MASQ = 0x400000 + RTCF_NAT = 0x800000 + RTCF_VALVE = 0x200000 + RTF_ADDRCLASSMASK = 0xf8000000 + RTF_ADDRCONF = 0x40000 + RTF_ALLONLINK = 0x20000 + RTF_BROADCAST = 0x10000000 + RTF_CACHE = 0x1000000 + RTF_DEFAULT = 0x10000 + RTF_DYNAMIC = 0x10 + RTF_FLOW = 0x2000000 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_INTERFACE = 0x40000000 + RTF_IRTT = 0x100 + RTF_LINKRT = 0x100000 + RTF_LOCAL = 0x80000000 + RTF_MODIFIED = 0x20 + RTF_MSS = 0x40 + RTF_MTU = 0x40 + RTF_MULTICAST = 0x20000000 + RTF_NAT = 0x8000000 + RTF_NOFORWARD = 0x1000 + RTF_NONEXTHOP = 0x200000 + RTF_NOPMTUDISC = 0x4000 + RTF_POLICY = 0x4000000 + RTF_REINSTATE = 0x8 + RTF_REJECT = 0x200 + RTF_STATIC = 0x400 + RTF_THROW = 0x2000 + RTF_UP = 0x1 + RTF_WINDOW = 0x80 + RTF_XRESOLVE = 0x800 + RTM_BASE = 0x10 + RTM_DELACTION = 0x31 + RTM_DELADDR = 0x15 + RTM_DELADDRLABEL = 0x49 + RTM_DELLINK = 0x11 + RTM_DELNEIGH = 0x1d + RTM_DELQDISC = 0x25 + RTM_DELROUTE = 0x19 + RTM_DELRULE = 0x21 + RTM_DELTCLASS = 0x29 + RTM_DELTFILTER = 0x2d + RTM_F_CLONED = 0x200 + RTM_F_EQUALIZE = 0x400 + RTM_F_NOTIFY = 0x100 + RTM_F_PREFIX = 0x800 + RTM_GETACTION = 0x32 + RTM_GETADDR = 0x16 + RTM_GETADDRLABEL = 0x4a + RTM_GETANYCAST = 0x3e + RTM_GETDCB = 0x4e + RTM_GETLINK = 0x12 + RTM_GETMULTICAST = 0x3a + RTM_GETNEIGH = 0x1e + RTM_GETNEIGHTBL = 0x42 + RTM_GETQDISC = 0x26 + RTM_GETROUTE = 0x1a + RTM_GETRULE = 0x22 + RTM_GETTCLASS = 0x2a + RTM_GETTFILTER = 0x2e + RTM_MAX = 0x4f + RTM_NEWACTION = 0x30 + RTM_NEWADDR = 0x14 + RTM_NEWADDRLABEL = 0x48 + RTM_NEWLINK = 0x10 + RTM_NEWNDUSEROPT = 0x44 + RTM_NEWNEIGH = 0x1c + RTM_NEWNEIGHTBL = 0x40 + RTM_NEWPREFIX = 0x34 + RTM_NEWQDISC = 0x24 + RTM_NEWROUTE = 0x18 + RTM_NEWRULE = 0x20 + RTM_NEWTCLASS = 0x28 + RTM_NEWTFILTER = 0x2c + RTM_NR_FAMILIES = 0x10 + RTM_NR_MSGTYPES = 0x40 + RTM_SETDCB = 0x4f + RTM_SETLINK = 0x13 + RTM_SETNEIGHTBL = 0x43 + RTNH_ALIGNTO = 0x4 + RTNH_F_DEAD = 0x1 + RTNH_F_ONLINK = 0x4 + RTNH_F_PERVASIVE = 0x2 + RTN_MAX = 0xb + RTPROT_BIRD = 0xc + RTPROT_BOOT = 0x3 + RTPROT_DHCP = 0x10 + RTPROT_DNROUTED = 0xd + RTPROT_GATED = 0x8 + RTPROT_KERNEL = 0x2 + RTPROT_MRT = 0xa + RTPROT_NTK = 0xf + RTPROT_RA = 0x9 + RTPROT_REDIRECT = 0x1 + RTPROT_STATIC = 0x4 + RTPROT_UNSPEC = 0x0 + RTPROT_XORP = 0xe + RTPROT_ZEBRA = 0xb + RT_CLASS_DEFAULT = 0xfd + RT_CLASS_LOCAL = 0xff + RT_CLASS_MAIN = 0xfe + RT_CLASS_MAX = 0xff + RT_CLASS_UNSPEC = 0x0 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + RUSAGE_THREAD = 0x1 + SCM_CREDENTIALS = 0x2 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x1d + SCM_TIMESTAMPING = 0x25 + SCM_TIMESTAMPNS = 0x23 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIOCADDDLCI = 0x8980 + SIOCADDMULTI = 0x8931 + SIOCADDRT = 0x890b + SIOCATMARK = 0x40047307 + SIOCDARP = 0x8953 + SIOCDELDLCI = 0x8981 + SIOCDELMULTI = 0x8932 + SIOCDELRT = 0x890c + SIOCDEVPRIVATE = 0x89f0 + SIOCDIFADDR = 0x8936 + SIOCDRARP = 0x8960 + SIOCGARP = 0x8954 + SIOCGIFADDR = 0x8915 + SIOCGIFBR = 0x8940 + SIOCGIFBRDADDR = 0x8919 + SIOCGIFCONF = 0x8912 + SIOCGIFCOUNT = 0x8938 + SIOCGIFDSTADDR = 0x8917 + SIOCGIFENCAP = 0x8925 + SIOCGIFFLAGS = 0x8913 + SIOCGIFHWADDR = 0x8927 + SIOCGIFINDEX = 0x8933 + SIOCGIFMAP = 0x8970 + SIOCGIFMEM = 0x891f + SIOCGIFMETRIC = 0x891d + SIOCGIFMTU = 0x8921 + SIOCGIFNAME = 0x8910 + SIOCGIFNETMASK = 0x891b + SIOCGIFPFLAGS = 0x8935 + SIOCGIFSLAVE = 0x8929 + SIOCGIFTXQLEN = 0x8942 + SIOCGPGRP = 0x40047309 + SIOCGRARP = 0x8961 + SIOCGSTAMP = 0x8906 + SIOCGSTAMPNS = 0x8907 + SIOCPROTOPRIVATE = 0x89e0 + SIOCRTMSG = 0x890d + SIOCSARP = 0x8955 + SIOCSIFADDR = 0x8916 + SIOCSIFBR = 0x8941 + SIOCSIFBRDADDR = 0x891a + SIOCSIFDSTADDR = 0x8918 + SIOCSIFENCAP = 0x8926 + SIOCSIFFLAGS = 0x8914 + SIOCSIFHWADDR = 0x8924 + SIOCSIFHWBROADCAST = 0x8937 + SIOCSIFLINK = 0x8911 + SIOCSIFMAP = 0x8971 + SIOCSIFMEM = 0x8920 + SIOCSIFMETRIC = 0x891e + SIOCSIFMTU = 0x8922 + SIOCSIFNAME = 0x8923 + SIOCSIFNETMASK = 0x891c + SIOCSIFPFLAGS = 0x8934 + SIOCSIFSLAVE = 0x8930 + SIOCSIFTXQLEN = 0x8943 + SIOCSPGRP = 0x80047308 + SIOCSRARP = 0x8962 + SOCK_CLOEXEC = 0x80000 + SOCK_DCCP = 0x6 + SOCK_DGRAM = 0x1 + SOCK_NONBLOCK = 0x80 + SOCK_PACKET = 0xa + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x2 + SOL_AAL = 0x109 + SOL_ATM = 0x108 + SOL_CAN_BASE = 0x64 + SOL_DECNET = 0x105 + SOL_ICMPV6 = 0x3a + SOL_IP = 0x0 + SOL_IPV6 = 0x29 + SOL_IRDA = 0x10a + SOL_PACKET = 0x107 + SOL_RAW = 0xff + SOL_SOCKET = 0xffff + SOL_TCP = 0x6 + SOL_X25 = 0x106 + SOMAXCONN = 0x80 + SO_ACCEPTCONN = 0x1009 + SO_ATTACH_FILTER = 0x1a + SO_BINDTODEVICE = 0x19 + SO_BROADCAST = 0x20 + SO_BSDCOMPAT = 0xe + SO_DEBUG = 0x1 + SO_DETACH_FILTER = 0x1b + SO_DOMAIN = 0x1029 + SO_DONTROUTE = 0x10 + SO_ERROR = 0x1007 + SO_KEEPALIVE = 0x8 + SO_LINGER = 0x80 + SO_MARK = 0x24 + SO_NO_CHECK = 0xb + SO_OOBINLINE = 0x100 + SO_PASSCRED = 0x11 + SO_PASSSEC = 0x22 + SO_PEERCRED = 0x12 + SO_PEERNAME = 0x1c + SO_PEERSEC = 0x1e + SO_PRIORITY = 0xc + SO_PROTOCOL = 0x1028 + SO_RCVBUF = 0x1002 + SO_RCVBUFFORCE = 0x21 + SO_RCVLOWAT = 0x1004 + SO_RCVTIMEO = 0x1006 + SO_REUSEADDR = 0x4 + SO_RXQ_OVFL = 0x28 + SO_SECURITY_AUTHENTICATION = 0x16 + SO_SECURITY_ENCRYPTION_NETWORK = 0x18 + SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17 + SO_SNDBUF = 0x1001 + SO_SNDBUFFORCE = 0x1f + SO_SNDLOWAT = 0x1003 + SO_SNDTIMEO = 0x1005 + SO_STYLE = 0x1008 + SO_TIMESTAMP = 0x1d + SO_TIMESTAMPING = 0x25 + SO_TIMESTAMPNS = 0x23 + SO_TYPE = 0x1008 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + TAB0 = 0x0 + TAB1 = 0x800 + TAB2 = 0x1000 + TAB3 = 0x1800 + TABDLY = 0x1800 + TCFLSH = 0x5407 + TCGETA = 0x5401 + TCGETS = 0x540d + TCGETS2 = 0x4030542a + TCIFLUSH = 0x0 + TCIOFF = 0x2 + TCIOFLUSH = 0x2 + TCION = 0x3 + TCOFLUSH = 0x1 + TCOOFF = 0x0 + TCOON = 0x1 + TCP_CONGESTION = 0xd + TCP_CORK = 0x3 + TCP_DEFER_ACCEPT = 0x9 + TCP_INFO = 0xb + TCP_KEEPCNT = 0x6 + TCP_KEEPIDLE = 0x4 + TCP_KEEPINTVL = 0x5 + TCP_LINGER2 = 0x8 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAX_WINSHIFT = 0xe + TCP_MD5SIG = 0xe + TCP_MD5SIG_MAXKEYLEN = 0x50 + TCP_MSS = 0x200 + TCP_NODELAY = 0x1 + TCP_QUICKACK = 0xc + TCP_SYNCNT = 0x7 + TCP_WINDOW_CLAMP = 0xa + TCSAFLUSH = 0x5410 + TCSBRK = 0x5405 + TCSBRKP = 0x5486 + TCSETA = 0x5402 + TCSETAF = 0x5404 + TCSETAW = 0x5403 + TCSETS = 0x540e + TCSETS2 = 0x8030542b + TCSETSF = 0x5410 + TCSETSF2 = 0x8030542d + TCSETSW = 0x540f + TCSETSW2 = 0x8030542c + TCXONC = 0x5406 + TIOCCBRK = 0x5428 + TIOCCONS = 0x80047478 + TIOCEXCL = 0x740d + TIOCGDEV = 0x40045432 + TIOCGETD = 0x7400 + TIOCGETP = 0x7408 + TIOCGICOUNT = 0x5492 + TIOCGLCKTRMIOS = 0x548b + TIOCGLTC = 0x7474 + TIOCGPGRP = 0x40047477 + TIOCGPTN = 0x40045430 + TIOCGSERIAL = 0x5484 + TIOCGSID = 0x7416 + TIOCGSOFTCAR = 0x5481 + TIOCGWINSZ = 0x40087468 + TIOCINQ = 0x467f + TIOCLINUX = 0x5483 + TIOCMBIC = 0x741c + TIOCMBIS = 0x741b + TIOCMGET = 0x741d + TIOCMIWAIT = 0x5491 + TIOCMSET = 0x741a + TIOCM_CAR = 0x100 + TIOCM_CD = 0x100 + TIOCM_CTS = 0x40 + TIOCM_DSR = 0x400 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x200 + TIOCM_RNG = 0x200 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x20 + TIOCM_ST = 0x10 + TIOCNOTTY = 0x5471 + TIOCNXCL = 0x740e + TIOCOUTQ = 0x7472 + TIOCPKT = 0x5470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_IOCTL = 0x40 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCSBRK = 0x5427 + TIOCSCTTY = 0x5480 + TIOCSERCONFIG = 0x5488 + TIOCSERGETLSR = 0x548e + TIOCSERGETMULTI = 0x548f + TIOCSERGSTRUCT = 0x548d + TIOCSERGWILD = 0x5489 + TIOCSERSETMULTI = 0x5490 + TIOCSERSWILD = 0x548a + TIOCSER_TEMT = 0x1 + TIOCSETD = 0x7401 + TIOCSETN = 0x740a + TIOCSETP = 0x7409 + TIOCSIG = 0x80045436 + TIOCSLCKTRMIOS = 0x548c + TIOCSLTC = 0x7475 + TIOCSPGRP = 0x80047476 + TIOCSPTLCK = 0x80045431 + TIOCSSERIAL = 0x5485 + TIOCSSOFTCAR = 0x5482 + TIOCSTI = 0x5472 + TIOCSWINSZ = 0x80087467 + TIOCVHANGUP = 0x5437 + TOSTOP = 0x8000 + TUNATTACHFILTER = 0x800854d5 + TUNDETACHFILTER = 0x800854d6 + TUNGETFEATURES = 0x400454cf + TUNGETIFF = 0x400454d2 + TUNGETSNDBUF = 0x400454d3 + TUNGETVNETHDRSZ = 0x400454d7 + TUNSETDEBUG = 0x800454c9 + TUNSETGROUP = 0x800454ce + TUNSETIFF = 0x800454ca + TUNSETLINK = 0x800454cd + TUNSETNOCSUM = 0x800454c8 + TUNSETOFFLOAD = 0x800454d0 + TUNSETOWNER = 0x800454cc + TUNSETPERSIST = 0x800454cb + TUNSETSNDBUF = 0x800454d4 + TUNSETTXFILTER = 0x800454d1 + TUNSETVNETHDRSZ = 0x800454d8 + VDISCARD = 0xd + VEOF = 0x10 + VEOL = 0x11 + VEOL2 = 0x6 + VERASE = 0x2 + VINTR = 0x0 + VKILL = 0x3 + VLNEXT = 0xf + VMIN = 0x4 + VQUIT = 0x1 + VREPRINT = 0xc + VSTART = 0x8 + VSTOP = 0x9 + VSUSP = 0xa + VSWTC = 0x7 + VSWTCH = 0x7 + VT0 = 0x0 + VT1 = 0x4000 + VTDLY = 0x4000 + VTIME = 0x5 + VWERASE = 0xe + WALL = 0x40000000 + WCLONE = 0x80000000 + WCONTINUED = 0x8 + WEXITED = 0x4 + WNOHANG = 0x1 + WNOTHREAD = 0x20000000 + WNOWAIT = 0x1000000 + WORDSIZE = 0x20 + WSTOPPED = 0x2 + WUNTRACED = 0x2 + XCASE = 0x4 + XTABS = 0x1800 +) + +// Errors +const ( + E2BIG = syscall.Errno(0x7) + EACCES = syscall.Errno(0xd) + EADDRINUSE = syscall.Errno(0x7d) + EADDRNOTAVAIL = syscall.Errno(0x7e) + EADV = syscall.Errno(0x44) + EAFNOSUPPORT = syscall.Errno(0x7c) + EAGAIN = syscall.Errno(0xb) + EALREADY = syscall.Errno(0x95) + EBADE = syscall.Errno(0x32) + EBADF = syscall.Errno(0x9) + EBADFD = syscall.Errno(0x51) + EBADMSG = syscall.Errno(0x4d) + EBADR = syscall.Errno(0x33) + EBADRQC = syscall.Errno(0x36) + EBADSLT = syscall.Errno(0x37) + EBFONT = syscall.Errno(0x3b) + EBUSY = syscall.Errno(0x10) + ECANCELED = syscall.Errno(0x9e) + ECHILD = syscall.Errno(0xa) + ECHRNG = syscall.Errno(0x25) + ECOMM = syscall.Errno(0x46) + ECONNABORTED = syscall.Errno(0x82) + ECONNREFUSED = syscall.Errno(0x92) + ECONNRESET = syscall.Errno(0x83) + EDEADLK = syscall.Errno(0x2d) + EDEADLOCK = syscall.Errno(0x38) + EDESTADDRREQ = syscall.Errno(0x60) + EDOM = syscall.Errno(0x21) + EDOTDOT = syscall.Errno(0x49) + EDQUOT = syscall.Errno(0x46d) + EEXIST = syscall.Errno(0x11) + EFAULT = syscall.Errno(0xe) + EFBIG = syscall.Errno(0x1b) + EHOSTDOWN = syscall.Errno(0x93) + EHOSTUNREACH = syscall.Errno(0x94) + EHWPOISON = syscall.Errno(0xa8) + EIDRM = syscall.Errno(0x24) + EILSEQ = syscall.Errno(0x58) + EINIT = syscall.Errno(0x8d) + EINPROGRESS = syscall.Errno(0x96) + EINTR = syscall.Errno(0x4) + EINVAL = syscall.Errno(0x16) + EIO = syscall.Errno(0x5) + EISCONN = syscall.Errno(0x85) + EISDIR = syscall.Errno(0x15) + EISNAM = syscall.Errno(0x8b) + EKEYEXPIRED = syscall.Errno(0xa2) + EKEYREJECTED = syscall.Errno(0xa4) + EKEYREVOKED = syscall.Errno(0xa3) + EL2HLT = syscall.Errno(0x2c) + EL2NSYNC = syscall.Errno(0x26) + EL3HLT = syscall.Errno(0x27) + EL3RST = syscall.Errno(0x28) + ELIBACC = syscall.Errno(0x53) + ELIBBAD = syscall.Errno(0x54) + ELIBEXEC = syscall.Errno(0x57) + ELIBMAX = syscall.Errno(0x56) + ELIBSCN = syscall.Errno(0x55) + ELNRNG = syscall.Errno(0x29) + ELOOP = syscall.Errno(0x5a) + EMEDIUMTYPE = syscall.Errno(0xa0) + EMFILE = syscall.Errno(0x18) + EMLINK = syscall.Errno(0x1f) + EMSGSIZE = syscall.Errno(0x61) + EMULTIHOP = syscall.Errno(0x4a) + ENAMETOOLONG = syscall.Errno(0x4e) + ENAVAIL = syscall.Errno(0x8a) + ENETDOWN = syscall.Errno(0x7f) + ENETRESET = syscall.Errno(0x81) + ENETUNREACH = syscall.Errno(0x80) + ENFILE = syscall.Errno(0x17) + ENOANO = syscall.Errno(0x35) + ENOBUFS = syscall.Errno(0x84) + ENOCSI = syscall.Errno(0x2b) + ENODATA = syscall.Errno(0x3d) + ENODEV = syscall.Errno(0x13) + ENOENT = syscall.Errno(0x2) + ENOEXEC = syscall.Errno(0x8) + ENOKEY = syscall.Errno(0xa1) + ENOLCK = syscall.Errno(0x2e) + ENOLINK = syscall.Errno(0x43) + ENOMEDIUM = syscall.Errno(0x9f) + ENOMEM = syscall.Errno(0xc) + ENOMSG = syscall.Errno(0x23) + ENONET = syscall.Errno(0x40) + ENOPKG = syscall.Errno(0x41) + ENOPROTOOPT = syscall.Errno(0x63) + ENOSPC = syscall.Errno(0x1c) + ENOSR = syscall.Errno(0x3f) + ENOSTR = syscall.Errno(0x3c) + ENOSYS = syscall.Errno(0x59) + ENOTBLK = syscall.Errno(0xf) + ENOTCONN = syscall.Errno(0x86) + ENOTDIR = syscall.Errno(0x14) + ENOTEMPTY = syscall.Errno(0x5d) + ENOTNAM = syscall.Errno(0x89) + ENOTRECOVERABLE = syscall.Errno(0xa6) + ENOTSOCK = syscall.Errno(0x5f) + ENOTSUP = syscall.Errno(0x7a) + ENOTTY = syscall.Errno(0x19) + ENOTUNIQ = syscall.Errno(0x50) + ENXIO = syscall.Errno(0x6) + EOPNOTSUPP = syscall.Errno(0x7a) + EOVERFLOW = syscall.Errno(0x4f) + EOWNERDEAD = syscall.Errno(0xa5) + EPERM = syscall.Errno(0x1) + EPFNOSUPPORT = syscall.Errno(0x7b) + EPIPE = syscall.Errno(0x20) + EPROTO = syscall.Errno(0x47) + EPROTONOSUPPORT = syscall.Errno(0x78) + EPROTOTYPE = syscall.Errno(0x62) + ERANGE = syscall.Errno(0x22) + EREMCHG = syscall.Errno(0x52) + EREMDEV = syscall.Errno(0x8e) + EREMOTE = syscall.Errno(0x42) + EREMOTEIO = syscall.Errno(0x8c) + ERESTART = syscall.Errno(0x5b) + ERFKILL = syscall.Errno(0xa7) + EROFS = syscall.Errno(0x1e) + ESHUTDOWN = syscall.Errno(0x8f) + ESOCKTNOSUPPORT = syscall.Errno(0x79) + ESPIPE = syscall.Errno(0x1d) + ESRCH = syscall.Errno(0x3) + ESRMNT = syscall.Errno(0x45) + ESTALE = syscall.Errno(0x97) + ESTRPIPE = syscall.Errno(0x5c) + ETIME = syscall.Errno(0x3e) + ETIMEDOUT = syscall.Errno(0x91) + ETOOMANYREFS = syscall.Errno(0x90) + ETXTBSY = syscall.Errno(0x1a) + EUCLEAN = syscall.Errno(0x87) + EUNATCH = syscall.Errno(0x2a) + EUSERS = syscall.Errno(0x5e) + EWOULDBLOCK = syscall.Errno(0xb) + EXDEV = syscall.Errno(0x12) + EXFULL = syscall.Errno(0x34) +) + +// Signals +const ( + SIGABRT = syscall.Signal(0x6) + SIGALRM = syscall.Signal(0xe) + SIGBUS = syscall.Signal(0xa) + SIGCHLD = syscall.Signal(0x12) + SIGCLD = syscall.Signal(0x12) + SIGCONT = syscall.Signal(0x19) + SIGEMT = syscall.Signal(0x7) + SIGFPE = syscall.Signal(0x8) + SIGHUP = syscall.Signal(0x1) + SIGILL = syscall.Signal(0x4) + SIGINT = syscall.Signal(0x2) + SIGIO = syscall.Signal(0x16) + SIGIOT = syscall.Signal(0x6) + SIGKILL = syscall.Signal(0x9) + SIGPIPE = syscall.Signal(0xd) + SIGPOLL = syscall.Signal(0x16) + SIGPROF = syscall.Signal(0x1d) + SIGPWR = syscall.Signal(0x13) + SIGQUIT = syscall.Signal(0x3) + SIGSEGV = syscall.Signal(0xb) + SIGSTOP = syscall.Signal(0x17) + SIGSYS = syscall.Signal(0xc) + SIGTERM = syscall.Signal(0xf) + SIGTRAP = syscall.Signal(0x5) + SIGTSTP = syscall.Signal(0x18) + SIGTTIN = syscall.Signal(0x1a) + SIGTTOU = syscall.Signal(0x1b) + SIGURG = syscall.Signal(0x15) + SIGUSR1 = syscall.Signal(0x10) + SIGUSR2 = syscall.Signal(0x11) + SIGVTALRM = syscall.Signal(0x1c) + SIGWINCH = syscall.Signal(0x14) + SIGXCPU = syscall.Signal(0x1e) + SIGXFSZ = syscall.Signal(0x1f) +) + +// Error table +var errors = [...]string{ + 1: "operation not permitted", + 2: "no such file or directory", + 3: "no such process", + 4: "interrupted system call", + 5: "input/output error", + 6: "no such device or address", + 7: "argument list too long", + 8: "exec format error", + 9: "bad file descriptor", + 10: "no child processes", + 11: "resource temporarily unavailable", + 12: "cannot allocate memory", + 13: "permission denied", + 14: "bad address", + 15: "block device required", + 16: "device or resource busy", + 17: "file exists", + 18: "invalid cross-device link", + 19: "no such device", + 20: "not a directory", + 21: "is a directory", + 22: "invalid argument", + 23: "too many open files in system", + 24: "too many open files", + 25: "inappropriate ioctl for device", + 26: "text file busy", + 27: "file too large", + 28: "no space left on device", + 29: "illegal seek", + 30: "read-only file system", + 31: "too many links", + 32: "broken pipe", + 33: "numerical argument out of domain", + 34: "numerical result out of range", + 35: "no message of desired type", + 36: "identifier removed", + 37: "channel number out of range", + 38: "level 2 not synchronized", + 39: "level 3 halted", + 40: "level 3 reset", + 41: "link number out of range", + 42: "protocol driver not attached", + 43: "no CSI structure available", + 44: "level 2 halted", + 45: "resource deadlock avoided", + 46: "no locks available", + 50: "invalid exchange", + 51: "invalid request descriptor", + 52: "exchange full", + 53: "no anode", + 54: "invalid request code", + 55: "invalid slot", + 56: "file locking deadlock error", + 59: "bad font file format", + 60: "device not a stream", + 61: "no data available", + 62: "timer expired", + 63: "out of streams resources", + 64: "machine is not on the network", + 65: "package not installed", + 66: "object is remote", + 67: "link has been severed", + 68: "advertise error", + 69: "srmount error", + 70: "communication error on send", + 71: "protocol error", + 73: "RFS specific error", + 74: "multihop attempted", + 77: "bad message", + 78: "file name too long", + 79: "value too large for defined data type", + 80: "name not unique on network", + 81: "file descriptor in bad state", + 82: "remote address changed", + 83: "can not access a needed shared library", + 84: "accessing a corrupted shared library", + 85: ".lib section in a.out corrupted", + 86: "attempting to link in too many shared libraries", + 87: "cannot exec a shared library directly", + 88: "invalid or incomplete multibyte or wide character", + 89: "function not implemented", + 90: "too many levels of symbolic links", + 91: "interrupted system call should be restarted", + 92: "streams pipe error", + 93: "directory not empty", + 94: "too many users", + 95: "socket operation on non-socket", + 96: "destination address required", + 97: "message too long", + 98: "protocol wrong type for socket", + 99: "protocol not available", + 120: "protocol not supported", + 121: "socket type not supported", + 122: "operation not supported", + 123: "protocol family not supported", + 124: "address family not supported by protocol", + 125: "address already in use", + 126: "cannot assign requested address", + 127: "network is down", + 128: "network is unreachable", + 129: "network dropped connection on reset", + 130: "software caused connection abort", + 131: "connection reset by peer", + 132: "no buffer space available", + 133: "transport endpoint is already connected", + 134: "transport endpoint is not connected", + 135: "structure needs cleaning", + 137: "not a XENIX named type file", + 138: "no XENIX semaphores available", + 139: "is a named type file", + 140: "remote I/O error", + 141: "unknown error 141", + 142: "unknown error 142", + 143: "cannot send after transport endpoint shutdown", + 144: "too many references: cannot splice", + 145: "connection timed out", + 146: "connection refused", + 147: "host is down", + 148: "no route to host", + 149: "operation already in progress", + 150: "operation now in progress", + 151: "stale NFS file handle", + 158: "operation canceled", + 159: "no medium found", + 160: "wrong medium type", + 161: "required key not available", + 162: "key has expired", + 163: "key has been revoked", + 164: "key was rejected by service", + 165: "owner died", + 166: "state not recoverable", + 167: "operation not possible due to RF-kill", + 168: "unknown error 168", + 1133: "disk quota exceeded", +} + +// Signal table +var signals = [...]string{ + 1: "hangup", + 2: "interrupt", + 3: "quit", + 4: "illegal instruction", + 5: "trace/breakpoint trap", + 6: "aborted", + 7: "EMT trap", + 8: "floating point exception", + 9: "killed", + 10: "bus error", + 11: "segmentation fault", + 12: "bad system call", + 13: "broken pipe", + 14: "alarm clock", + 15: "terminated", + 16: "user defined signal 1", + 17: "user defined signal 2", + 18: "child exited", + 19: "power failure", + 20: "window changed", + 21: "urgent I/O condition", + 22: "I/O possible", + 23: "stopped (signal)", + 24: "stopped", + 25: "continued", + 26: "stopped (tty input)", + 27: "stopped (tty output)", + 28: "virtual timer expired", + 29: "profiling timer expired", + 30: "CPU time limit exceeded", + 31: "file size limit exceeded", +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go new file mode 100644 index 0000000000..0f5ee22375 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -0,0 +1,2020 @@ +// mkerrors.sh +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// +build mipsle,linux + +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs -- _const.go + +package unix + +import "syscall" + +const ( + AF_ALG = 0x26 + AF_APPLETALK = 0x5 + AF_ASH = 0x12 + AF_ATMPVC = 0x8 + AF_ATMSVC = 0x14 + AF_AX25 = 0x3 + AF_BLUETOOTH = 0x1f + AF_BRIDGE = 0x7 + AF_CAIF = 0x25 + AF_CAN = 0x1d + AF_DECnet = 0xc + AF_ECONET = 0x13 + AF_FILE = 0x1 + AF_IB = 0x1b + AF_IEEE802154 = 0x24 + AF_INET = 0x2 + AF_INET6 = 0xa + AF_IPX = 0x4 + AF_IRDA = 0x17 + AF_ISDN = 0x22 + AF_IUCV = 0x20 + AF_KCM = 0x29 + AF_KEY = 0xf + AF_LLC = 0x1a + AF_LOCAL = 0x1 + AF_MAX = 0x2a + AF_MPLS = 0x1c + AF_NETBEUI = 0xd + AF_NETLINK = 0x10 + AF_NETROM = 0x6 + AF_NFC = 0x27 + AF_PACKET = 0x11 + AF_PHONET = 0x23 + AF_PPPOX = 0x18 + AF_RDS = 0x15 + AF_ROSE = 0xb + AF_ROUTE = 0x10 + AF_RXRPC = 0x21 + AF_SECURITY = 0xe + AF_SNA = 0x16 + AF_TIPC = 0x1e + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + AF_VSOCK = 0x28 + AF_WANPIPE = 0x19 + AF_X25 = 0x9 + ARPHRD_6LOWPAN = 0x339 + ARPHRD_ADAPT = 0x108 + ARPHRD_APPLETLK = 0x8 + ARPHRD_ARCNET = 0x7 + ARPHRD_ASH = 0x30d + ARPHRD_ATM = 0x13 + ARPHRD_AX25 = 0x3 + ARPHRD_BIF = 0x307 + ARPHRD_CAIF = 0x336 + ARPHRD_CAN = 0x118 + ARPHRD_CHAOS = 0x5 + ARPHRD_CISCO = 0x201 + ARPHRD_CSLIP = 0x101 + ARPHRD_CSLIP6 = 0x103 + ARPHRD_DDCMP = 0x205 + ARPHRD_DLCI = 0xf + ARPHRD_ECONET = 0x30e + ARPHRD_EETHER = 0x2 + ARPHRD_ETHER = 0x1 + ARPHRD_EUI64 = 0x1b + ARPHRD_FCAL = 0x311 + ARPHRD_FCFABRIC = 0x313 + ARPHRD_FCPL = 0x312 + ARPHRD_FCPP = 0x310 + ARPHRD_FDDI = 0x306 + ARPHRD_FRAD = 0x302 + ARPHRD_HDLC = 0x201 + ARPHRD_HIPPI = 0x30c + ARPHRD_HWX25 = 0x110 + ARPHRD_IEEE1394 = 0x18 + ARPHRD_IEEE802 = 0x6 + ARPHRD_IEEE80211 = 0x321 + ARPHRD_IEEE80211_PRISM = 0x322 + ARPHRD_IEEE80211_RADIOTAP = 0x323 + ARPHRD_IEEE802154 = 0x324 + ARPHRD_IEEE802154_MONITOR = 0x325 + ARPHRD_IEEE802_TR = 0x320 + ARPHRD_INFINIBAND = 0x20 + ARPHRD_IP6GRE = 0x337 + ARPHRD_IPDDP = 0x309 + ARPHRD_IPGRE = 0x30a + ARPHRD_IRDA = 0x30f + ARPHRD_LAPB = 0x204 + ARPHRD_LOCALTLK = 0x305 + ARPHRD_LOOPBACK = 0x304 + ARPHRD_METRICOM = 0x17 + ARPHRD_NETLINK = 0x338 + ARPHRD_NETROM = 0x0 + ARPHRD_NONE = 0xfffe + ARPHRD_PHONET = 0x334 + ARPHRD_PHONET_PIPE = 0x335 + ARPHRD_PIMREG = 0x30b + ARPHRD_PPP = 0x200 + ARPHRD_PRONET = 0x4 + ARPHRD_RAWHDLC = 0x206 + ARPHRD_ROSE = 0x10e + ARPHRD_RSRVD = 0x104 + ARPHRD_SIT = 0x308 + ARPHRD_SKIP = 0x303 + ARPHRD_SLIP = 0x100 + ARPHRD_SLIP6 = 0x102 + ARPHRD_TUNNEL = 0x300 + ARPHRD_TUNNEL6 = 0x301 + ARPHRD_VOID = 0xffff + ARPHRD_X25 = 0x10f + B0 = 0x0 + B1000000 = 0x1008 + B110 = 0x3 + B115200 = 0x1002 + B1152000 = 0x1009 + B1200 = 0x9 + B134 = 0x4 + B150 = 0x5 + B1500000 = 0x100a + B1800 = 0xa + B19200 = 0xe + B200 = 0x6 + B2000000 = 0x100b + B230400 = 0x1003 + B2400 = 0xb + B2500000 = 0x100c + B300 = 0x7 + B3000000 = 0x100d + B3500000 = 0x100e + B38400 = 0xf + B4000000 = 0x100f + B460800 = 0x1004 + B4800 = 0xc + B50 = 0x1 + B500000 = 0x1005 + B57600 = 0x1001 + B576000 = 0x1006 + B600 = 0x8 + B75 = 0x2 + B921600 = 0x1007 + B9600 = 0xd + BOTHER = 0x1000 + BPF_A = 0x10 + BPF_ABS = 0x20 + BPF_ADD = 0x0 + BPF_ALU = 0x4 + BPF_AND = 0x50 + BPF_B = 0x10 + BPF_DIV = 0x30 + BPF_H = 0x8 + BPF_IMM = 0x0 + BPF_IND = 0x40 + BPF_JA = 0x0 + BPF_JEQ = 0x10 + BPF_JGE = 0x30 + BPF_JGT = 0x20 + BPF_JMP = 0x5 + BPF_JSET = 0x40 + BPF_K = 0x0 + BPF_LD = 0x0 + BPF_LDX = 0x1 + BPF_LEN = 0x80 + BPF_LL_OFF = -0x200000 + BPF_LSH = 0x60 + BPF_MAJOR_VERSION = 0x1 + BPF_MAXINSNS = 0x1000 + BPF_MEM = 0x60 + BPF_MEMWORDS = 0x10 + BPF_MINOR_VERSION = 0x1 + BPF_MISC = 0x7 + BPF_MOD = 0x90 + BPF_MSH = 0xa0 + BPF_MUL = 0x20 + BPF_NEG = 0x80 + BPF_NET_OFF = -0x100000 + BPF_OR = 0x40 + BPF_RET = 0x6 + BPF_RSH = 0x70 + BPF_ST = 0x2 + BPF_STX = 0x3 + BPF_SUB = 0x10 + BPF_TAX = 0x0 + BPF_TXA = 0x80 + BPF_W = 0x0 + BPF_X = 0x8 + BPF_XOR = 0xa0 + BRKINT = 0x2 + BS0 = 0x0 + BS1 = 0x2000 + BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 + CBAUD = 0x100f + CBAUDEX = 0x1000 + CFLUSH = 0xf + CIBAUD = 0x100f0000 + CLOCAL = 0x800 + CLOCK_BOOTTIME = 0x7 + CLOCK_BOOTTIME_ALARM = 0x9 + CLOCK_DEFAULT = 0x0 + CLOCK_EXT = 0x1 + CLOCK_INT = 0x2 + CLOCK_MONOTONIC = 0x1 + CLOCK_MONOTONIC_COARSE = 0x6 + CLOCK_MONOTONIC_RAW = 0x4 + CLOCK_PROCESS_CPUTIME_ID = 0x2 + CLOCK_REALTIME = 0x0 + CLOCK_REALTIME_ALARM = 0x8 + CLOCK_REALTIME_COARSE = 0x5 + CLOCK_TAI = 0xb + CLOCK_THREAD_CPUTIME_ID = 0x3 + CLOCK_TXFROMRX = 0x4 + CLOCK_TXINT = 0x3 + CLONE_CHILD_CLEARTID = 0x200000 + CLONE_CHILD_SETTID = 0x1000000 + CLONE_DETACHED = 0x400000 + CLONE_FILES = 0x400 + CLONE_FS = 0x200 + CLONE_IO = 0x80000000 + CLONE_NEWCGROUP = 0x2000000 + CLONE_NEWIPC = 0x8000000 + CLONE_NEWNET = 0x40000000 + CLONE_NEWNS = 0x20000 + CLONE_NEWPID = 0x20000000 + CLONE_NEWUSER = 0x10000000 + CLONE_NEWUTS = 0x4000000 + CLONE_PARENT = 0x8000 + CLONE_PARENT_SETTID = 0x100000 + CLONE_PTRACE = 0x2000 + CLONE_SETTLS = 0x80000 + CLONE_SIGHAND = 0x800 + CLONE_SYSVSEM = 0x40000 + CLONE_THREAD = 0x10000 + CLONE_UNTRACED = 0x800000 + CLONE_VFORK = 0x4000 + CLONE_VM = 0x100 + CMSPAR = 0x40000000 + CR0 = 0x0 + CR1 = 0x200 + CR2 = 0x400 + CR3 = 0x600 + CRDLY = 0x600 + CREAD = 0x80 + CRTSCTS = 0x80000000 + CS5 = 0x0 + CS6 = 0x10 + CS7 = 0x20 + CS8 = 0x30 + CSIGNAL = 0xff + CSIZE = 0x30 + CSTART = 0x11 + CSTATUS = 0x0 + CSTOP = 0x13 + CSTOPB = 0x40 + CSUSP = 0x1a + DT_BLK = 0x6 + DT_CHR = 0x2 + DT_DIR = 0x4 + DT_FIFO = 0x1 + DT_LNK = 0xa + DT_REG = 0x8 + DT_SOCK = 0xc + DT_UNKNOWN = 0x0 + DT_WHT = 0xe + ECHO = 0x8 + ECHOCTL = 0x200 + ECHOE = 0x10 + ECHOK = 0x20 + ECHOKE = 0x800 + ECHONL = 0x40 + ECHOPRT = 0x400 + ENCODING_DEFAULT = 0x0 + ENCODING_FM_MARK = 0x3 + ENCODING_FM_SPACE = 0x4 + ENCODING_MANCHESTER = 0x5 + ENCODING_NRZ = 0x1 + ENCODING_NRZI = 0x2 + EPOLLERR = 0x8 + EPOLLET = 0x80000000 + EPOLLEXCLUSIVE = 0x10000000 + EPOLLHUP = 0x10 + EPOLLIN = 0x1 + EPOLLMSG = 0x400 + EPOLLONESHOT = 0x40000000 + EPOLLOUT = 0x4 + EPOLLPRI = 0x2 + EPOLLRDBAND = 0x80 + EPOLLRDHUP = 0x2000 + EPOLLRDNORM = 0x40 + EPOLLWAKEUP = 0x20000000 + EPOLLWRBAND = 0x200 + EPOLLWRNORM = 0x100 + EPOLL_CLOEXEC = 0x80000 + EPOLL_CTL_ADD = 0x1 + EPOLL_CTL_DEL = 0x2 + EPOLL_CTL_MOD = 0x3 + ETH_P_1588 = 0x88f7 + ETH_P_8021AD = 0x88a8 + ETH_P_8021AH = 0x88e7 + ETH_P_8021Q = 0x8100 + ETH_P_80221 = 0x8917 + ETH_P_802_2 = 0x4 + ETH_P_802_3 = 0x1 + ETH_P_802_3_MIN = 0x600 + ETH_P_802_EX1 = 0x88b5 + ETH_P_AARP = 0x80f3 + ETH_P_AF_IUCV = 0xfbfb + ETH_P_ALL = 0x3 + ETH_P_AOE = 0x88a2 + ETH_P_ARCNET = 0x1a + ETH_P_ARP = 0x806 + ETH_P_ATALK = 0x809b + ETH_P_ATMFATE = 0x8884 + ETH_P_ATMMPOA = 0x884c + ETH_P_AX25 = 0x2 + ETH_P_BATMAN = 0x4305 + ETH_P_BPQ = 0x8ff + ETH_P_CAIF = 0xf7 + ETH_P_CAN = 0xc + ETH_P_CANFD = 0xd + ETH_P_CONTROL = 0x16 + ETH_P_CUST = 0x6006 + ETH_P_DDCMP = 0x6 + ETH_P_DEC = 0x6000 + ETH_P_DIAG = 0x6005 + ETH_P_DNA_DL = 0x6001 + ETH_P_DNA_RC = 0x6002 + ETH_P_DNA_RT = 0x6003 + ETH_P_DSA = 0x1b + ETH_P_ECONET = 0x18 + ETH_P_EDSA = 0xdada + ETH_P_FCOE = 0x8906 + ETH_P_FIP = 0x8914 + ETH_P_HDLC = 0x19 + ETH_P_HSR = 0x892f + ETH_P_IEEE802154 = 0xf6 + ETH_P_IEEEPUP = 0xa00 + ETH_P_IEEEPUPAT = 0xa01 + ETH_P_IP = 0x800 + ETH_P_IPV6 = 0x86dd + ETH_P_IPX = 0x8137 + ETH_P_IRDA = 0x17 + ETH_P_LAT = 0x6004 + ETH_P_LINK_CTL = 0x886c + ETH_P_LOCALTALK = 0x9 + ETH_P_LOOP = 0x60 + ETH_P_LOOPBACK = 0x9000 + ETH_P_MACSEC = 0x88e5 + ETH_P_MOBITEX = 0x15 + ETH_P_MPLS_MC = 0x8848 + ETH_P_MPLS_UC = 0x8847 + ETH_P_MVRP = 0x88f5 + ETH_P_PAE = 0x888e + ETH_P_PAUSE = 0x8808 + ETH_P_PHONET = 0xf5 + ETH_P_PPPTALK = 0x10 + ETH_P_PPP_DISC = 0x8863 + ETH_P_PPP_MP = 0x8 + ETH_P_PPP_SES = 0x8864 + ETH_P_PRP = 0x88fb + ETH_P_PUP = 0x200 + ETH_P_PUPAT = 0x201 + ETH_P_QINQ1 = 0x9100 + ETH_P_QINQ2 = 0x9200 + ETH_P_QINQ3 = 0x9300 + ETH_P_RARP = 0x8035 + ETH_P_SCA = 0x6007 + ETH_P_SLOW = 0x8809 + ETH_P_SNAP = 0x5 + ETH_P_TDLS = 0x890d + ETH_P_TEB = 0x6558 + ETH_P_TIPC = 0x88ca + ETH_P_TRAILER = 0x1c + ETH_P_TR_802_2 = 0x11 + ETH_P_TSN = 0x22f0 + ETH_P_WAN_PPP = 0x7 + ETH_P_WCCP = 0x883e + ETH_P_X25 = 0x805 + ETH_P_XDSA = 0xf8 + EXTA = 0xe + EXTB = 0xf + EXTPROC = 0x10000 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0x400 + FF0 = 0x0 + FF1 = 0x8000 + FFDLY = 0x8000 + FLUSHO = 0x2000 + F_DUPFD = 0x0 + F_DUPFD_CLOEXEC = 0x406 + F_EXLCK = 0x4 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLEASE = 0x401 + F_GETLK = 0x21 + F_GETLK64 = 0x21 + F_GETOWN = 0x17 + F_GETOWN_EX = 0x10 + F_GETPIPE_SZ = 0x408 + F_GETSIG = 0xb + F_LOCK = 0x1 + F_NOTIFY = 0x402 + F_OFD_GETLK = 0x24 + F_OFD_SETLK = 0x25 + F_OFD_SETLKW = 0x26 + F_OK = 0x0 + F_RDLCK = 0x0 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLEASE = 0x400 + F_SETLK = 0x22 + F_SETLK64 = 0x22 + F_SETLKW = 0x23 + F_SETLKW64 = 0x23 + F_SETOWN = 0x18 + F_SETOWN_EX = 0xf + F_SETPIPE_SZ = 0x407 + F_SETSIG = 0xa + F_SHLCK = 0x8 + F_TEST = 0x3 + F_TLOCK = 0x2 + F_ULOCK = 0x0 + F_UNLCK = 0x2 + F_WRLCK = 0x1 + HUPCL = 0x400 + IBSHIFT = 0x10 + ICANON = 0x2 + ICMPV6_FILTER = 0x1 + ICRNL = 0x100 + IEXTEN = 0x100 + IFA_F_DADFAILED = 0x8 + IFA_F_DEPRECATED = 0x20 + IFA_F_HOMEADDRESS = 0x10 + IFA_F_MANAGETEMPADDR = 0x100 + IFA_F_MCAUTOJOIN = 0x400 + IFA_F_NODAD = 0x2 + IFA_F_NOPREFIXROUTE = 0x200 + IFA_F_OPTIMISTIC = 0x4 + IFA_F_PERMANENT = 0x80 + IFA_F_SECONDARY = 0x1 + IFA_F_STABLE_PRIVACY = 0x800 + IFA_F_TEMPORARY = 0x1 + IFA_F_TENTATIVE = 0x40 + IFA_MAX = 0x8 + IFF_ALLMULTI = 0x200 + IFF_ATTACH_QUEUE = 0x200 + IFF_AUTOMEDIA = 0x4000 + IFF_BROADCAST = 0x2 + IFF_DEBUG = 0x4 + IFF_DETACH_QUEUE = 0x400 + IFF_DORMANT = 0x20000 + IFF_DYNAMIC = 0x8000 + IFF_ECHO = 0x40000 + IFF_LOOPBACK = 0x8 + IFF_LOWER_UP = 0x10000 + IFF_MASTER = 0x400 + IFF_MULTICAST = 0x1000 + IFF_MULTI_QUEUE = 0x100 + IFF_NOARP = 0x80 + IFF_NOFILTER = 0x1000 + IFF_NOTRAILERS = 0x20 + IFF_NO_PI = 0x1000 + IFF_ONE_QUEUE = 0x2000 + IFF_PERSIST = 0x800 + IFF_POINTOPOINT = 0x10 + IFF_PORTSEL = 0x2000 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SLAVE = 0x800 + IFF_TAP = 0x2 + IFF_TUN = 0x1 + IFF_TUN_EXCL = 0x8000 + IFF_UP = 0x1 + IFF_VNET_HDR = 0x4000 + IFF_VOLATILE = 0x70c5a + IFNAMSIZ = 0x10 + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x2000 + INLCR = 0x40 + INPCK = 0x10 + IN_ACCESS = 0x1 + IN_ALL_EVENTS = 0xfff + IN_ATTRIB = 0x4 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLOEXEC = 0x80000 + IN_CLOSE = 0x18 + IN_CLOSE_NOWRITE = 0x10 + IN_CLOSE_WRITE = 0x8 + IN_CREATE = 0x100 + IN_DELETE = 0x200 + IN_DELETE_SELF = 0x400 + IN_DONT_FOLLOW = 0x2000000 + IN_EXCL_UNLINK = 0x4000000 + IN_IGNORED = 0x8000 + IN_ISDIR = 0x40000000 + IN_LOOPBACKNET = 0x7f + IN_MASK_ADD = 0x20000000 + IN_MODIFY = 0x2 + IN_MOVE = 0xc0 + IN_MOVED_FROM = 0x40 + IN_MOVED_TO = 0x80 + IN_MOVE_SELF = 0x800 + IN_NONBLOCK = 0x80 + IN_ONESHOT = 0x80000000 + IN_ONLYDIR = 0x1000000 + IN_OPEN = 0x20 + IN_Q_OVERFLOW = 0x4000 + IN_UNMOUNT = 0x2000 + IPPROTO_AH = 0x33 + IPPROTO_BEETPH = 0x5e + IPPROTO_COMP = 0x6c + IPPROTO_DCCP = 0x21 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_ENCAP = 0x62 + IPPROTO_ESP = 0x32 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GRE = 0x2f + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IGMP = 0x2 + IPPROTO_IP = 0x0 + IPPROTO_IPIP = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_MH = 0x87 + IPPROTO_MPLS = 0x89 + IPPROTO_MTP = 0x5c + IPPROTO_NONE = 0x3b + IPPROTO_PIM = 0x67 + IPPROTO_PUP = 0xc + IPPROTO_RAW = 0xff + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_SCTP = 0x84 + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_UDP = 0x11 + IPPROTO_UDPLITE = 0x88 + IPV6_2292DSTOPTS = 0x4 + IPV6_2292HOPLIMIT = 0x8 + IPV6_2292HOPOPTS = 0x3 + IPV6_2292PKTINFO = 0x2 + IPV6_2292PKTOPTIONS = 0x6 + IPV6_2292RTHDR = 0x5 + IPV6_ADDRFORM = 0x1 + IPV6_ADD_MEMBERSHIP = 0x14 + IPV6_AUTHHDR = 0xa + IPV6_CHECKSUM = 0x7 + IPV6_DONTFRAG = 0x3e + IPV6_DROP_MEMBERSHIP = 0x15 + IPV6_DSTOPTS = 0x3b + IPV6_HDRINCL = 0x24 + IPV6_HOPLIMIT = 0x34 + IPV6_HOPOPTS = 0x36 + IPV6_IPSEC_POLICY = 0x22 + IPV6_JOIN_ANYCAST = 0x1b + IPV6_JOIN_GROUP = 0x14 + IPV6_LEAVE_ANYCAST = 0x1c + IPV6_LEAVE_GROUP = 0x15 + IPV6_MTU = 0x18 + IPV6_MTU_DISCOVER = 0x17 + IPV6_MULTICAST_HOPS = 0x12 + IPV6_MULTICAST_IF = 0x11 + IPV6_MULTICAST_LOOP = 0x13 + IPV6_NEXTHOP = 0x9 + IPV6_PATHMTU = 0x3d + IPV6_PKTINFO = 0x32 + IPV6_PMTUDISC_DO = 0x2 + IPV6_PMTUDISC_DONT = 0x0 + IPV6_PMTUDISC_INTERFACE = 0x4 + IPV6_PMTUDISC_OMIT = 0x5 + IPV6_PMTUDISC_PROBE = 0x3 + IPV6_PMTUDISC_WANT = 0x1 + IPV6_RECVDSTOPTS = 0x3a + IPV6_RECVERR = 0x19 + IPV6_RECVHOPLIMIT = 0x33 + IPV6_RECVHOPOPTS = 0x35 + IPV6_RECVPATHMTU = 0x3c + IPV6_RECVPKTINFO = 0x31 + IPV6_RECVRTHDR = 0x38 + IPV6_RECVTCLASS = 0x42 + IPV6_ROUTER_ALERT = 0x16 + IPV6_RTHDR = 0x39 + IPV6_RTHDRDSTOPTS = 0x37 + IPV6_RTHDR_LOOSE = 0x0 + IPV6_RTHDR_STRICT = 0x1 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_RXDSTOPTS = 0x3b + IPV6_RXHOPOPTS = 0x36 + IPV6_TCLASS = 0x43 + IPV6_UNICAST_HOPS = 0x10 + IPV6_V6ONLY = 0x1a + IPV6_XFRM_POLICY = 0x23 + IP_ADD_MEMBERSHIP = 0x23 + IP_ADD_SOURCE_MEMBERSHIP = 0x27 + IP_BIND_ADDRESS_NO_PORT = 0x18 + IP_BLOCK_SOURCE = 0x26 + IP_CHECKSUM = 0x17 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DROP_MEMBERSHIP = 0x24 + IP_DROP_SOURCE_MEMBERSHIP = 0x28 + IP_FREEBIND = 0xf + IP_HDRINCL = 0x3 + IP_IPSEC_POLICY = 0x10 + IP_MAXPACKET = 0xffff + IP_MAX_MEMBERSHIPS = 0x14 + IP_MF = 0x2000 + IP_MINTTL = 0x15 + IP_MSFILTER = 0x29 + IP_MSS = 0x240 + IP_MTU = 0xe + IP_MTU_DISCOVER = 0xa + IP_MULTICAST_ALL = 0x31 + IP_MULTICAST_IF = 0x20 + IP_MULTICAST_LOOP = 0x22 + IP_MULTICAST_TTL = 0x21 + IP_NODEFRAG = 0x16 + IP_OFFMASK = 0x1fff + IP_OPTIONS = 0x4 + IP_ORIGDSTADDR = 0x14 + IP_PASSSEC = 0x12 + IP_PKTINFO = 0x8 + IP_PKTOPTIONS = 0x9 + IP_PMTUDISC = 0xa + IP_PMTUDISC_DO = 0x2 + IP_PMTUDISC_DONT = 0x0 + IP_PMTUDISC_INTERFACE = 0x4 + IP_PMTUDISC_OMIT = 0x5 + IP_PMTUDISC_PROBE = 0x3 + IP_PMTUDISC_WANT = 0x1 + IP_RECVERR = 0xb + IP_RECVOPTS = 0x6 + IP_RECVORIGDSTADDR = 0x14 + IP_RECVRETOPTS = 0x7 + IP_RECVTOS = 0xd + IP_RECVTTL = 0xc + IP_RETOPTS = 0x7 + IP_RF = 0x8000 + IP_ROUTER_ALERT = 0x5 + IP_TOS = 0x1 + IP_TRANSPARENT = 0x13 + IP_TTL = 0x2 + IP_UNBLOCK_SOURCE = 0x25 + IP_UNICAST_IF = 0x32 + IP_XFRM_POLICY = 0x11 + ISIG = 0x1 + ISTRIP = 0x20 + IUCLC = 0x200 + IUTF8 = 0x4000 + IXANY = 0x800 + IXOFF = 0x1000 + IXON = 0x400 + LINUX_REBOOT_CMD_CAD_OFF = 0x0 + LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef + LINUX_REBOOT_CMD_HALT = 0xcdef0123 + LINUX_REBOOT_CMD_KEXEC = 0x45584543 + LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc + LINUX_REBOOT_CMD_RESTART = 0x1234567 + LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4 + LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2 + LINUX_REBOOT_MAGIC1 = 0xfee1dead + LINUX_REBOOT_MAGIC2 = 0x28121969 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_DODUMP = 0x11 + MADV_DOFORK = 0xb + MADV_DONTDUMP = 0x10 + MADV_DONTFORK = 0xa + MADV_DONTNEED = 0x4 + MADV_FREE = 0x8 + MADV_HUGEPAGE = 0xe + MADV_HWPOISON = 0x64 + MADV_MERGEABLE = 0xc + MADV_NOHUGEPAGE = 0xf + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_REMOVE = 0x9 + MADV_SEQUENTIAL = 0x2 + MADV_UNMERGEABLE = 0xd + MADV_WILLNEED = 0x3 + MAP_ANON = 0x800 + MAP_ANONYMOUS = 0x800 + MAP_DENYWRITE = 0x2000 + MAP_EXECUTABLE = 0x4000 + MAP_FILE = 0x0 + MAP_FIXED = 0x10 + MAP_GROWSDOWN = 0x1000 + MAP_HUGETLB = 0x80000 + MAP_HUGE_MASK = 0x3f + MAP_HUGE_SHIFT = 0x1a + MAP_LOCKED = 0x8000 + MAP_NONBLOCK = 0x20000 + MAP_NORESERVE = 0x400 + MAP_POPULATE = 0x10000 + MAP_PRIVATE = 0x2 + MAP_RENAME = 0x800 + MAP_SHARED = 0x1 + MAP_STACK = 0x40000 + MAP_TYPE = 0xf + MCL_CURRENT = 0x1 + MCL_FUTURE = 0x2 + MCL_ONFAULT = 0x4 + MNT_DETACH = 0x2 + MNT_EXPIRE = 0x4 + MNT_FORCE = 0x1 + MSG_BATCH = 0x40000 + MSG_CMSG_CLOEXEC = 0x40000000 + MSG_CONFIRM = 0x800 + MSG_CTRUNC = 0x8 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x40 + MSG_EOR = 0x80 + MSG_ERRQUEUE = 0x2000 + MSG_FASTOPEN = 0x20000000 + MSG_FIN = 0x200 + MSG_MORE = 0x8000 + MSG_NOSIGNAL = 0x4000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_PROXY = 0x10 + MSG_RST = 0x1000 + MSG_SYN = 0x400 + MSG_TRUNC = 0x20 + MSG_TRYHARD = 0x4 + MSG_WAITALL = 0x100 + MSG_WAITFORONE = 0x10000 + MS_ACTIVE = 0x40000000 + MS_ASYNC = 0x1 + MS_BIND = 0x1000 + MS_DIRSYNC = 0x80 + MS_INVALIDATE = 0x2 + MS_I_VERSION = 0x800000 + MS_KERNMOUNT = 0x400000 + MS_LAZYTIME = 0x2000000 + MS_MANDLOCK = 0x40 + MS_MGC_MSK = 0xffff0000 + MS_MGC_VAL = 0xc0ed0000 + MS_MOVE = 0x2000 + MS_NOATIME = 0x400 + MS_NODEV = 0x4 + MS_NODIRATIME = 0x800 + MS_NOEXEC = 0x8 + MS_NOSUID = 0x2 + MS_NOUSER = -0x80000000 + MS_POSIXACL = 0x10000 + MS_PRIVATE = 0x40000 + MS_RDONLY = 0x1 + MS_REC = 0x4000 + MS_RELATIME = 0x200000 + MS_REMOUNT = 0x20 + MS_RMT_MASK = 0x2800051 + MS_SHARED = 0x100000 + MS_SILENT = 0x8000 + MS_SLAVE = 0x80000 + MS_STRICTATIME = 0x1000000 + MS_SYNC = 0x4 + MS_SYNCHRONOUS = 0x10 + MS_UNBINDABLE = 0x20000 + NAME_MAX = 0xff + NETLINK_ADD_MEMBERSHIP = 0x1 + NETLINK_AUDIT = 0x9 + NETLINK_BROADCAST_ERROR = 0x4 + NETLINK_CAP_ACK = 0xa + NETLINK_CONNECTOR = 0xb + NETLINK_CRYPTO = 0x15 + NETLINK_DNRTMSG = 0xe + NETLINK_DROP_MEMBERSHIP = 0x2 + NETLINK_ECRYPTFS = 0x13 + NETLINK_FIB_LOOKUP = 0xa + NETLINK_FIREWALL = 0x3 + NETLINK_GENERIC = 0x10 + NETLINK_INET_DIAG = 0x4 + NETLINK_IP6_FW = 0xd + NETLINK_ISCSI = 0x8 + NETLINK_KOBJECT_UEVENT = 0xf + NETLINK_LISTEN_ALL_NSID = 0x8 + NETLINK_LIST_MEMBERSHIPS = 0x9 + NETLINK_NETFILTER = 0xc + NETLINK_NFLOG = 0x5 + NETLINK_NO_ENOBUFS = 0x5 + NETLINK_PKTINFO = 0x3 + NETLINK_RDMA = 0x14 + NETLINK_ROUTE = 0x0 + NETLINK_RX_RING = 0x6 + NETLINK_SCSITRANSPORT = 0x12 + NETLINK_SELINUX = 0x7 + NETLINK_SOCK_DIAG = 0x4 + NETLINK_TX_RING = 0x7 + NETLINK_UNUSED = 0x1 + NETLINK_USERSOCK = 0x2 + NETLINK_XFRM = 0x6 + NL0 = 0x0 + NL1 = 0x100 + NLA_ALIGNTO = 0x4 + NLA_F_NESTED = 0x8000 + NLA_F_NET_BYTEORDER = 0x4000 + NLA_HDRLEN = 0x4 + NLDLY = 0x100 + NLMSG_ALIGNTO = 0x4 + NLMSG_DONE = 0x3 + NLMSG_ERROR = 0x2 + NLMSG_HDRLEN = 0x10 + NLMSG_MIN_TYPE = 0x10 + NLMSG_NOOP = 0x1 + NLMSG_OVERRUN = 0x4 + NLM_F_ACK = 0x4 + NLM_F_APPEND = 0x800 + NLM_F_ATOMIC = 0x400 + NLM_F_CREATE = 0x400 + NLM_F_DUMP = 0x300 + NLM_F_DUMP_FILTERED = 0x20 + NLM_F_DUMP_INTR = 0x10 + NLM_F_ECHO = 0x8 + NLM_F_EXCL = 0x200 + NLM_F_MATCH = 0x200 + NLM_F_MULTI = 0x2 + NLM_F_REPLACE = 0x100 + NLM_F_REQUEST = 0x1 + NLM_F_ROOT = 0x100 + NOFLSH = 0x80 + OCRNL = 0x8 + OFDEL = 0x80 + OFILL = 0x40 + OLCUC = 0x2 + ONLCR = 0x4 + ONLRET = 0x20 + ONOCR = 0x10 + OPOST = 0x1 + O_ACCMODE = 0x3 + O_APPEND = 0x8 + O_ASYNC = 0x1000 + O_CLOEXEC = 0x80000 + O_CREAT = 0x100 + O_DIRECT = 0x8000 + O_DIRECTORY = 0x10000 + O_DSYNC = 0x10 + O_EXCL = 0x400 + O_FSYNC = 0x4010 + O_LARGEFILE = 0x2000 + O_NDELAY = 0x80 + O_NOATIME = 0x40000 + O_NOCTTY = 0x800 + O_NOFOLLOW = 0x20000 + O_NONBLOCK = 0x80 + O_PATH = 0x200000 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_RSYNC = 0x4010 + O_SYNC = 0x4010 + O_TMPFILE = 0x410000 + O_TRUNC = 0x200 + O_WRONLY = 0x1 + PACKET_ADD_MEMBERSHIP = 0x1 + PACKET_AUXDATA = 0x8 + PACKET_BROADCAST = 0x1 + PACKET_COPY_THRESH = 0x7 + PACKET_DROP_MEMBERSHIP = 0x2 + PACKET_FANOUT = 0x12 + PACKET_FANOUT_CBPF = 0x6 + PACKET_FANOUT_CPU = 0x2 + PACKET_FANOUT_DATA = 0x16 + PACKET_FANOUT_EBPF = 0x7 + PACKET_FANOUT_FLAG_DEFRAG = 0x8000 + PACKET_FANOUT_FLAG_ROLLOVER = 0x1000 + PACKET_FANOUT_HASH = 0x0 + PACKET_FANOUT_LB = 0x1 + PACKET_FANOUT_QM = 0x5 + PACKET_FANOUT_RND = 0x4 + PACKET_FANOUT_ROLLOVER = 0x3 + PACKET_FASTROUTE = 0x6 + PACKET_HDRLEN = 0xb + PACKET_HOST = 0x0 + PACKET_KERNEL = 0x7 + PACKET_LOOPBACK = 0x5 + PACKET_LOSS = 0xe + PACKET_MR_ALLMULTI = 0x2 + PACKET_MR_MULTICAST = 0x0 + PACKET_MR_PROMISC = 0x1 + PACKET_MR_UNICAST = 0x3 + PACKET_MULTICAST = 0x2 + PACKET_ORIGDEV = 0x9 + PACKET_OTHERHOST = 0x3 + PACKET_OUTGOING = 0x4 + PACKET_QDISC_BYPASS = 0x14 + PACKET_RECV_OUTPUT = 0x3 + PACKET_RESERVE = 0xc + PACKET_ROLLOVER_STATS = 0x15 + PACKET_RX_RING = 0x5 + PACKET_STATISTICS = 0x6 + PACKET_TIMESTAMP = 0x11 + PACKET_TX_HAS_OFF = 0x13 + PACKET_TX_RING = 0xd + PACKET_TX_TIMESTAMP = 0x10 + PACKET_USER = 0x6 + PACKET_VERSION = 0xa + PACKET_VNET_HDR = 0xf + PARENB = 0x100 + PARITY_CRC16_PR0 = 0x2 + PARITY_CRC16_PR0_CCITT = 0x4 + PARITY_CRC16_PR1 = 0x3 + PARITY_CRC16_PR1_CCITT = 0x5 + PARITY_CRC32_PR0_CCITT = 0x6 + PARITY_CRC32_PR1_CCITT = 0x7 + PARITY_DEFAULT = 0x0 + PARITY_NONE = 0x1 + PARMRK = 0x8 + PARODD = 0x200 + PENDIN = 0x4000 + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROT_EXEC = 0x4 + PROT_GROWSDOWN = 0x1000000 + PROT_GROWSUP = 0x2000000 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + PR_CAPBSET_DROP = 0x18 + PR_CAPBSET_READ = 0x17 + PR_CAP_AMBIENT = 0x2f + PR_CAP_AMBIENT_CLEAR_ALL = 0x4 + PR_CAP_AMBIENT_IS_SET = 0x1 + PR_CAP_AMBIENT_LOWER = 0x3 + PR_CAP_AMBIENT_RAISE = 0x2 + PR_ENDIAN_BIG = 0x0 + PR_ENDIAN_LITTLE = 0x1 + PR_ENDIAN_PPC_LITTLE = 0x2 + PR_FPEMU_NOPRINT = 0x1 + PR_FPEMU_SIGFPE = 0x2 + PR_FP_EXC_ASYNC = 0x2 + PR_FP_EXC_DISABLED = 0x0 + PR_FP_EXC_DIV = 0x10000 + PR_FP_EXC_INV = 0x100000 + PR_FP_EXC_NONRECOV = 0x1 + PR_FP_EXC_OVF = 0x20000 + PR_FP_EXC_PRECISE = 0x3 + PR_FP_EXC_RES = 0x80000 + PR_FP_EXC_SW_ENABLE = 0x80 + PR_FP_EXC_UND = 0x40000 + PR_FP_MODE_FR = 0x1 + PR_FP_MODE_FRE = 0x2 + PR_GET_CHILD_SUBREAPER = 0x25 + PR_GET_DUMPABLE = 0x3 + PR_GET_ENDIAN = 0x13 + PR_GET_FPEMU = 0x9 + PR_GET_FPEXC = 0xb + PR_GET_FP_MODE = 0x2e + PR_GET_KEEPCAPS = 0x7 + PR_GET_NAME = 0x10 + PR_GET_NO_NEW_PRIVS = 0x27 + PR_GET_PDEATHSIG = 0x2 + PR_GET_SECCOMP = 0x15 + PR_GET_SECUREBITS = 0x1b + PR_GET_THP_DISABLE = 0x2a + PR_GET_TID_ADDRESS = 0x28 + PR_GET_TIMERSLACK = 0x1e + PR_GET_TIMING = 0xd + PR_GET_TSC = 0x19 + PR_GET_UNALIGN = 0x5 + PR_MCE_KILL = 0x21 + PR_MCE_KILL_CLEAR = 0x0 + PR_MCE_KILL_DEFAULT = 0x2 + PR_MCE_KILL_EARLY = 0x1 + PR_MCE_KILL_GET = 0x22 + PR_MCE_KILL_LATE = 0x0 + PR_MCE_KILL_SET = 0x1 + PR_MPX_DISABLE_MANAGEMENT = 0x2c + PR_MPX_ENABLE_MANAGEMENT = 0x2b + PR_SET_CHILD_SUBREAPER = 0x24 + PR_SET_DUMPABLE = 0x4 + PR_SET_ENDIAN = 0x14 + PR_SET_FPEMU = 0xa + PR_SET_FPEXC = 0xc + PR_SET_FP_MODE = 0x2d + PR_SET_KEEPCAPS = 0x8 + PR_SET_MM = 0x23 + PR_SET_MM_ARG_END = 0x9 + PR_SET_MM_ARG_START = 0x8 + PR_SET_MM_AUXV = 0xc + PR_SET_MM_BRK = 0x7 + PR_SET_MM_END_CODE = 0x2 + PR_SET_MM_END_DATA = 0x4 + PR_SET_MM_ENV_END = 0xb + PR_SET_MM_ENV_START = 0xa + PR_SET_MM_EXE_FILE = 0xd + PR_SET_MM_MAP = 0xe + PR_SET_MM_MAP_SIZE = 0xf + PR_SET_MM_START_BRK = 0x6 + PR_SET_MM_START_CODE = 0x1 + PR_SET_MM_START_DATA = 0x3 + PR_SET_MM_START_STACK = 0x5 + PR_SET_NAME = 0xf + PR_SET_NO_NEW_PRIVS = 0x26 + PR_SET_PDEATHSIG = 0x1 + PR_SET_PTRACER = 0x59616d61 + PR_SET_PTRACER_ANY = 0xffffffff + PR_SET_SECCOMP = 0x16 + PR_SET_SECUREBITS = 0x1c + PR_SET_THP_DISABLE = 0x29 + PR_SET_TIMERSLACK = 0x1d + PR_SET_TIMING = 0xe + PR_SET_TSC = 0x1a + PR_SET_UNALIGN = 0x6 + PR_TASK_PERF_EVENTS_DISABLE = 0x1f + PR_TASK_PERF_EVENTS_ENABLE = 0x20 + PR_TIMING_STATISTICAL = 0x0 + PR_TIMING_TIMESTAMP = 0x1 + PR_TSC_ENABLE = 0x1 + PR_TSC_SIGSEGV = 0x2 + PR_UNALIGN_NOPRINT = 0x1 + PR_UNALIGN_SIGBUS = 0x2 + PTRACE_ATTACH = 0x10 + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0x11 + PTRACE_EVENT_CLONE = 0x3 + PTRACE_EVENT_EXEC = 0x4 + PTRACE_EVENT_EXIT = 0x6 + PTRACE_EVENT_FORK = 0x1 + PTRACE_EVENT_SECCOMP = 0x7 + PTRACE_EVENT_STOP = 0x80 + PTRACE_EVENT_VFORK = 0x2 + PTRACE_EVENT_VFORK_DONE = 0x5 + PTRACE_GETEVENTMSG = 0x4201 + PTRACE_GETFPREGS = 0xe + PTRACE_GETREGS = 0xc + PTRACE_GETREGSET = 0x4204 + PTRACE_GETSIGINFO = 0x4202 + PTRACE_GETSIGMASK = 0x420a + PTRACE_GET_THREAD_AREA = 0x19 + PTRACE_GET_THREAD_AREA_3264 = 0xc4 + PTRACE_GET_WATCH_REGS = 0xd0 + PTRACE_INTERRUPT = 0x4207 + PTRACE_KILL = 0x8 + PTRACE_LISTEN = 0x4208 + PTRACE_OLDSETOPTIONS = 0x15 + PTRACE_O_EXITKILL = 0x100000 + PTRACE_O_MASK = 0x3000ff + PTRACE_O_SUSPEND_SECCOMP = 0x200000 + PTRACE_O_TRACECLONE = 0x8 + PTRACE_O_TRACEEXEC = 0x10 + PTRACE_O_TRACEEXIT = 0x40 + PTRACE_O_TRACEFORK = 0x2 + PTRACE_O_TRACESECCOMP = 0x80 + PTRACE_O_TRACESYSGOOD = 0x1 + PTRACE_O_TRACEVFORK = 0x4 + PTRACE_O_TRACEVFORKDONE = 0x20 + PTRACE_PEEKDATA = 0x2 + PTRACE_PEEKDATA_3264 = 0xc1 + PTRACE_PEEKSIGINFO = 0x4209 + PTRACE_PEEKSIGINFO_SHARED = 0x1 + PTRACE_PEEKTEXT = 0x1 + PTRACE_PEEKTEXT_3264 = 0xc0 + PTRACE_PEEKUSR = 0x3 + PTRACE_POKEDATA = 0x5 + PTRACE_POKEDATA_3264 = 0xc3 + PTRACE_POKETEXT = 0x4 + PTRACE_POKETEXT_3264 = 0xc2 + PTRACE_POKEUSR = 0x6 + PTRACE_SECCOMP_GET_FILTER = 0x420c + PTRACE_SEIZE = 0x4206 + PTRACE_SETFPREGS = 0xf + PTRACE_SETOPTIONS = 0x4200 + PTRACE_SETREGS = 0xd + PTRACE_SETREGSET = 0x4205 + PTRACE_SETSIGINFO = 0x4203 + PTRACE_SETSIGMASK = 0x420b + PTRACE_SET_THREAD_AREA = 0x1a + PTRACE_SET_WATCH_REGS = 0xd1 + PTRACE_SINGLESTEP = 0x9 + PTRACE_SYSCALL = 0x18 + PTRACE_TRACEME = 0x0 + RLIMIT_AS = 0x6 + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_NOFILE = 0x5 + RLIMIT_STACK = 0x3 + RLIM_INFINITY = -0x1 + RTAX_ADVMSS = 0x8 + RTAX_CC_ALGO = 0x10 + RTAX_CWND = 0x7 + RTAX_FEATURES = 0xc + RTAX_FEATURE_ALLFRAG = 0x8 + RTAX_FEATURE_ECN = 0x1 + RTAX_FEATURE_MASK = 0xf + RTAX_FEATURE_SACK = 0x2 + RTAX_FEATURE_TIMESTAMP = 0x4 + RTAX_HOPLIMIT = 0xa + RTAX_INITCWND = 0xb + RTAX_INITRWND = 0xe + RTAX_LOCK = 0x1 + RTAX_MAX = 0x10 + RTAX_MTU = 0x2 + RTAX_QUICKACK = 0xf + RTAX_REORDERING = 0x9 + RTAX_RTO_MIN = 0xd + RTAX_RTT = 0x4 + RTAX_RTTVAR = 0x5 + RTAX_SSTHRESH = 0x6 + RTAX_UNSPEC = 0x0 + RTAX_WINDOW = 0x3 + RTA_ALIGNTO = 0x4 + RTA_MAX = 0x18 + RTCF_DIRECTSRC = 0x4000000 + RTCF_DOREDIRECT = 0x1000000 + RTCF_LOG = 0x2000000 + RTCF_MASQ = 0x400000 + RTCF_NAT = 0x800000 + RTCF_VALVE = 0x200000 + RTF_ADDRCLASSMASK = 0xf8000000 + RTF_ADDRCONF = 0x40000 + RTF_ALLONLINK = 0x20000 + RTF_BROADCAST = 0x10000000 + RTF_CACHE = 0x1000000 + RTF_DEFAULT = 0x10000 + RTF_DYNAMIC = 0x10 + RTF_FLOW = 0x2000000 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_INTERFACE = 0x40000000 + RTF_IRTT = 0x100 + RTF_LINKRT = 0x100000 + RTF_LOCAL = 0x80000000 + RTF_MODIFIED = 0x20 + RTF_MSS = 0x40 + RTF_MTU = 0x40 + RTF_MULTICAST = 0x20000000 + RTF_NAT = 0x8000000 + RTF_NOFORWARD = 0x1000 + RTF_NONEXTHOP = 0x200000 + RTF_NOPMTUDISC = 0x4000 + RTF_POLICY = 0x4000000 + RTF_REINSTATE = 0x8 + RTF_REJECT = 0x200 + RTF_STATIC = 0x400 + RTF_THROW = 0x2000 + RTF_UP = 0x1 + RTF_WINDOW = 0x80 + RTF_XRESOLVE = 0x800 + RTM_BASE = 0x10 + RTM_DELACTION = 0x31 + RTM_DELADDR = 0x15 + RTM_DELADDRLABEL = 0x49 + RTM_DELLINK = 0x11 + RTM_DELMDB = 0x55 + RTM_DELNEIGH = 0x1d + RTM_DELNSID = 0x59 + RTM_DELQDISC = 0x25 + RTM_DELROUTE = 0x19 + RTM_DELRULE = 0x21 + RTM_DELTCLASS = 0x29 + RTM_DELTFILTER = 0x2d + RTM_F_CLONED = 0x200 + RTM_F_EQUALIZE = 0x400 + RTM_F_LOOKUP_TABLE = 0x1000 + RTM_F_NOTIFY = 0x100 + RTM_F_PREFIX = 0x800 + RTM_GETACTION = 0x32 + RTM_GETADDR = 0x16 + RTM_GETADDRLABEL = 0x4a + RTM_GETANYCAST = 0x3e + RTM_GETDCB = 0x4e + RTM_GETLINK = 0x12 + RTM_GETMDB = 0x56 + RTM_GETMULTICAST = 0x3a + RTM_GETNEIGH = 0x1e + RTM_GETNEIGHTBL = 0x42 + RTM_GETNETCONF = 0x52 + RTM_GETNSID = 0x5a + RTM_GETQDISC = 0x26 + RTM_GETROUTE = 0x1a + RTM_GETRULE = 0x22 + RTM_GETSTATS = 0x5e + RTM_GETTCLASS = 0x2a + RTM_GETTFILTER = 0x2e + RTM_MAX = 0x5f + RTM_NEWACTION = 0x30 + RTM_NEWADDR = 0x14 + RTM_NEWADDRLABEL = 0x48 + RTM_NEWLINK = 0x10 + RTM_NEWMDB = 0x54 + RTM_NEWNDUSEROPT = 0x44 + RTM_NEWNEIGH = 0x1c + RTM_NEWNEIGHTBL = 0x40 + RTM_NEWNETCONF = 0x50 + RTM_NEWNSID = 0x58 + RTM_NEWPREFIX = 0x34 + RTM_NEWQDISC = 0x24 + RTM_NEWROUTE = 0x18 + RTM_NEWRULE = 0x20 + RTM_NEWSTATS = 0x5c + RTM_NEWTCLASS = 0x28 + RTM_NEWTFILTER = 0x2c + RTM_NR_FAMILIES = 0x14 + RTM_NR_MSGTYPES = 0x50 + RTM_SETDCB = 0x4f + RTM_SETLINK = 0x13 + RTM_SETNEIGHTBL = 0x43 + RTNH_ALIGNTO = 0x4 + RTNH_COMPARE_MASK = 0x11 + RTNH_F_DEAD = 0x1 + RTNH_F_LINKDOWN = 0x10 + RTNH_F_OFFLOAD = 0x8 + RTNH_F_ONLINK = 0x4 + RTNH_F_PERVASIVE = 0x2 + RTN_MAX = 0xb + RTPROT_BABEL = 0x2a + RTPROT_BIRD = 0xc + RTPROT_BOOT = 0x3 + RTPROT_DHCP = 0x10 + RTPROT_DNROUTED = 0xd + RTPROT_GATED = 0x8 + RTPROT_KERNEL = 0x2 + RTPROT_MROUTED = 0x11 + RTPROT_MRT = 0xa + RTPROT_NTK = 0xf + RTPROT_RA = 0x9 + RTPROT_REDIRECT = 0x1 + RTPROT_STATIC = 0x4 + RTPROT_UNSPEC = 0x0 + RTPROT_XORP = 0xe + RTPROT_ZEBRA = 0xb + RT_CLASS_DEFAULT = 0xfd + RT_CLASS_LOCAL = 0xff + RT_CLASS_MAIN = 0xfe + RT_CLASS_MAX = 0xff + RT_CLASS_UNSPEC = 0x0 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + RUSAGE_THREAD = 0x1 + SCM_CREDENTIALS = 0x2 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x1d + SCM_TIMESTAMPING = 0x25 + SCM_TIMESTAMPNS = 0x23 + SCM_WIFI_STATUS = 0x29 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIOCADDDLCI = 0x8980 + SIOCADDMULTI = 0x8931 + SIOCADDRT = 0x890b + SIOCATMARK = 0x40047307 + SIOCDARP = 0x8953 + SIOCDELDLCI = 0x8981 + SIOCDELMULTI = 0x8932 + SIOCDELRT = 0x890c + SIOCDEVPRIVATE = 0x89f0 + SIOCDIFADDR = 0x8936 + SIOCDRARP = 0x8960 + SIOCGARP = 0x8954 + SIOCGIFADDR = 0x8915 + SIOCGIFBR = 0x8940 + SIOCGIFBRDADDR = 0x8919 + SIOCGIFCONF = 0x8912 + SIOCGIFCOUNT = 0x8938 + SIOCGIFDSTADDR = 0x8917 + SIOCGIFENCAP = 0x8925 + SIOCGIFFLAGS = 0x8913 + SIOCGIFHWADDR = 0x8927 + SIOCGIFINDEX = 0x8933 + SIOCGIFMAP = 0x8970 + SIOCGIFMEM = 0x891f + SIOCGIFMETRIC = 0x891d + SIOCGIFMTU = 0x8921 + SIOCGIFNAME = 0x8910 + SIOCGIFNETMASK = 0x891b + SIOCGIFPFLAGS = 0x8935 + SIOCGIFSLAVE = 0x8929 + SIOCGIFTXQLEN = 0x8942 + SIOCGPGRP = 0x40047309 + SIOCGRARP = 0x8961 + SIOCGSTAMP = 0x8906 + SIOCGSTAMPNS = 0x8907 + SIOCPROTOPRIVATE = 0x89e0 + SIOCRTMSG = 0x890d + SIOCSARP = 0x8955 + SIOCSIFADDR = 0x8916 + SIOCSIFBR = 0x8941 + SIOCSIFBRDADDR = 0x891a + SIOCSIFDSTADDR = 0x8918 + SIOCSIFENCAP = 0x8926 + SIOCSIFFLAGS = 0x8914 + SIOCSIFHWADDR = 0x8924 + SIOCSIFHWBROADCAST = 0x8937 + SIOCSIFLINK = 0x8911 + SIOCSIFMAP = 0x8971 + SIOCSIFMEM = 0x8920 + SIOCSIFMETRIC = 0x891e + SIOCSIFMTU = 0x8922 + SIOCSIFNAME = 0x8923 + SIOCSIFNETMASK = 0x891c + SIOCSIFPFLAGS = 0x8934 + SIOCSIFSLAVE = 0x8930 + SIOCSIFTXQLEN = 0x8943 + SIOCSPGRP = 0x80047308 + SIOCSRARP = 0x8962 + SOCK_CLOEXEC = 0x80000 + SOCK_DCCP = 0x6 + SOCK_DGRAM = 0x1 + SOCK_NONBLOCK = 0x80 + SOCK_PACKET = 0xa + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x2 + SOL_AAL = 0x109 + SOL_ALG = 0x117 + SOL_ATM = 0x108 + SOL_CAIF = 0x116 + SOL_CAN_BASE = 0x64 + SOL_DCCP = 0x10d + SOL_DECNET = 0x105 + SOL_ICMPV6 = 0x3a + SOL_IP = 0x0 + SOL_IPV6 = 0x29 + SOL_IRDA = 0x10a + SOL_IUCV = 0x115 + SOL_KCM = 0x119 + SOL_LLC = 0x10c + SOL_NETBEUI = 0x10b + SOL_NETLINK = 0x10e + SOL_NFC = 0x118 + SOL_PACKET = 0x107 + SOL_PNPIPE = 0x113 + SOL_PPPOL2TP = 0x111 + SOL_RAW = 0xff + SOL_RDS = 0x114 + SOL_RXRPC = 0x110 + SOL_SOCKET = 0xffff + SOL_TCP = 0x6 + SOL_TIPC = 0x10f + SOL_X25 = 0x106 + SOMAXCONN = 0x80 + SO_ACCEPTCONN = 0x1009 + SO_ATTACH_BPF = 0x32 + SO_ATTACH_FILTER = 0x1a + SO_ATTACH_REUSEPORT_CBPF = 0x33 + SO_ATTACH_REUSEPORT_EBPF = 0x34 + SO_BINDTODEVICE = 0x19 + SO_BPF_EXTENSIONS = 0x30 + SO_BROADCAST = 0x20 + SO_BSDCOMPAT = 0xe + SO_BUSY_POLL = 0x2e + SO_CNX_ADVICE = 0x35 + SO_DEBUG = 0x1 + SO_DETACH_BPF = 0x1b + SO_DETACH_FILTER = 0x1b + SO_DOMAIN = 0x1029 + SO_DONTROUTE = 0x10 + SO_ERROR = 0x1007 + SO_GET_FILTER = 0x1a + SO_INCOMING_CPU = 0x31 + SO_KEEPALIVE = 0x8 + SO_LINGER = 0x80 + SO_LOCK_FILTER = 0x2c + SO_MARK = 0x24 + SO_MAX_PACING_RATE = 0x2f + SO_NOFCS = 0x2b + SO_NO_CHECK = 0xb + SO_OOBINLINE = 0x100 + SO_PASSCRED = 0x11 + SO_PASSSEC = 0x22 + SO_PEEK_OFF = 0x2a + SO_PEERCRED = 0x12 + SO_PEERNAME = 0x1c + SO_PEERSEC = 0x1e + SO_PRIORITY = 0xc + SO_PROTOCOL = 0x1028 + SO_RCVBUF = 0x1002 + SO_RCVBUFFORCE = 0x21 + SO_RCVLOWAT = 0x1004 + SO_RCVTIMEO = 0x1006 + SO_REUSEADDR = 0x4 + SO_REUSEPORT = 0x200 + SO_RXQ_OVFL = 0x28 + SO_SECURITY_AUTHENTICATION = 0x16 + SO_SECURITY_ENCRYPTION_NETWORK = 0x18 + SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17 + SO_SELECT_ERR_QUEUE = 0x2d + SO_SNDBUF = 0x1001 + SO_SNDBUFFORCE = 0x1f + SO_SNDLOWAT = 0x1003 + SO_SNDTIMEO = 0x1005 + SO_STYLE = 0x1008 + SO_TIMESTAMP = 0x1d + SO_TIMESTAMPING = 0x25 + SO_TIMESTAMPNS = 0x23 + SO_TYPE = 0x1008 + SO_WIFI_STATUS = 0x29 + S_BLKSIZE = 0x200 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + TAB0 = 0x0 + TAB1 = 0x800 + TAB2 = 0x1000 + TAB3 = 0x1800 + TABDLY = 0x1800 + TCFLSH = 0x5407 + TCGETA = 0x5401 + TCGETS = 0x540d + TCGETS2 = 0x4030542a + TCIFLUSH = 0x0 + TCIOFF = 0x2 + TCIOFLUSH = 0x2 + TCION = 0x3 + TCOFLUSH = 0x1 + TCOOFF = 0x0 + TCOON = 0x1 + TCP_CC_INFO = 0x1a + TCP_CONGESTION = 0xd + TCP_COOKIE_IN_ALWAYS = 0x1 + TCP_COOKIE_MAX = 0x10 + TCP_COOKIE_MIN = 0x8 + TCP_COOKIE_OUT_NEVER = 0x2 + TCP_COOKIE_PAIR_SIZE = 0x20 + TCP_COOKIE_TRANSACTIONS = 0xf + TCP_CORK = 0x3 + TCP_DEFER_ACCEPT = 0x9 + TCP_FASTOPEN = 0x17 + TCP_INFO = 0xb + TCP_KEEPCNT = 0x6 + TCP_KEEPIDLE = 0x4 + TCP_KEEPINTVL = 0x5 + TCP_LINGER2 = 0x8 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAX_WINSHIFT = 0xe + TCP_MD5SIG = 0xe + TCP_MD5SIG_MAXKEYLEN = 0x50 + TCP_MSS = 0x200 + TCP_MSS_DEFAULT = 0x218 + TCP_MSS_DESIRED = 0x4c4 + TCP_NODELAY = 0x1 + TCP_NOTSENT_LOWAT = 0x19 + TCP_QUEUE_SEQ = 0x15 + TCP_QUICKACK = 0xc + TCP_REPAIR = 0x13 + TCP_REPAIR_OPTIONS = 0x16 + TCP_REPAIR_QUEUE = 0x14 + TCP_SAVED_SYN = 0x1c + TCP_SAVE_SYN = 0x1b + TCP_SYNCNT = 0x7 + TCP_S_DATA_IN = 0x4 + TCP_S_DATA_OUT = 0x8 + TCP_THIN_DUPACK = 0x11 + TCP_THIN_LINEAR_TIMEOUTS = 0x10 + TCP_TIMESTAMP = 0x18 + TCP_USER_TIMEOUT = 0x12 + TCP_WINDOW_CLAMP = 0xa + TCSAFLUSH = 0x5410 + TCSBRK = 0x5405 + TCSBRKP = 0x5486 + TCSETA = 0x5402 + TCSETAF = 0x5404 + TCSETAW = 0x5403 + TCSETS = 0x540e + TCSETS2 = 0x8030542b + TCSETSF = 0x5410 + TCSETSF2 = 0x8030542d + TCSETSW = 0x540f + TCSETSW2 = 0x8030542c + TCXONC = 0x5406 + TIOCCBRK = 0x5428 + TIOCCONS = 0x80047478 + TIOCEXCL = 0x740d + TIOCGDEV = 0x40045432 + TIOCGETD = 0x7400 + TIOCGETP = 0x7408 + TIOCGEXCL = 0x40045440 + TIOCGICOUNT = 0x5492 + TIOCGLCKTRMIOS = 0x548b + TIOCGLTC = 0x7474 + TIOCGPGRP = 0x40047477 + TIOCGPKT = 0x40045438 + TIOCGPTLCK = 0x40045439 + TIOCGPTN = 0x40045430 + TIOCGRS485 = 0x4020542e + TIOCGSERIAL = 0x5484 + TIOCGSID = 0x7416 + TIOCGSOFTCAR = 0x5481 + TIOCGWINSZ = 0x40087468 + TIOCINQ = 0x467f + TIOCLINUX = 0x5483 + TIOCMBIC = 0x741c + TIOCMBIS = 0x741b + TIOCMGET = 0x741d + TIOCMIWAIT = 0x5491 + TIOCMSET = 0x741a + TIOCM_CAR = 0x100 + TIOCM_CD = 0x100 + TIOCM_CTS = 0x40 + TIOCM_DSR = 0x400 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x200 + TIOCM_RNG = 0x200 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x20 + TIOCM_ST = 0x10 + TIOCNOTTY = 0x5471 + TIOCNXCL = 0x740e + TIOCOUTQ = 0x7472 + TIOCPKT = 0x5470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_IOCTL = 0x40 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCSBRK = 0x5427 + TIOCSCTTY = 0x5480 + TIOCSERCONFIG = 0x5488 + TIOCSERGETLSR = 0x548e + TIOCSERGETMULTI = 0x548f + TIOCSERGSTRUCT = 0x548d + TIOCSERGWILD = 0x5489 + TIOCSERSETMULTI = 0x5490 + TIOCSERSWILD = 0x548a + TIOCSER_TEMT = 0x1 + TIOCSETD = 0x7401 + TIOCSETN = 0x740a + TIOCSETP = 0x7409 + TIOCSIG = 0x80045436 + TIOCSLCKTRMIOS = 0x548c + TIOCSLTC = 0x7475 + TIOCSPGRP = 0x80047476 + TIOCSPTLCK = 0x80045431 + TIOCSRS485 = 0xc020542f + TIOCSSERIAL = 0x5485 + TIOCSSOFTCAR = 0x5482 + TIOCSTI = 0x5472 + TIOCSWINSZ = 0x80087467 + TIOCVHANGUP = 0x5437 + TOSTOP = 0x8000 + TUNATTACHFILTER = 0x800854d5 + TUNDETACHFILTER = 0x800854d6 + TUNGETFEATURES = 0x400454cf + TUNGETFILTER = 0x400854db + TUNGETIFF = 0x400454d2 + TUNGETSNDBUF = 0x400454d3 + TUNGETVNETBE = 0x400454df + TUNGETVNETHDRSZ = 0x400454d7 + TUNGETVNETLE = 0x400454dd + TUNSETDEBUG = 0x800454c9 + TUNSETGROUP = 0x800454ce + TUNSETIFF = 0x800454ca + TUNSETIFINDEX = 0x800454da + TUNSETLINK = 0x800454cd + TUNSETNOCSUM = 0x800454c8 + TUNSETOFFLOAD = 0x800454d0 + TUNSETOWNER = 0x800454cc + TUNSETPERSIST = 0x800454cb + TUNSETQUEUE = 0x800454d9 + TUNSETSNDBUF = 0x800454d4 + TUNSETTXFILTER = 0x800454d1 + TUNSETVNETBE = 0x800454de + TUNSETVNETHDRSZ = 0x800454d8 + TUNSETVNETLE = 0x800454dc + VDISCARD = 0xd + VEOF = 0x10 + VEOL = 0x11 + VEOL2 = 0x6 + VERASE = 0x2 + VINTR = 0x0 + VKILL = 0x3 + VLNEXT = 0xf + VMIN = 0x4 + VQUIT = 0x1 + VREPRINT = 0xc + VSTART = 0x8 + VSTOP = 0x9 + VSUSP = 0xa + VSWTC = 0x7 + VSWTCH = 0x7 + VT0 = 0x0 + VT1 = 0x4000 + VTDLY = 0x4000 + VTIME = 0x5 + VWERASE = 0xe + WALL = 0x40000000 + WCLONE = 0x80000000 + WCONTINUED = 0x8 + WEXITED = 0x4 + WNOHANG = 0x1 + WNOTHREAD = 0x20000000 + WNOWAIT = 0x1000000 + WORDSIZE = 0x20 + WSTOPPED = 0x2 + WUNTRACED = 0x2 + XCASE = 0x4 + XTABS = 0x1800 +) + +// Errors +const ( + E2BIG = syscall.Errno(0x7) + EACCES = syscall.Errno(0xd) + EADDRINUSE = syscall.Errno(0x7d) + EADDRNOTAVAIL = syscall.Errno(0x7e) + EADV = syscall.Errno(0x44) + EAFNOSUPPORT = syscall.Errno(0x7c) + EAGAIN = syscall.Errno(0xb) + EALREADY = syscall.Errno(0x95) + EBADE = syscall.Errno(0x32) + EBADF = syscall.Errno(0x9) + EBADFD = syscall.Errno(0x51) + EBADMSG = syscall.Errno(0x4d) + EBADR = syscall.Errno(0x33) + EBADRQC = syscall.Errno(0x36) + EBADSLT = syscall.Errno(0x37) + EBFONT = syscall.Errno(0x3b) + EBUSY = syscall.Errno(0x10) + ECANCELED = syscall.Errno(0x9e) + ECHILD = syscall.Errno(0xa) + ECHRNG = syscall.Errno(0x25) + ECOMM = syscall.Errno(0x46) + ECONNABORTED = syscall.Errno(0x82) + ECONNREFUSED = syscall.Errno(0x92) + ECONNRESET = syscall.Errno(0x83) + EDEADLK = syscall.Errno(0x2d) + EDEADLOCK = syscall.Errno(0x38) + EDESTADDRREQ = syscall.Errno(0x60) + EDOM = syscall.Errno(0x21) + EDOTDOT = syscall.Errno(0x49) + EDQUOT = syscall.Errno(0x46d) + EEXIST = syscall.Errno(0x11) + EFAULT = syscall.Errno(0xe) + EFBIG = syscall.Errno(0x1b) + EHOSTDOWN = syscall.Errno(0x93) + EHOSTUNREACH = syscall.Errno(0x94) + EHWPOISON = syscall.Errno(0xa8) + EIDRM = syscall.Errno(0x24) + EILSEQ = syscall.Errno(0x58) + EINIT = syscall.Errno(0x8d) + EINPROGRESS = syscall.Errno(0x96) + EINTR = syscall.Errno(0x4) + EINVAL = syscall.Errno(0x16) + EIO = syscall.Errno(0x5) + EISCONN = syscall.Errno(0x85) + EISDIR = syscall.Errno(0x15) + EISNAM = syscall.Errno(0x8b) + EKEYEXPIRED = syscall.Errno(0xa2) + EKEYREJECTED = syscall.Errno(0xa4) + EKEYREVOKED = syscall.Errno(0xa3) + EL2HLT = syscall.Errno(0x2c) + EL2NSYNC = syscall.Errno(0x26) + EL3HLT = syscall.Errno(0x27) + EL3RST = syscall.Errno(0x28) + ELIBACC = syscall.Errno(0x53) + ELIBBAD = syscall.Errno(0x54) + ELIBEXEC = syscall.Errno(0x57) + ELIBMAX = syscall.Errno(0x56) + ELIBSCN = syscall.Errno(0x55) + ELNRNG = syscall.Errno(0x29) + ELOOP = syscall.Errno(0x5a) + EMEDIUMTYPE = syscall.Errno(0xa0) + EMFILE = syscall.Errno(0x18) + EMLINK = syscall.Errno(0x1f) + EMSGSIZE = syscall.Errno(0x61) + EMULTIHOP = syscall.Errno(0x4a) + ENAMETOOLONG = syscall.Errno(0x4e) + ENAVAIL = syscall.Errno(0x8a) + ENETDOWN = syscall.Errno(0x7f) + ENETRESET = syscall.Errno(0x81) + ENETUNREACH = syscall.Errno(0x80) + ENFILE = syscall.Errno(0x17) + ENOANO = syscall.Errno(0x35) + ENOBUFS = syscall.Errno(0x84) + ENOCSI = syscall.Errno(0x2b) + ENODATA = syscall.Errno(0x3d) + ENODEV = syscall.Errno(0x13) + ENOENT = syscall.Errno(0x2) + ENOEXEC = syscall.Errno(0x8) + ENOKEY = syscall.Errno(0xa1) + ENOLCK = syscall.Errno(0x2e) + ENOLINK = syscall.Errno(0x43) + ENOMEDIUM = syscall.Errno(0x9f) + ENOMEM = syscall.Errno(0xc) + ENOMSG = syscall.Errno(0x23) + ENONET = syscall.Errno(0x40) + ENOPKG = syscall.Errno(0x41) + ENOPROTOOPT = syscall.Errno(0x63) + ENOSPC = syscall.Errno(0x1c) + ENOSR = syscall.Errno(0x3f) + ENOSTR = syscall.Errno(0x3c) + ENOSYS = syscall.Errno(0x59) + ENOTBLK = syscall.Errno(0xf) + ENOTCONN = syscall.Errno(0x86) + ENOTDIR = syscall.Errno(0x14) + ENOTEMPTY = syscall.Errno(0x5d) + ENOTNAM = syscall.Errno(0x89) + ENOTRECOVERABLE = syscall.Errno(0xa6) + ENOTSOCK = syscall.Errno(0x5f) + ENOTSUP = syscall.Errno(0x7a) + ENOTTY = syscall.Errno(0x19) + ENOTUNIQ = syscall.Errno(0x50) + ENXIO = syscall.Errno(0x6) + EOPNOTSUPP = syscall.Errno(0x7a) + EOVERFLOW = syscall.Errno(0x4f) + EOWNERDEAD = syscall.Errno(0xa5) + EPERM = syscall.Errno(0x1) + EPFNOSUPPORT = syscall.Errno(0x7b) + EPIPE = syscall.Errno(0x20) + EPROTO = syscall.Errno(0x47) + EPROTONOSUPPORT = syscall.Errno(0x78) + EPROTOTYPE = syscall.Errno(0x62) + ERANGE = syscall.Errno(0x22) + EREMCHG = syscall.Errno(0x52) + EREMDEV = syscall.Errno(0x8e) + EREMOTE = syscall.Errno(0x42) + EREMOTEIO = syscall.Errno(0x8c) + ERESTART = syscall.Errno(0x5b) + ERFKILL = syscall.Errno(0xa7) + EROFS = syscall.Errno(0x1e) + ESHUTDOWN = syscall.Errno(0x8f) + ESOCKTNOSUPPORT = syscall.Errno(0x79) + ESPIPE = syscall.Errno(0x1d) + ESRCH = syscall.Errno(0x3) + ESRMNT = syscall.Errno(0x45) + ESTALE = syscall.Errno(0x97) + ESTRPIPE = syscall.Errno(0x5c) + ETIME = syscall.Errno(0x3e) + ETIMEDOUT = syscall.Errno(0x91) + ETOOMANYREFS = syscall.Errno(0x90) + ETXTBSY = syscall.Errno(0x1a) + EUCLEAN = syscall.Errno(0x87) + EUNATCH = syscall.Errno(0x2a) + EUSERS = syscall.Errno(0x5e) + EWOULDBLOCK = syscall.Errno(0xb) + EXDEV = syscall.Errno(0x12) + EXFULL = syscall.Errno(0x34) +) + +// Signals +const ( + SIGABRT = syscall.Signal(0x6) + SIGALRM = syscall.Signal(0xe) + SIGBUS = syscall.Signal(0xa) + SIGCHLD = syscall.Signal(0x12) + SIGCLD = syscall.Signal(0x12) + SIGCONT = syscall.Signal(0x19) + SIGEMT = syscall.Signal(0x7) + SIGFPE = syscall.Signal(0x8) + SIGHUP = syscall.Signal(0x1) + SIGILL = syscall.Signal(0x4) + SIGINT = syscall.Signal(0x2) + SIGIO = syscall.Signal(0x16) + SIGIOT = syscall.Signal(0x6) + SIGKILL = syscall.Signal(0x9) + SIGPIPE = syscall.Signal(0xd) + SIGPOLL = syscall.Signal(0x16) + SIGPROF = syscall.Signal(0x1d) + SIGPWR = syscall.Signal(0x13) + SIGQUIT = syscall.Signal(0x3) + SIGSEGV = syscall.Signal(0xb) + SIGSTOP = syscall.Signal(0x17) + SIGSYS = syscall.Signal(0xc) + SIGTERM = syscall.Signal(0xf) + SIGTRAP = syscall.Signal(0x5) + SIGTSTP = syscall.Signal(0x18) + SIGTTIN = syscall.Signal(0x1a) + SIGTTOU = syscall.Signal(0x1b) + SIGURG = syscall.Signal(0x15) + SIGUSR1 = syscall.Signal(0x10) + SIGUSR2 = syscall.Signal(0x11) + SIGVTALRM = syscall.Signal(0x1c) + SIGWINCH = syscall.Signal(0x14) + SIGXCPU = syscall.Signal(0x1e) + SIGXFSZ = syscall.Signal(0x1f) +) + +// Error table +var errors = [...]string{ + 1: "operation not permitted", + 2: "no such file or directory", + 3: "no such process", + 4: "interrupted system call", + 5: "input/output error", + 6: "no such device or address", + 7: "argument list too long", + 8: "exec format error", + 9: "bad file descriptor", + 10: "no child processes", + 11: "resource temporarily unavailable", + 12: "cannot allocate memory", + 13: "permission denied", + 14: "bad address", + 15: "block device required", + 16: "device or resource busy", + 17: "file exists", + 18: "invalid cross-device link", + 19: "no such device", + 20: "not a directory", + 21: "is a directory", + 22: "invalid argument", + 23: "too many open files in system", + 24: "too many open files", + 25: "inappropriate ioctl for device", + 26: "text file busy", + 27: "file too large", + 28: "no space left on device", + 29: "illegal seek", + 30: "read-only file system", + 31: "too many links", + 32: "broken pipe", + 33: "numerical argument out of domain", + 34: "numerical result out of range", + 35: "no message of desired type", + 36: "identifier removed", + 37: "channel number out of range", + 38: "level 2 not synchronized", + 39: "level 3 halted", + 40: "level 3 reset", + 41: "link number out of range", + 42: "protocol driver not attached", + 43: "no CSI structure available", + 44: "level 2 halted", + 45: "resource deadlock avoided", + 46: "no locks available", + 50: "invalid exchange", + 51: "invalid request descriptor", + 52: "exchange full", + 53: "no anode", + 54: "invalid request code", + 55: "invalid slot", + 56: "file locking deadlock error", + 59: "bad font file format", + 60: "device not a stream", + 61: "no data available", + 62: "timer expired", + 63: "out of streams resources", + 64: "machine is not on the network", + 65: "package not installed", + 66: "object is remote", + 67: "link has been severed", + 68: "advertise error", + 69: "srmount error", + 70: "communication error on send", + 71: "protocol error", + 73: "RFS specific error", + 74: "multihop attempted", + 77: "bad message", + 78: "file name too long", + 79: "value too large for defined data type", + 80: "name not unique on network", + 81: "file descriptor in bad state", + 82: "remote address changed", + 83: "can not access a needed shared library", + 84: "accessing a corrupted shared library", + 85: ".lib section in a.out corrupted", + 86: "attempting to link in too many shared libraries", + 87: "cannot exec a shared library directly", + 88: "invalid or incomplete multibyte or wide character", + 89: "function not implemented", + 90: "too many levels of symbolic links", + 91: "interrupted system call should be restarted", + 92: "streams pipe error", + 93: "directory not empty", + 94: "too many users", + 95: "socket operation on non-socket", + 96: "destination address required", + 97: "message too long", + 98: "protocol wrong type for socket", + 99: "protocol not available", + 120: "protocol not supported", + 121: "socket type not supported", + 122: "operation not supported", + 123: "protocol family not supported", + 124: "address family not supported by protocol", + 125: "address already in use", + 126: "cannot assign requested address", + 127: "network is down", + 128: "network is unreachable", + 129: "network dropped connection on reset", + 130: "software caused connection abort", + 131: "connection reset by peer", + 132: "no buffer space available", + 133: "transport endpoint is already connected", + 134: "transport endpoint is not connected", + 135: "structure needs cleaning", + 137: "not a XENIX named type file", + 138: "no XENIX semaphores available", + 139: "is a named type file", + 140: "remote I/O error", + 141: "unknown error 141", + 142: "unknown error 142", + 143: "cannot send after transport endpoint shutdown", + 144: "too many references: cannot splice", + 145: "connection timed out", + 146: "connection refused", + 147: "host is down", + 148: "no route to host", + 149: "operation already in progress", + 150: "operation now in progress", + 151: "stale file handle", + 158: "operation canceled", + 159: "no medium found", + 160: "wrong medium type", + 161: "required key not available", + 162: "key has expired", + 163: "key has been revoked", + 164: "key was rejected by service", + 165: "owner died", + 166: "state not recoverable", + 167: "operation not possible due to RF-kill", + 168: "memory page has hardware error", + 1133: "disk quota exceeded", +} + +// Signal table +var signals = [...]string{ + 1: "hangup", + 2: "interrupt", + 3: "quit", + 4: "illegal instruction", + 5: "trace/breakpoint trap", + 6: "aborted", + 7: "EMT trap", + 8: "floating point exception", + 9: "killed", + 10: "bus error", + 11: "segmentation fault", + 12: "bad system call", + 13: "broken pipe", + 14: "alarm clock", + 15: "terminated", + 16: "user defined signal 1", + 17: "user defined signal 2", + 18: "child exited", + 19: "power failure", + 20: "window changed", + 21: "urgent I/O condition", + 22: "I/O possible", + 23: "stopped (signal)", + 24: "stopped", + 25: "continued", + 26: "stopped (tty input)", + 27: "stopped (tty output)", + 28: "virtual timer expired", + 29: "profiling timer expired", + 30: "CPU time limit exceeded", + 31: "file size limit exceeded", +} diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 8b42ca2fe9..4e4193951b 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -197,6 +197,25 @@ const ( BS0 = 0x0 BS1 = 0x8000 BSDLY = 0x8000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0xff CBAUDEX = 0x0 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index e8d12b5d6d..407e6b5392 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -196,6 +196,25 @@ const ( BS0 = 0x0 BS1 = 0x8000 BSDLY = 0x8000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0xff CBAUDEX = 0x0 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 329f25e7cf..40c9b87931 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -201,6 +201,25 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 766d1e6128..62680ed8aa 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -205,6 +205,25 @@ const ( BS0 = 0x0 BS1 = 0x2000 BSDLY = 0x2000 + CAN_BCM = 0x2 + CAN_EFF_FLAG = 0x80000000 + CAN_EFF_ID_BITS = 0x1d + CAN_EFF_MASK = 0x1fffffff + CAN_ERR_FLAG = 0x20000000 + CAN_ERR_MASK = 0x1fffffff + CAN_INV_FILTER = 0x20000000 + CAN_ISOTP = 0x6 + CAN_MAX_DLC = 0x8 + CAN_MAX_DLEN = 0x8 + CAN_MCNET = 0x5 + CAN_MTU = 0x10 + CAN_NPROTO = 0x7 + CAN_RAW = 0x1 + CAN_RTR_FLAG = 0x40000000 + CAN_SFF_ID_BITS = 0xb + CAN_SFF_MASK = 0x7ff + CAN_TP16 = 0x3 + CAN_TP20 = 0x4 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go index 80f6a1b0ad..fa92387b1a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go index 078c8f05af..b34d5c26f0 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go index 76e5f7c0bb..2e5cb39845 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go index 72b79470a2..0d584cc0de 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go new file mode 100644 index 0000000000..a18e0b1712 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go @@ -0,0 +1,1829 @@ +// mksyscall.pl -b32 -arm syscall_linux.go syscall_linux_mipsx.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// +build mips,linux + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0) + use(unsafe.Pointer(_p0)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + use(unsafe.Pointer(_p0)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(source) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(target) + if err != nil { + return + } + var _p2 *byte + _p2, err = BytePtrFromString(fstype) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + use(unsafe.Pointer(_p2)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Acct(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtimex(buf *Timex) (state int, err error) { + r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0) + state = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ClockGettime(clockid int32, time *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(oldfd int) (fd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup3(oldfd int, newfd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate1(flag int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { + _, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fdatasync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdents(fd int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettid() (tid int) { + r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + tid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getxattr(path string, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(dest) > 0 { + _p2 = unsafe.Pointer(&dest[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(pathname) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask)) + use(unsafe.Pointer(_p0)) + watchdesc = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyInit1(flags int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0) + success = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kill(pid int, sig syscall.Signal) (err error) { + _, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Klogctl(typ int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listxattr(path string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + use(unsafe.Pointer(_p0)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Nanosleep(time *Timespec, leftover *Timespec) (err error) { + _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func PivotRoot(newroot string, putold string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(newroot) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(putold) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PRCTL, uintptr(option), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Removexattr(path string, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setdomainname(p []byte) (err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sethostname(p []byte) (err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setns(fd int, nstype int) (err error) { + _, _, e1 := Syscall(SYS_SETNS, uintptr(fd), uintptr(nstype), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setxattr(path string, attr string, data []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(data) > 0 { + _p2 = unsafe.Pointer(&data[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() { + Syscall(SYS_SYNC, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sysinfo(info *Sysinfo_t) (err error) { + _, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { + r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0) + n = int64(int64(r0)<<32 | int64(r1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) { + _, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Times(tms *Tms) (ticks uintptr, err error) { + r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0) + ticks = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(mask int) (oldmask int) { + r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Uname(buf *Utsname) (err error) { + _, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(target string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(target) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unshare(flags int) (err error) { + _, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func exitThread(code int) (err error) { + _, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, p *byte, np int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, p *byte, np int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, advice int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(oldfd int, newfd int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length>>32), uintptr(length), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (euid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + euid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, n int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset>>32), uintptr(offset)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset>>32), uintptr(offset)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { + r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) + written = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setfsgid(gid int) (err error) { + _, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setfsuid(uid int) (err error) { + _, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresgid(rgid int, egid int, sgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresuid(ruid int, euid int, suid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) { + r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) + n = int64(int64(r0)<<32 | int64(r1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func SyncFileRange(fd int, off int64, n int64, flags int) (err error) { + _, _, e1 := Syscall9(SYS_SYNC_FILE_RANGE, uintptr(fd), 0, uintptr(off>>32), uintptr(off), uintptr(n>>32), uintptr(n), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length>>32), uintptr(length), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(n int, list *_Gid_t) (nn int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + nn = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(n int, list *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyInit() (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ioperm(from int, num int, on int) (err error) { + _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Iopl(level int) (err error) { + _, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Time(t *Time_t) (tt Time_t, err error) { + r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0) + tt = Time_t(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pause() (err error) { + _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe2(p *[2]_C_int, flags int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset)) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getrlimit(resource int, rlim *rlimit32) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setrlimit(resource int, rlim *rlimit32) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go index ba55509ea0..bf6f3603ba 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go index 2b1cc8473b..8c86bd70b3 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go new file mode 100644 index 0000000000..645e00ebd6 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go @@ -0,0 +1,1829 @@ +// mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_mipsx.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// +build mipsle,linux + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0) + use(unsafe.Pointer(_p0)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Readlinkat(dirfd int, path string, buf []byte) (n int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(buf) > 0 { + _p1 = unsafe.Pointer(&buf[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0) + use(unsafe.Pointer(_p0)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1))) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unlinkat(dirfd int, path string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags)) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getcwd(buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) { + r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0) + wpid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(source) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(target) + if err != nil { + return + } + var _p2 *byte + _p2, err = BytePtrFromString(fstype) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + use(unsafe.Pointer(_p2)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Acct(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Adjtimex(buf *Timex) (state int, err error) { + r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0) + state = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chdir(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Chroot(path string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ClockGettime(clockid int32, time *Timespec) (err error) { + _, _, e1 := Syscall(SYS_CLOCK_GETTIME, uintptr(clockid), uintptr(unsafe.Pointer(time)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Close(fd int) (err error) { + _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup(oldfd int) (fd int, err error) { + r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup3(oldfd int, newfd int, flags int) (err error) { + _, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate1(flag int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { + _, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Exit(code int) { + Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { + _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchdir(fd int) (err error) { + _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmod(fd int, mode uint32) (err error) { + _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func fcntl(fd int, cmd int, arg int) (val int, err error) { + r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)) + val = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fdatasync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Flock(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fsync(fd int) (err error) { + _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getdents(fd int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0) + pgid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpid() (pid int) { + r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getppid() (ppid int) { + r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + ppid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getpriority(which int, who int) (prio int, err error) { + r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0) + prio = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getrusage(who int, rusage *Rusage) (err error) { + _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettid() (tid int) { + r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + tid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getxattr(path string, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(dest) > 0 { + _p2 = unsafe.Pointer(&dest[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(pathname) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask)) + use(unsafe.Pointer(_p0)) + watchdesc = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyInit1(flags int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0) + success = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Kill(pid int, sig syscall.Signal) (err error) { + _, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Klogctl(typ int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listxattr(path string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + use(unsafe.Pointer(_p0)) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mkdirat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Nanosleep(time *Timespec, leftover *Timespec) (err error) { + _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func PivotRoot(newroot string, putold string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(newroot) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(putold) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) { + _, _, e1 := Syscall6(SYS_PRCTL, uintptr(option), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func read(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Removexattr(path string, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(oldpath) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(newpath) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setdomainname(p []byte) (err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sethostname(p []byte) (err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpgid(pid int, pgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setsid() (pid int, err error) { + r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0) + pid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Settimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setns(fd int, nstype int) (err error) { + _, _, e1 := Syscall(SYS_SETNS, uintptr(fd), uintptr(nstype), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setpriority(which int, who int, prio int) (err error) { + _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setxattr(path string, attr string, data []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(data) > 0 { + _p2 = unsafe.Pointer(&data[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sync() { + Syscall(SYS_SYNC, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Sysinfo(info *Sysinfo_t) (err error) { + _, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { + r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0) + n = int64(int64(r1)<<32 | int64(r0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) { + _, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Times(tms *Tms) (ticks uintptr, err error) { + r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0) + ticks = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Umask(mask int) (oldmask int) { + r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + oldmask = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Uname(buf *Utsname) (err error) { + _, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unmount(target string, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(target) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Unshare(flags int) (err error) { + _, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func write(fd int, p []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func exitThread(code int) (err error) { + _, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func readlen(fd int, p *byte, np int) (n int, err error) { + r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func writelen(fd int, p *byte, np int) (n int, err error) { + r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func munmap(addr uintptr, length uintptr) (err error) { + _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Madvise(b []byte, advice int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mprotect(b []byte, prot int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlockall() (err error) { + _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Dup2(oldfd int, newfd int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fchown(fd int, uid int, gid int) (err error) { + _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ftruncate(fd int, length int64) (err error) { + _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getegid() (egid int) { + r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + egid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Geteuid() (euid int) { + r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + euid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getgid() (gid int) { + r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Getuid() (uid int) { + r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lchown(path string, uid int, gid int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Listen(s int, n int) (err error) { + _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pread(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pwrite(fd int, p []byte, offset int64) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) { + r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { + r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) + written = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setfsgid(gid int) (err error) { + _, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setfsuid(uid int) (err error) { + _, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setregid(rgid int, egid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresgid(rgid int, egid int, sgid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setresuid(ruid int, euid int, suid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Setreuid(ruid int, euid int) (err error) { + _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Shutdown(fd int, how int) (err error) { + _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) { + r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)) + n = int64(int64(r1)<<32 | int64(r0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func SyncFileRange(fd int, off int64, n int64, flags int) (err error) { + _, _, e1 := Syscall9(SYS_SYNC_FILE_RANGE, uintptr(fd), 0, uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Truncate(path string, length int64) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { + r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) { + _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getgroups(n int, list *_Gid_t) (nn int, err error) { + r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + nn = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setgroups(n int, list *_Gid_t) (err error) { + _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) { + _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { + _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socket(domain int, typ int, proto int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) { + _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) { + _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) { + var _p0 unsafe.Pointer + if len(p) > 0 { + _p0 = unsafe.Pointer(&p[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) { + r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func InotifyInit() (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Ioperm(from int, num int, on int) (err error) { + _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Iopl(level int) (err error) { + _, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Gettimeofday(tv *Timeval) (err error) { + _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Time(t *Time_t) (tt Time_t, err error) { + r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0) + tt = Time_t(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lstat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Fstat(fd int, stat *Stat_t) (err error) { + _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Stat(path string, stat *Stat_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + use(unsafe.Pointer(_p0)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Pause() (err error) { + _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func pipe2(p *[2]_C_int, flags int) (err error) { + _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) { + r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset)) + xaddr = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getrlimit(resource int, rlim *rlimit32) (err error) { + _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setrlimit(resource int, rlim *rlimit32) (err error) { + _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { + r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go index 25f39db9df..f5d488b4a5 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go index 70702b5166..5183711ec8 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go index 94b93d3d02..4c7ed08cc4 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go index 774b10ed8f..beb83e4fdc 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go @@ -572,6 +572,17 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getsid(pid int) (sid int, err error) { + r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0) + sid = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettid() (tid int) { r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) tid = int(r0) @@ -762,8 +773,8 @@ func PivotRoot(newroot string, putold string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) { - _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0) +func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { + _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go new file mode 100644 index 0000000000..0786867e98 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -0,0 +1,359 @@ +// mksysnum_linux.pl /usr/include/mips-linux-gnu/asm/unistd.h +// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT + +// +build mips,linux + +package unix + +const ( + SYS_SYSCALL = 4000 + SYS_EXIT = 4001 + SYS_FORK = 4002 + SYS_READ = 4003 + SYS_WRITE = 4004 + SYS_OPEN = 4005 + SYS_CLOSE = 4006 + SYS_WAITPID = 4007 + SYS_CREAT = 4008 + SYS_LINK = 4009 + SYS_UNLINK = 4010 + SYS_EXECVE = 4011 + SYS_CHDIR = 4012 + SYS_TIME = 4013 + SYS_MKNOD = 4014 + SYS_CHMOD = 4015 + SYS_LCHOWN = 4016 + SYS_BREAK = 4017 + SYS_UNUSED18 = 4018 + SYS_LSEEK = 4019 + SYS_GETPID = 4020 + SYS_MOUNT = 4021 + SYS_UMOUNT = 4022 + SYS_SETUID = 4023 + SYS_GETUID = 4024 + SYS_STIME = 4025 + SYS_PTRACE = 4026 + SYS_ALARM = 4027 + SYS_UNUSED28 = 4028 + SYS_PAUSE = 4029 + SYS_UTIME = 4030 + SYS_STTY = 4031 + SYS_GTTY = 4032 + SYS_ACCESS = 4033 + SYS_NICE = 4034 + SYS_FTIME = 4035 + SYS_SYNC = 4036 + SYS_KILL = 4037 + SYS_RENAME = 4038 + SYS_MKDIR = 4039 + SYS_RMDIR = 4040 + SYS_DUP = 4041 + SYS_PIPE = 4042 + SYS_TIMES = 4043 + SYS_PROF = 4044 + SYS_BRK = 4045 + SYS_SETGID = 4046 + SYS_GETGID = 4047 + SYS_SIGNAL = 4048 + SYS_GETEUID = 4049 + SYS_GETEGID = 4050 + SYS_ACCT = 4051 + SYS_UMOUNT2 = 4052 + SYS_LOCK = 4053 + SYS_IOCTL = 4054 + SYS_FCNTL = 4055 + SYS_MPX = 4056 + SYS_SETPGID = 4057 + SYS_ULIMIT = 4058 + SYS_UNUSED59 = 4059 + SYS_UMASK = 4060 + SYS_CHROOT = 4061 + SYS_USTAT = 4062 + SYS_DUP2 = 4063 + SYS_GETPPID = 4064 + SYS_GETPGRP = 4065 + SYS_SETSID = 4066 + SYS_SIGACTION = 4067 + SYS_SGETMASK = 4068 + SYS_SSETMASK = 4069 + SYS_SETREUID = 4070 + SYS_SETREGID = 4071 + SYS_SIGSUSPEND = 4072 + SYS_SIGPENDING = 4073 + SYS_SETHOSTNAME = 4074 + SYS_SETRLIMIT = 4075 + SYS_GETRLIMIT = 4076 + SYS_GETRUSAGE = 4077 + SYS_GETTIMEOFDAY = 4078 + SYS_SETTIMEOFDAY = 4079 + SYS_GETGROUPS = 4080 + SYS_SETGROUPS = 4081 + SYS_RESERVED82 = 4082 + SYS_SYMLINK = 4083 + SYS_UNUSED84 = 4084 + SYS_READLINK = 4085 + SYS_USELIB = 4086 + SYS_SWAPON = 4087 + SYS_REBOOT = 4088 + SYS_READDIR = 4089 + SYS_MMAP = 4090 + SYS_MUNMAP = 4091 + SYS_TRUNCATE = 4092 + SYS_FTRUNCATE = 4093 + SYS_FCHMOD = 4094 + SYS_FCHOWN = 4095 + SYS_GETPRIORITY = 4096 + SYS_SETPRIORITY = 4097 + SYS_PROFIL = 4098 + SYS_STATFS = 4099 + SYS_FSTATFS = 4100 + SYS_IOPERM = 4101 + SYS_SOCKETCALL = 4102 + SYS_SYSLOG = 4103 + SYS_SETITIMER = 4104 + SYS_GETITIMER = 4105 + SYS_STAT = 4106 + SYS_LSTAT = 4107 + SYS_FSTAT = 4108 + SYS_UNUSED109 = 4109 + SYS_IOPL = 4110 + SYS_VHANGUP = 4111 + SYS_IDLE = 4112 + SYS_VM86 = 4113 + SYS_WAIT4 = 4114 + SYS_SWAPOFF = 4115 + SYS_SYSINFO = 4116 + SYS_IPC = 4117 + SYS_FSYNC = 4118 + SYS_SIGRETURN = 4119 + SYS_CLONE = 4120 + SYS_SETDOMAINNAME = 4121 + SYS_UNAME = 4122 + SYS_MODIFY_LDT = 4123 + SYS_ADJTIMEX = 4124 + SYS_MPROTECT = 4125 + SYS_SIGPROCMASK = 4126 + SYS_CREATE_MODULE = 4127 + SYS_INIT_MODULE = 4128 + SYS_DELETE_MODULE = 4129 + SYS_GET_KERNEL_SYMS = 4130 + SYS_QUOTACTL = 4131 + SYS_GETPGID = 4132 + SYS_FCHDIR = 4133 + SYS_BDFLUSH = 4134 + SYS_SYSFS = 4135 + SYS_PERSONALITY = 4136 + SYS_AFS_SYSCALL = 4137 + SYS_SETFSUID = 4138 + SYS_SETFSGID = 4139 + SYS__LLSEEK = 4140 + SYS_GETDENTS = 4141 + SYS__NEWSELECT = 4142 + SYS_FLOCK = 4143 + SYS_MSYNC = 4144 + SYS_READV = 4145 + SYS_WRITEV = 4146 + SYS_CACHEFLUSH = 4147 + SYS_CACHECTL = 4148 + SYS_SYSMIPS = 4149 + SYS_UNUSED150 = 4150 + SYS_GETSID = 4151 + SYS_FDATASYNC = 4152 + SYS__SYSCTL = 4153 + SYS_MLOCK = 4154 + SYS_MUNLOCK = 4155 + SYS_MLOCKALL = 4156 + SYS_MUNLOCKALL = 4157 + SYS_SCHED_SETPARAM = 4158 + SYS_SCHED_GETPARAM = 4159 + SYS_SCHED_SETSCHEDULER = 4160 + SYS_SCHED_GETSCHEDULER = 4161 + SYS_SCHED_YIELD = 4162 + SYS_SCHED_GET_PRIORITY_MAX = 4163 + SYS_SCHED_GET_PRIORITY_MIN = 4164 + SYS_SCHED_RR_GET_INTERVAL = 4165 + SYS_NANOSLEEP = 4166 + SYS_MREMAP = 4167 + SYS_ACCEPT = 4168 + SYS_BIND = 4169 + SYS_CONNECT = 4170 + SYS_GETPEERNAME = 4171 + SYS_GETSOCKNAME = 4172 + SYS_GETSOCKOPT = 4173 + SYS_LISTEN = 4174 + SYS_RECV = 4175 + SYS_RECVFROM = 4176 + SYS_RECVMSG = 4177 + SYS_SEND = 4178 + SYS_SENDMSG = 4179 + SYS_SENDTO = 4180 + SYS_SETSOCKOPT = 4181 + SYS_SHUTDOWN = 4182 + SYS_SOCKET = 4183 + SYS_SOCKETPAIR = 4184 + SYS_SETRESUID = 4185 + SYS_GETRESUID = 4186 + SYS_QUERY_MODULE = 4187 + SYS_POLL = 4188 + SYS_NFSSERVCTL = 4189 + SYS_SETRESGID = 4190 + SYS_GETRESGID = 4191 + SYS_PRCTL = 4192 + SYS_RT_SIGRETURN = 4193 + SYS_RT_SIGACTION = 4194 + SYS_RT_SIGPROCMASK = 4195 + SYS_RT_SIGPENDING = 4196 + SYS_RT_SIGTIMEDWAIT = 4197 + SYS_RT_SIGQUEUEINFO = 4198 + SYS_RT_SIGSUSPEND = 4199 + SYS_PREAD64 = 4200 + SYS_PWRITE64 = 4201 + SYS_CHOWN = 4202 + SYS_GETCWD = 4203 + SYS_CAPGET = 4204 + SYS_CAPSET = 4205 + SYS_SIGALTSTACK = 4206 + SYS_SENDFILE = 4207 + SYS_GETPMSG = 4208 + SYS_PUTPMSG = 4209 + SYS_MMAP2 = 4210 + SYS_TRUNCATE64 = 4211 + SYS_FTRUNCATE64 = 4212 + SYS_STAT64 = 4213 + SYS_LSTAT64 = 4214 + SYS_FSTAT64 = 4215 + SYS_PIVOT_ROOT = 4216 + SYS_MINCORE = 4217 + SYS_MADVISE = 4218 + SYS_GETDENTS64 = 4219 + SYS_FCNTL64 = 4220 + SYS_RESERVED221 = 4221 + SYS_GETTID = 4222 + SYS_READAHEAD = 4223 + SYS_SETXATTR = 4224 + SYS_LSETXATTR = 4225 + SYS_FSETXATTR = 4226 + SYS_GETXATTR = 4227 + SYS_LGETXATTR = 4228 + SYS_FGETXATTR = 4229 + SYS_LISTXATTR = 4230 + SYS_LLISTXATTR = 4231 + SYS_FLISTXATTR = 4232 + SYS_REMOVEXATTR = 4233 + SYS_LREMOVEXATTR = 4234 + SYS_FREMOVEXATTR = 4235 + SYS_TKILL = 4236 + SYS_SENDFILE64 = 4237 + SYS_FUTEX = 4238 + SYS_SCHED_SETAFFINITY = 4239 + SYS_SCHED_GETAFFINITY = 4240 + SYS_IO_SETUP = 4241 + SYS_IO_DESTROY = 4242 + SYS_IO_GETEVENTS = 4243 + SYS_IO_SUBMIT = 4244 + SYS_IO_CANCEL = 4245 + SYS_EXIT_GROUP = 4246 + SYS_LOOKUP_DCOOKIE = 4247 + SYS_EPOLL_CREATE = 4248 + SYS_EPOLL_CTL = 4249 + SYS_EPOLL_WAIT = 4250 + SYS_REMAP_FILE_PAGES = 4251 + SYS_SET_TID_ADDRESS = 4252 + SYS_RESTART_SYSCALL = 4253 + SYS_FADVISE64 = 4254 + SYS_STATFS64 = 4255 + SYS_FSTATFS64 = 4256 + SYS_TIMER_CREATE = 4257 + SYS_TIMER_SETTIME = 4258 + SYS_TIMER_GETTIME = 4259 + SYS_TIMER_GETOVERRUN = 4260 + SYS_TIMER_DELETE = 4261 + SYS_CLOCK_SETTIME = 4262 + SYS_CLOCK_GETTIME = 4263 + SYS_CLOCK_GETRES = 4264 + SYS_CLOCK_NANOSLEEP = 4265 + SYS_TGKILL = 4266 + SYS_UTIMES = 4267 + SYS_MBIND = 4268 + SYS_GET_MEMPOLICY = 4269 + SYS_SET_MEMPOLICY = 4270 + SYS_MQ_OPEN = 4271 + SYS_MQ_UNLINK = 4272 + SYS_MQ_TIMEDSEND = 4273 + SYS_MQ_TIMEDRECEIVE = 4274 + SYS_MQ_NOTIFY = 4275 + SYS_MQ_GETSETATTR = 4276 + SYS_VSERVER = 4277 + SYS_WAITID = 4278 + SYS_ADD_KEY = 4280 + SYS_REQUEST_KEY = 4281 + SYS_KEYCTL = 4282 + SYS_SET_THREAD_AREA = 4283 + SYS_INOTIFY_INIT = 4284 + SYS_INOTIFY_ADD_WATCH = 4285 + SYS_INOTIFY_RM_WATCH = 4286 + SYS_MIGRATE_PAGES = 4287 + SYS_OPENAT = 4288 + SYS_MKDIRAT = 4289 + SYS_MKNODAT = 4290 + SYS_FCHOWNAT = 4291 + SYS_FUTIMESAT = 4292 + SYS_FSTATAT64 = 4293 + SYS_UNLINKAT = 4294 + SYS_RENAMEAT = 4295 + SYS_LINKAT = 4296 + SYS_SYMLINKAT = 4297 + SYS_READLINKAT = 4298 + SYS_FCHMODAT = 4299 + SYS_FACCESSAT = 4300 + SYS_PSELECT6 = 4301 + SYS_PPOLL = 4302 + SYS_UNSHARE = 4303 + SYS_SPLICE = 4304 + SYS_SYNC_FILE_RANGE = 4305 + SYS_TEE = 4306 + SYS_VMSPLICE = 4307 + SYS_MOVE_PAGES = 4308 + SYS_SET_ROBUST_LIST = 4309 + SYS_GET_ROBUST_LIST = 4310 + SYS_KEXEC_LOAD = 4311 + SYS_GETCPU = 4312 + SYS_EPOLL_PWAIT = 4313 + SYS_IOPRIO_SET = 4314 + SYS_IOPRIO_GET = 4315 + SYS_UTIMENSAT = 4316 + SYS_SIGNALFD = 4317 + SYS_TIMERFD = 4318 + SYS_EVENTFD = 4319 + SYS_FALLOCATE = 4320 + SYS_TIMERFD_CREATE = 4321 + SYS_TIMERFD_GETTIME = 4322 + SYS_TIMERFD_SETTIME = 4323 + SYS_SIGNALFD4 = 4324 + SYS_EVENTFD2 = 4325 + SYS_EPOLL_CREATE1 = 4326 + SYS_DUP3 = 4327 + SYS_PIPE2 = 4328 + SYS_INOTIFY_INIT1 = 4329 + SYS_PREADV = 4330 + SYS_PWRITEV = 4331 + SYS_RT_TGSIGQUEUEINFO = 4332 + SYS_PERF_EVENT_OPEN = 4333 + SYS_ACCEPT4 = 4334 + SYS_RECVMMSG = 4335 + SYS_FANOTIFY_INIT = 4336 + SYS_FANOTIFY_MARK = 4337 + SYS_PRLIMIT64 = 4338 + SYS_NAME_TO_HANDLE_AT = 4339 + SYS_OPEN_BY_HANDLE_AT = 4340 + SYS_CLOCK_ADJTIME = 4341 + SYS_SYNCFS = 4342 + SYS_SENDMMSG = 4343 + SYS_SETNS = 4344 + SYS_PROCESS_VM_READV = 4345 + SYS_PROCESS_VM_WRITEV = 4346 + SYS_LINUX_SYSCALLS = 4346 + SYS_O32_LINUX_SYSCALLS = 4346 + SYS_64_LINUX_SYSCALLS = 4305 + SYS_N32_LINUX_SYSCALLS = 4310 +) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go new file mode 100644 index 0000000000..25d231708f --- /dev/null +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -0,0 +1,359 @@ +// mksysnum_linux.pl /usr/include/mips-linux-gnu/asm/unistd.h +// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT + +// +build mipsle,linux + +package unix + +const ( + SYS_SYSCALL = 4000 + SYS_EXIT = 4001 + SYS_FORK = 4002 + SYS_READ = 4003 + SYS_WRITE = 4004 + SYS_OPEN = 4005 + SYS_CLOSE = 4006 + SYS_WAITPID = 4007 + SYS_CREAT = 4008 + SYS_LINK = 4009 + SYS_UNLINK = 4010 + SYS_EXECVE = 4011 + SYS_CHDIR = 4012 + SYS_TIME = 4013 + SYS_MKNOD = 4014 + SYS_CHMOD = 4015 + SYS_LCHOWN = 4016 + SYS_BREAK = 4017 + SYS_UNUSED18 = 4018 + SYS_LSEEK = 4019 + SYS_GETPID = 4020 + SYS_MOUNT = 4021 + SYS_UMOUNT = 4022 + SYS_SETUID = 4023 + SYS_GETUID = 4024 + SYS_STIME = 4025 + SYS_PTRACE = 4026 + SYS_ALARM = 4027 + SYS_UNUSED28 = 4028 + SYS_PAUSE = 4029 + SYS_UTIME = 4030 + SYS_STTY = 4031 + SYS_GTTY = 4032 + SYS_ACCESS = 4033 + SYS_NICE = 4034 + SYS_FTIME = 4035 + SYS_SYNC = 4036 + SYS_KILL = 4037 + SYS_RENAME = 4038 + SYS_MKDIR = 4039 + SYS_RMDIR = 4040 + SYS_DUP = 4041 + SYS_PIPE = 4042 + SYS_TIMES = 4043 + SYS_PROF = 4044 + SYS_BRK = 4045 + SYS_SETGID = 4046 + SYS_GETGID = 4047 + SYS_SIGNAL = 4048 + SYS_GETEUID = 4049 + SYS_GETEGID = 4050 + SYS_ACCT = 4051 + SYS_UMOUNT2 = 4052 + SYS_LOCK = 4053 + SYS_IOCTL = 4054 + SYS_FCNTL = 4055 + SYS_MPX = 4056 + SYS_SETPGID = 4057 + SYS_ULIMIT = 4058 + SYS_UNUSED59 = 4059 + SYS_UMASK = 4060 + SYS_CHROOT = 4061 + SYS_USTAT = 4062 + SYS_DUP2 = 4063 + SYS_GETPPID = 4064 + SYS_GETPGRP = 4065 + SYS_SETSID = 4066 + SYS_SIGACTION = 4067 + SYS_SGETMASK = 4068 + SYS_SSETMASK = 4069 + SYS_SETREUID = 4070 + SYS_SETREGID = 4071 + SYS_SIGSUSPEND = 4072 + SYS_SIGPENDING = 4073 + SYS_SETHOSTNAME = 4074 + SYS_SETRLIMIT = 4075 + SYS_GETRLIMIT = 4076 + SYS_GETRUSAGE = 4077 + SYS_GETTIMEOFDAY = 4078 + SYS_SETTIMEOFDAY = 4079 + SYS_GETGROUPS = 4080 + SYS_SETGROUPS = 4081 + SYS_RESERVED82 = 4082 + SYS_SYMLINK = 4083 + SYS_UNUSED84 = 4084 + SYS_READLINK = 4085 + SYS_USELIB = 4086 + SYS_SWAPON = 4087 + SYS_REBOOT = 4088 + SYS_READDIR = 4089 + SYS_MMAP = 4090 + SYS_MUNMAP = 4091 + SYS_TRUNCATE = 4092 + SYS_FTRUNCATE = 4093 + SYS_FCHMOD = 4094 + SYS_FCHOWN = 4095 + SYS_GETPRIORITY = 4096 + SYS_SETPRIORITY = 4097 + SYS_PROFIL = 4098 + SYS_STATFS = 4099 + SYS_FSTATFS = 4100 + SYS_IOPERM = 4101 + SYS_SOCKETCALL = 4102 + SYS_SYSLOG = 4103 + SYS_SETITIMER = 4104 + SYS_GETITIMER = 4105 + SYS_STAT = 4106 + SYS_LSTAT = 4107 + SYS_FSTAT = 4108 + SYS_UNUSED109 = 4109 + SYS_IOPL = 4110 + SYS_VHANGUP = 4111 + SYS_IDLE = 4112 + SYS_VM86 = 4113 + SYS_WAIT4 = 4114 + SYS_SWAPOFF = 4115 + SYS_SYSINFO = 4116 + SYS_IPC = 4117 + SYS_FSYNC = 4118 + SYS_SIGRETURN = 4119 + SYS_CLONE = 4120 + SYS_SETDOMAINNAME = 4121 + SYS_UNAME = 4122 + SYS_MODIFY_LDT = 4123 + SYS_ADJTIMEX = 4124 + SYS_MPROTECT = 4125 + SYS_SIGPROCMASK = 4126 + SYS_CREATE_MODULE = 4127 + SYS_INIT_MODULE = 4128 + SYS_DELETE_MODULE = 4129 + SYS_GET_KERNEL_SYMS = 4130 + SYS_QUOTACTL = 4131 + SYS_GETPGID = 4132 + SYS_FCHDIR = 4133 + SYS_BDFLUSH = 4134 + SYS_SYSFS = 4135 + SYS_PERSONALITY = 4136 + SYS_AFS_SYSCALL = 4137 + SYS_SETFSUID = 4138 + SYS_SETFSGID = 4139 + SYS__LLSEEK = 4140 + SYS_GETDENTS = 4141 + SYS__NEWSELECT = 4142 + SYS_FLOCK = 4143 + SYS_MSYNC = 4144 + SYS_READV = 4145 + SYS_WRITEV = 4146 + SYS_CACHEFLUSH = 4147 + SYS_CACHECTL = 4148 + SYS_SYSMIPS = 4149 + SYS_UNUSED150 = 4150 + SYS_GETSID = 4151 + SYS_FDATASYNC = 4152 + SYS__SYSCTL = 4153 + SYS_MLOCK = 4154 + SYS_MUNLOCK = 4155 + SYS_MLOCKALL = 4156 + SYS_MUNLOCKALL = 4157 + SYS_SCHED_SETPARAM = 4158 + SYS_SCHED_GETPARAM = 4159 + SYS_SCHED_SETSCHEDULER = 4160 + SYS_SCHED_GETSCHEDULER = 4161 + SYS_SCHED_YIELD = 4162 + SYS_SCHED_GET_PRIORITY_MAX = 4163 + SYS_SCHED_GET_PRIORITY_MIN = 4164 + SYS_SCHED_RR_GET_INTERVAL = 4165 + SYS_NANOSLEEP = 4166 + SYS_MREMAP = 4167 + SYS_ACCEPT = 4168 + SYS_BIND = 4169 + SYS_CONNECT = 4170 + SYS_GETPEERNAME = 4171 + SYS_GETSOCKNAME = 4172 + SYS_GETSOCKOPT = 4173 + SYS_LISTEN = 4174 + SYS_RECV = 4175 + SYS_RECVFROM = 4176 + SYS_RECVMSG = 4177 + SYS_SEND = 4178 + SYS_SENDMSG = 4179 + SYS_SENDTO = 4180 + SYS_SETSOCKOPT = 4181 + SYS_SHUTDOWN = 4182 + SYS_SOCKET = 4183 + SYS_SOCKETPAIR = 4184 + SYS_SETRESUID = 4185 + SYS_GETRESUID = 4186 + SYS_QUERY_MODULE = 4187 + SYS_POLL = 4188 + SYS_NFSSERVCTL = 4189 + SYS_SETRESGID = 4190 + SYS_GETRESGID = 4191 + SYS_PRCTL = 4192 + SYS_RT_SIGRETURN = 4193 + SYS_RT_SIGACTION = 4194 + SYS_RT_SIGPROCMASK = 4195 + SYS_RT_SIGPENDING = 4196 + SYS_RT_SIGTIMEDWAIT = 4197 + SYS_RT_SIGQUEUEINFO = 4198 + SYS_RT_SIGSUSPEND = 4199 + SYS_PREAD64 = 4200 + SYS_PWRITE64 = 4201 + SYS_CHOWN = 4202 + SYS_GETCWD = 4203 + SYS_CAPGET = 4204 + SYS_CAPSET = 4205 + SYS_SIGALTSTACK = 4206 + SYS_SENDFILE = 4207 + SYS_GETPMSG = 4208 + SYS_PUTPMSG = 4209 + SYS_MMAP2 = 4210 + SYS_TRUNCATE64 = 4211 + SYS_FTRUNCATE64 = 4212 + SYS_STAT64 = 4213 + SYS_LSTAT64 = 4214 + SYS_FSTAT64 = 4215 + SYS_PIVOT_ROOT = 4216 + SYS_MINCORE = 4217 + SYS_MADVISE = 4218 + SYS_GETDENTS64 = 4219 + SYS_FCNTL64 = 4220 + SYS_RESERVED221 = 4221 + SYS_GETTID = 4222 + SYS_READAHEAD = 4223 + SYS_SETXATTR = 4224 + SYS_LSETXATTR = 4225 + SYS_FSETXATTR = 4226 + SYS_GETXATTR = 4227 + SYS_LGETXATTR = 4228 + SYS_FGETXATTR = 4229 + SYS_LISTXATTR = 4230 + SYS_LLISTXATTR = 4231 + SYS_FLISTXATTR = 4232 + SYS_REMOVEXATTR = 4233 + SYS_LREMOVEXATTR = 4234 + SYS_FREMOVEXATTR = 4235 + SYS_TKILL = 4236 + SYS_SENDFILE64 = 4237 + SYS_FUTEX = 4238 + SYS_SCHED_SETAFFINITY = 4239 + SYS_SCHED_GETAFFINITY = 4240 + SYS_IO_SETUP = 4241 + SYS_IO_DESTROY = 4242 + SYS_IO_GETEVENTS = 4243 + SYS_IO_SUBMIT = 4244 + SYS_IO_CANCEL = 4245 + SYS_EXIT_GROUP = 4246 + SYS_LOOKUP_DCOOKIE = 4247 + SYS_EPOLL_CREATE = 4248 + SYS_EPOLL_CTL = 4249 + SYS_EPOLL_WAIT = 4250 + SYS_REMAP_FILE_PAGES = 4251 + SYS_SET_TID_ADDRESS = 4252 + SYS_RESTART_SYSCALL = 4253 + SYS_FADVISE64 = 4254 + SYS_STATFS64 = 4255 + SYS_FSTATFS64 = 4256 + SYS_TIMER_CREATE = 4257 + SYS_TIMER_SETTIME = 4258 + SYS_TIMER_GETTIME = 4259 + SYS_TIMER_GETOVERRUN = 4260 + SYS_TIMER_DELETE = 4261 + SYS_CLOCK_SETTIME = 4262 + SYS_CLOCK_GETTIME = 4263 + SYS_CLOCK_GETRES = 4264 + SYS_CLOCK_NANOSLEEP = 4265 + SYS_TGKILL = 4266 + SYS_UTIMES = 4267 + SYS_MBIND = 4268 + SYS_GET_MEMPOLICY = 4269 + SYS_SET_MEMPOLICY = 4270 + SYS_MQ_OPEN = 4271 + SYS_MQ_UNLINK = 4272 + SYS_MQ_TIMEDSEND = 4273 + SYS_MQ_TIMEDRECEIVE = 4274 + SYS_MQ_NOTIFY = 4275 + SYS_MQ_GETSETATTR = 4276 + SYS_VSERVER = 4277 + SYS_WAITID = 4278 + SYS_ADD_KEY = 4280 + SYS_REQUEST_KEY = 4281 + SYS_KEYCTL = 4282 + SYS_SET_THREAD_AREA = 4283 + SYS_INOTIFY_INIT = 4284 + SYS_INOTIFY_ADD_WATCH = 4285 + SYS_INOTIFY_RM_WATCH = 4286 + SYS_MIGRATE_PAGES = 4287 + SYS_OPENAT = 4288 + SYS_MKDIRAT = 4289 + SYS_MKNODAT = 4290 + SYS_FCHOWNAT = 4291 + SYS_FUTIMESAT = 4292 + SYS_FSTATAT64 = 4293 + SYS_UNLINKAT = 4294 + SYS_RENAMEAT = 4295 + SYS_LINKAT = 4296 + SYS_SYMLINKAT = 4297 + SYS_READLINKAT = 4298 + SYS_FCHMODAT = 4299 + SYS_FACCESSAT = 4300 + SYS_PSELECT6 = 4301 + SYS_PPOLL = 4302 + SYS_UNSHARE = 4303 + SYS_SPLICE = 4304 + SYS_SYNC_FILE_RANGE = 4305 + SYS_TEE = 4306 + SYS_VMSPLICE = 4307 + SYS_MOVE_PAGES = 4308 + SYS_SET_ROBUST_LIST = 4309 + SYS_GET_ROBUST_LIST = 4310 + SYS_KEXEC_LOAD = 4311 + SYS_GETCPU = 4312 + SYS_EPOLL_PWAIT = 4313 + SYS_IOPRIO_SET = 4314 + SYS_IOPRIO_GET = 4315 + SYS_UTIMENSAT = 4316 + SYS_SIGNALFD = 4317 + SYS_TIMERFD = 4318 + SYS_EVENTFD = 4319 + SYS_FALLOCATE = 4320 + SYS_TIMERFD_CREATE = 4321 + SYS_TIMERFD_GETTIME = 4322 + SYS_TIMERFD_SETTIME = 4323 + SYS_SIGNALFD4 = 4324 + SYS_EVENTFD2 = 4325 + SYS_EPOLL_CREATE1 = 4326 + SYS_DUP3 = 4327 + SYS_PIPE2 = 4328 + SYS_INOTIFY_INIT1 = 4329 + SYS_PREADV = 4330 + SYS_PWRITEV = 4331 + SYS_RT_TGSIGQUEUEINFO = 4332 + SYS_PERF_EVENT_OPEN = 4333 + SYS_ACCEPT4 = 4334 + SYS_RECVMMSG = 4335 + SYS_FANOTIFY_INIT = 4336 + SYS_FANOTIFY_MARK = 4337 + SYS_PRLIMIT64 = 4338 + SYS_NAME_TO_HANDLE_AT = 4339 + SYS_OPEN_BY_HANDLE_AT = 4340 + SYS_CLOCK_ADJTIME = 4341 + SYS_SYNCFS = 4342 + SYS_SENDMMSG = 4343 + SYS_SETNS = 4344 + SYS_PROCESS_VM_READV = 4345 + SYS_PROCESS_VM_WRITEV = 4346 + SYS_LINUX_SYSCALLS = 4346 + SYS_O32_LINUX_SYSCALLS = 4346 + SYS_64_LINUX_SYSCALLS = 4305 + SYS_N32_LINUX_SYSCALLS = 4310 +) diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index f3ddf5345b..a3631053c7 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -203,6 +203,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -326,6 +333,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index a923bef353..0573e6cd24 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -205,6 +205,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -330,6 +337,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index 35f11bd1bc..0578b53964 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -207,6 +207,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -330,6 +337,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index e786addf78..808e04669a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -206,6 +206,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -331,6 +338,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go new file mode 100644 index 0000000000..2eaff573d0 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -0,0 +1,642 @@ +// +build mips,linux +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_linux.go | go run mkpost.go + +package unix + +const ( + sizeofPtr = 0x4 + sizeofShort = 0x2 + sizeofInt = 0x4 + sizeofLong = 0x4 + sizeofLongLong = 0x8 + PathMax = 0x1000 +) + +type ( + _C_short int16 + _C_int int32 + _C_long int32 + _C_long_long int64 +) + +type Timespec struct { + Sec int32 + Nsec int32 +} + +type Timeval struct { + Sec int32 + Usec int32 +} + +type Timex struct { + Modes uint32 + Offset int32 + Freq int32 + Maxerror int32 + Esterror int32 + Status int32 + Constant int32 + Precision int32 + Tolerance int32 + Time Timeval + Tick int32 + Ppsfreq int32 + Jitter int32 + Shift int32 + Stabil int32 + Jitcnt int32 + Calcnt int32 + Errcnt int32 + Stbcnt int32 + Tai int32 + Pad_cgo_0 [44]byte +} + +type Time_t int32 + +type Tms struct { + Utime int32 + Stime int32 + Cutime int32 + Cstime int32 +} + +type Utimbuf struct { + Actime int32 + Modtime int32 +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int32 + Ixrss int32 + Idrss int32 + Isrss int32 + Minflt int32 + Majflt int32 + Nswap int32 + Inblock int32 + Oublock int32 + Msgsnd int32 + Msgrcv int32 + Nsignals int32 + Nvcsw int32 + Nivcsw int32 +} + +type Rlimit struct { + Cur uint64 + Max uint64 +} + +type _Gid_t uint32 + +type Stat_t struct { + Dev uint32 + Pad1 [3]int32 + Ino uint64 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint32 + Pad2 [3]int32 + Size int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Blksize int32 + Pad4 int32 + Blocks int64 + Pad5 [14]int32 +} + +type Statfs_t struct { + Type int32 + Bsize int32 + Frsize int32 + Pad_cgo_0 [4]byte + Blocks uint64 + Bfree uint64 + Files uint64 + Ffree uint64 + Bavail uint64 + Fsid Fsid + Namelen int32 + Flags int32 + Spare [5]int32 + Pad_cgo_1 [4]byte +} + +type Dirent struct { + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + Pad_cgo_0 [5]byte +} + +type Fsid struct { + X__val [2]int32 +} + +type Flock_t struct { + Type int16 + Whence int16 + Pad_cgo_0 [4]byte + Start int64 + Len int64 + Pid int32 + Pad_cgo_1 [4]byte +} + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + +type RawSockaddrInet4 struct { + Family uint16 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Family uint16 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddrUnix struct { + Family uint16 + Path [108]int8 +} + +type RawSockaddrLinklayer struct { + Family uint16 + Protocol uint16 + Ifindex int32 + Hatype uint16 + Pkttype uint8 + Halen uint8 + Addr [8]uint8 +} + +type RawSockaddrNetlink struct { + Family uint16 + Pad uint16 + Pid uint32 + Groups uint32 +} + +type RawSockaddrHCI struct { + Family uint16 + Dev uint16 + Channel uint16 +} + +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + +type RawSockaddr struct { + Family uint16 + Data [14]int8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [96]int8 +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32 + Linger int32 +} + +type Iovec struct { + Base *byte + Len uint32 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + Iov *Iovec + Iovlen uint32 + Control *byte + Controllen uint32 + Flags int32 +} + +type Cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +type Inet4Pktinfo struct { + Ifindex int32 + Spec_dst [4]byte /* in_addr */ + Addr [4]byte /* in_addr */ +} + +type Inet6Pktinfo struct { + Addr [16]byte /* in6_addr */ + Ifindex uint32 +} + +type IPv6MTUInfo struct { + Addr RawSockaddrInet6 + Mtu uint32 +} + +type ICMPv6Filter struct { + Data [8]uint32 +} + +type Ucred struct { + Pid int32 + Uid uint32 + Gid uint32 +} + +type TCPInfo struct { + State uint8 + Ca_state uint8 + Retransmits uint8 + Probes uint8 + Backoff uint8 + Options uint8 + Pad_cgo_0 [2]byte + Rto uint32 + Ato uint32 + Snd_mss uint32 + Rcv_mss uint32 + Unacked uint32 + Sacked uint32 + Lost uint32 + Retrans uint32 + Fackets uint32 + Last_data_sent uint32 + Last_ack_sent uint32 + Last_data_recv uint32 + Last_ack_recv uint32 + Pmtu uint32 + Rcv_ssthresh uint32 + Rtt uint32 + Rttvar uint32 + Snd_ssthresh uint32 + Snd_cwnd uint32 + Advmss uint32 + Reordering uint32 + Rcv_rtt uint32 + Rcv_space uint32 + Total_retrans uint32 +} + +const ( + SizeofSockaddrInet4 = 0x10 + SizeofSockaddrInet6 = 0x1c + SizeofSockaddrAny = 0x70 + SizeofSockaddrUnix = 0x6e + SizeofSockaddrLinklayer = 0x14 + SizeofSockaddrNetlink = 0xc + SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 + SizeofLinger = 0x8 + SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc + SizeofIPv6Mreq = 0x14 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc + SizeofInet4Pktinfo = 0xc + SizeofInet6Pktinfo = 0x14 + SizeofIPv6MTUInfo = 0x20 + SizeofICMPv6Filter = 0x20 + SizeofUcred = 0xc + SizeofTCPInfo = 0x68 +) + +const ( + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_MAX = 0x1d + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 +) + +type NlMsghdr struct { + Len uint32 + Type uint16 + Flags uint16 + Seq uint32 + Pid uint32 +} + +type NlMsgerr struct { + Error int32 + Msg NlMsghdr +} + +type RtGenmsg struct { + Family uint8 +} + +type NlAttr struct { + Len uint16 + Type uint16 +} + +type RtAttr struct { + Len uint16 + Type uint16 +} + +type IfInfomsg struct { + Family uint8 + X__ifi_pad uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 +} + +type IfAddrmsg struct { + Family uint8 + Prefixlen uint8 + Flags uint8 + Scope uint8 + Index uint32 +} + +type RtMsg struct { + Family uint8 + Dst_len uint8 + Src_len uint8 + Tos uint8 + Table uint8 + Protocol uint8 + Scope uint8 + Type uint8 + Flags uint32 +} + +type RtNexthop struct { + Len uint16 + Flags uint8 + Hops uint8 + Ifindex int32 +} + +const ( + SizeofSockFilter = 0x8 + SizeofSockFprog = 0x8 +) + +type SockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} + +type SockFprog struct { + Len uint16 + Pad_cgo_0 [2]byte + Filter *SockFilter +} + +type InotifyEvent struct { + Wd int32 + Mask uint32 + Cookie uint32 + Len uint32 +} + +const SizeofInotifyEvent = 0x10 + +type PtraceRegs struct { + Regs [109]uint32 + U_tsize uint32 + U_dsize uint32 + U_ssize uint32 + Start_code uint32 + Start_data uint32 + Start_stack uint32 + Signal int32 + U_ar0 *byte + Magic uint32 + U_comm [32]int8 +} + +type ptracePsw struct { +} + +type ptraceFpregs struct { +} + +type ptracePer struct { +} + +type FdSet struct { + Bits [32]int32 +} + +type Sysinfo_t struct { + Uptime int32 + Loads [3]uint32 + Totalram uint32 + Freeram uint32 + Sharedram uint32 + Bufferram uint32 + Totalswap uint32 + Freeswap uint32 + Procs uint16 + Pad uint16 + Totalhigh uint32 + Freehigh uint32 + Unit uint32 + X_f [8]int8 +} + +type Utsname struct { + Sysname [65]int8 + Nodename [65]int8 + Release [65]int8 + Version [65]int8 + Machine [65]int8 + Domainname [65]int8 +} + +type Ustat_t struct { + Tfree int32 + Tinode uint32 + Fname [6]int8 + Fpack [6]int8 +} + +type EpollEvent struct { + Events uint32 + PadFd int32 + Fd int32 + Pad int32 +} + +const ( + AT_FDCWD = -0x64 + AT_REMOVEDIR = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_SYMLINK_NOFOLLOW = 0x100 +) + +type PollFd struct { + Fd int32 + Events int16 + Revents int16 +} + +const ( + POLLIN = 0x1 + POLLPRI = 0x2 + POLLOUT = 0x4 + POLLRDHUP = 0x2000 + POLLERR = 0x8 + POLLHUP = 0x10 + POLLNVAL = 0x20 +) + +type Sigset_t struct { + X__val [32]uint32 +} + +const _SC_PAGESIZE = 0x1e + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Line uint8 + Cc [23]uint8 + Ispeed uint32 + Ospeed uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index b29894deba..73e4b76c0c 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -206,6 +206,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -330,6 +337,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index d9af71b696..479ca3e1b8 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -206,6 +206,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -330,6 +337,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go new file mode 100644 index 0000000000..7617a69d02 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -0,0 +1,642 @@ +// +build mipsle,linux +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_linux.go | go run mkpost.go + +package unix + +const ( + sizeofPtr = 0x4 + sizeofShort = 0x2 + sizeofInt = 0x4 + sizeofLong = 0x4 + sizeofLongLong = 0x8 + PathMax = 0x1000 +) + +type ( + _C_short int16 + _C_int int32 + _C_long int32 + _C_long_long int64 +) + +type Timespec struct { + Sec int32 + Nsec int32 +} + +type Timeval struct { + Sec int32 + Usec int32 +} + +type Timex struct { + Modes uint32 + Offset int32 + Freq int32 + Maxerror int32 + Esterror int32 + Status int32 + Constant int32 + Precision int32 + Tolerance int32 + Time Timeval + Tick int32 + Ppsfreq int32 + Jitter int32 + Shift int32 + Stabil int32 + Jitcnt int32 + Calcnt int32 + Errcnt int32 + Stbcnt int32 + Tai int32 + Pad_cgo_0 [44]byte +} + +type Time_t int32 + +type Tms struct { + Utime int32 + Stime int32 + Cutime int32 + Cstime int32 +} + +type Utimbuf struct { + Actime int32 + Modtime int32 +} + +type Rusage struct { + Utime Timeval + Stime Timeval + Maxrss int32 + Ixrss int32 + Idrss int32 + Isrss int32 + Minflt int32 + Majflt int32 + Nswap int32 + Inblock int32 + Oublock int32 + Msgsnd int32 + Msgrcv int32 + Nsignals int32 + Nvcsw int32 + Nivcsw int32 +} + +type Rlimit struct { + Cur uint64 + Max uint64 +} + +type _Gid_t uint32 + +type Stat_t struct { + Dev uint32 + Pad1 [3]int32 + Ino uint64 + Mode uint32 + Nlink uint32 + Uid uint32 + Gid uint32 + Rdev uint32 + Pad2 [3]int32 + Size int64 + Atim Timespec + Mtim Timespec + Ctim Timespec + Blksize int32 + Pad4 int32 + Blocks int64 + Pad5 [14]int32 +} + +type Statfs_t struct { + Type int32 + Bsize int32 + Frsize int32 + Pad_cgo_0 [4]byte + Blocks uint64 + Bfree uint64 + Files uint64 + Ffree uint64 + Bavail uint64 + Fsid Fsid + Namelen int32 + Flags int32 + Spare [5]int32 + Pad_cgo_1 [4]byte +} + +type Dirent struct { + Ino uint64 + Off int64 + Reclen uint16 + Type uint8 + Name [256]int8 + Pad_cgo_0 [5]byte +} + +type Fsid struct { + X__val [2]int32 +} + +type Flock_t struct { + Type int16 + Whence int16 + Pad_cgo_0 [4]byte + Start int64 + Len int64 + Pid int32 + Pad_cgo_1 [4]byte +} + +const ( + FADV_NORMAL = 0x0 + FADV_RANDOM = 0x1 + FADV_SEQUENTIAL = 0x2 + FADV_WILLNEED = 0x3 + FADV_DONTNEED = 0x4 + FADV_NOREUSE = 0x5 +) + +type RawSockaddrInet4 struct { + Family uint16 + Port uint16 + Addr [4]byte /* in_addr */ + Zero [8]uint8 +} + +type RawSockaddrInet6 struct { + Family uint16 + Port uint16 + Flowinfo uint32 + Addr [16]byte /* in6_addr */ + Scope_id uint32 +} + +type RawSockaddrUnix struct { + Family uint16 + Path [108]int8 +} + +type RawSockaddrLinklayer struct { + Family uint16 + Protocol uint16 + Ifindex int32 + Hatype uint16 + Pkttype uint8 + Halen uint8 + Addr [8]uint8 +} + +type RawSockaddrNetlink struct { + Family uint16 + Pad uint16 + Pid uint32 + Groups uint32 +} + +type RawSockaddrHCI struct { + Family uint16 + Dev uint16 + Channel uint16 +} + +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + +type RawSockaddr struct { + Family uint16 + Data [14]int8 +} + +type RawSockaddrAny struct { + Addr RawSockaddr + Pad [96]int8 +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32 + Linger int32 +} + +type Iovec struct { + Base *byte + Len uint32 +} + +type IPMreq struct { + Multiaddr [4]byte /* in_addr */ + Interface [4]byte /* in_addr */ +} + +type IPMreqn struct { + Multiaddr [4]byte /* in_addr */ + Address [4]byte /* in_addr */ + Ifindex int32 +} + +type IPv6Mreq struct { + Multiaddr [16]byte /* in6_addr */ + Interface uint32 +} + +type Msghdr struct { + Name *byte + Namelen uint32 + Iov *Iovec + Iovlen uint32 + Control *byte + Controllen uint32 + Flags int32 +} + +type Cmsghdr struct { + Len uint32 + Level int32 + Type int32 +} + +type Inet4Pktinfo struct { + Ifindex int32 + Spec_dst [4]byte /* in_addr */ + Addr [4]byte /* in_addr */ +} + +type Inet6Pktinfo struct { + Addr [16]byte /* in6_addr */ + Ifindex uint32 +} + +type IPv6MTUInfo struct { + Addr RawSockaddrInet6 + Mtu uint32 +} + +type ICMPv6Filter struct { + Data [8]uint32 +} + +type Ucred struct { + Pid int32 + Uid uint32 + Gid uint32 +} + +type TCPInfo struct { + State uint8 + Ca_state uint8 + Retransmits uint8 + Probes uint8 + Backoff uint8 + Options uint8 + Pad_cgo_0 [2]byte + Rto uint32 + Ato uint32 + Snd_mss uint32 + Rcv_mss uint32 + Unacked uint32 + Sacked uint32 + Lost uint32 + Retrans uint32 + Fackets uint32 + Last_data_sent uint32 + Last_ack_sent uint32 + Last_data_recv uint32 + Last_ack_recv uint32 + Pmtu uint32 + Rcv_ssthresh uint32 + Rtt uint32 + Rttvar uint32 + Snd_ssthresh uint32 + Snd_cwnd uint32 + Advmss uint32 + Reordering uint32 + Rcv_rtt uint32 + Rcv_space uint32 + Total_retrans uint32 +} + +const ( + SizeofSockaddrInet4 = 0x10 + SizeofSockaddrInet6 = 0x1c + SizeofSockaddrAny = 0x70 + SizeofSockaddrUnix = 0x6e + SizeofSockaddrLinklayer = 0x14 + SizeofSockaddrNetlink = 0xc + SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 + SizeofLinger = 0x8 + SizeofIPMreq = 0x8 + SizeofIPMreqn = 0xc + SizeofIPv6Mreq = 0x14 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc + SizeofInet4Pktinfo = 0xc + SizeofInet6Pktinfo = 0x14 + SizeofIPv6MTUInfo = 0x20 + SizeofICMPv6Filter = 0x20 + SizeofUcred = 0xc + SizeofTCPInfo = 0x68 +) + +const ( + IFA_UNSPEC = 0x0 + IFA_ADDRESS = 0x1 + IFA_LOCAL = 0x2 + IFA_LABEL = 0x3 + IFA_BROADCAST = 0x4 + IFA_ANYCAST = 0x5 + IFA_CACHEINFO = 0x6 + IFA_MULTICAST = 0x7 + IFLA_UNSPEC = 0x0 + IFLA_ADDRESS = 0x1 + IFLA_BROADCAST = 0x2 + IFLA_IFNAME = 0x3 + IFLA_MTU = 0x4 + IFLA_LINK = 0x5 + IFLA_QDISC = 0x6 + IFLA_STATS = 0x7 + IFLA_COST = 0x8 + IFLA_PRIORITY = 0x9 + IFLA_MASTER = 0xa + IFLA_WIRELESS = 0xb + IFLA_PROTINFO = 0xc + IFLA_TXQLEN = 0xd + IFLA_MAP = 0xe + IFLA_WEIGHT = 0xf + IFLA_OPERSTATE = 0x10 + IFLA_LINKMODE = 0x11 + IFLA_LINKINFO = 0x12 + IFLA_NET_NS_PID = 0x13 + IFLA_IFALIAS = 0x14 + IFLA_MAX = 0x2a + RT_SCOPE_UNIVERSE = 0x0 + RT_SCOPE_SITE = 0xc8 + RT_SCOPE_LINK = 0xfd + RT_SCOPE_HOST = 0xfe + RT_SCOPE_NOWHERE = 0xff + RT_TABLE_UNSPEC = 0x0 + RT_TABLE_COMPAT = 0xfc + RT_TABLE_DEFAULT = 0xfd + RT_TABLE_MAIN = 0xfe + RT_TABLE_LOCAL = 0xff + RT_TABLE_MAX = 0xffffffff + RTA_UNSPEC = 0x0 + RTA_DST = 0x1 + RTA_SRC = 0x2 + RTA_IIF = 0x3 + RTA_OIF = 0x4 + RTA_GATEWAY = 0x5 + RTA_PRIORITY = 0x6 + RTA_PREFSRC = 0x7 + RTA_METRICS = 0x8 + RTA_MULTIPATH = 0x9 + RTA_FLOW = 0xb + RTA_CACHEINFO = 0xc + RTA_TABLE = 0xf + RTN_UNSPEC = 0x0 + RTN_UNICAST = 0x1 + RTN_LOCAL = 0x2 + RTN_BROADCAST = 0x3 + RTN_ANYCAST = 0x4 + RTN_MULTICAST = 0x5 + RTN_BLACKHOLE = 0x6 + RTN_UNREACHABLE = 0x7 + RTN_PROHIBIT = 0x8 + RTN_THROW = 0x9 + RTN_NAT = 0xa + RTN_XRESOLVE = 0xb + RTNLGRP_NONE = 0x0 + RTNLGRP_LINK = 0x1 + RTNLGRP_NOTIFY = 0x2 + RTNLGRP_NEIGH = 0x3 + RTNLGRP_TC = 0x4 + RTNLGRP_IPV4_IFADDR = 0x5 + RTNLGRP_IPV4_MROUTE = 0x6 + RTNLGRP_IPV4_ROUTE = 0x7 + RTNLGRP_IPV4_RULE = 0x8 + RTNLGRP_IPV6_IFADDR = 0x9 + RTNLGRP_IPV6_MROUTE = 0xa + RTNLGRP_IPV6_ROUTE = 0xb + RTNLGRP_IPV6_IFINFO = 0xc + RTNLGRP_IPV6_PREFIX = 0x12 + RTNLGRP_IPV6_RULE = 0x13 + RTNLGRP_ND_USEROPT = 0x14 + SizeofNlMsghdr = 0x10 + SizeofNlMsgerr = 0x14 + SizeofRtGenmsg = 0x1 + SizeofNlAttr = 0x4 + SizeofRtAttr = 0x4 + SizeofIfInfomsg = 0x10 + SizeofIfAddrmsg = 0x8 + SizeofRtMsg = 0xc + SizeofRtNexthop = 0x8 +) + +type NlMsghdr struct { + Len uint32 + Type uint16 + Flags uint16 + Seq uint32 + Pid uint32 +} + +type NlMsgerr struct { + Error int32 + Msg NlMsghdr +} + +type RtGenmsg struct { + Family uint8 +} + +type NlAttr struct { + Len uint16 + Type uint16 +} + +type RtAttr struct { + Len uint16 + Type uint16 +} + +type IfInfomsg struct { + Family uint8 + X__ifi_pad uint8 + Type uint16 + Index int32 + Flags uint32 + Change uint32 +} + +type IfAddrmsg struct { + Family uint8 + Prefixlen uint8 + Flags uint8 + Scope uint8 + Index uint32 +} + +type RtMsg struct { + Family uint8 + Dst_len uint8 + Src_len uint8 + Tos uint8 + Table uint8 + Protocol uint8 + Scope uint8 + Type uint8 + Flags uint32 +} + +type RtNexthop struct { + Len uint16 + Flags uint8 + Hops uint8 + Ifindex int32 +} + +const ( + SizeofSockFilter = 0x8 + SizeofSockFprog = 0x8 +) + +type SockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} + +type SockFprog struct { + Len uint16 + Pad_cgo_0 [2]byte + Filter *SockFilter +} + +type InotifyEvent struct { + Wd int32 + Mask uint32 + Cookie uint32 + Len uint32 +} + +const SizeofInotifyEvent = 0x10 + +type PtraceRegs struct { + Regs [109]uint32 + U_tsize uint32 + U_dsize uint32 + U_ssize uint32 + Start_code uint32 + Start_data uint32 + Start_stack uint32 + Signal int32 + U_ar0 *byte + Magic uint32 + U_comm [32]int8 +} + +type ptracePsw struct { +} + +type ptraceFpregs struct { +} + +type ptracePer struct { +} + +type FdSet struct { + Bits [32]int32 +} + +type Sysinfo_t struct { + Uptime int32 + Loads [3]uint32 + Totalram uint32 + Freeram uint32 + Sharedram uint32 + Bufferram uint32 + Totalswap uint32 + Freeswap uint32 + Procs uint16 + Pad uint16 + Totalhigh uint32 + Freehigh uint32 + Unit uint32 + X_f [8]int8 +} + +type Utsname struct { + Sysname [65]int8 + Nodename [65]int8 + Release [65]int8 + Version [65]int8 + Machine [65]int8 + Domainname [65]int8 +} + +type Ustat_t struct { + Tfree int32 + Tinode uint32 + Fname [6]int8 + Fpack [6]int8 +} + +type EpollEvent struct { + Events uint32 + PadFd int32 + Fd int32 + Pad int32 +} + +const ( + AT_FDCWD = -0x64 + AT_REMOVEDIR = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_SYMLINK_NOFOLLOW = 0x100 +) + +type PollFd struct { + Fd int32 + Events int16 + Revents int16 +} + +const ( + POLLIN = 0x1 + POLLPRI = 0x2 + POLLOUT = 0x4 + POLLRDHUP = 0x2000 + POLLERR = 0x8 + POLLHUP = 0x10 + POLLNVAL = 0x20 +) + +type Sigset_t struct { + X__val [32]uint32 +} + +const _SC_PAGESIZE = 0x1e + +type Termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Line uint8 + Cc [23]uint8 + Ispeed uint32 + Ospeed uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 4218170a9c..2db548b905 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -207,6 +207,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -332,6 +339,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 7db4c78c60..4bfdcc0aca 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -207,6 +207,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -332,6 +339,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index 76ee57cbfd..435cd792f8 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -206,6 +206,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -330,6 +337,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index 7d18b704af..439f96914f 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -211,6 +211,13 @@ type RawSockaddrHCI struct { Channel uint16 } +type RawSockaddrCAN struct { + Family uint16 + Pad_cgo_0 [2]byte + Ifindex int32 + Addr [8]byte +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -335,6 +342,7 @@ const ( SizeofSockaddrLinklayer = 0x14 SizeofSockaddrNetlink = 0xc SizeofSockaddrHCI = 0x6 + SizeofSockaddrCAN = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc diff --git a/vendor/golang.org/x/text/internal/gen/code.go b/vendor/golang.org/x/text/internal/gen/code.go index 2202c9f642..d7031b6945 100644 --- a/vendor/golang.org/x/text/internal/gen/code.go +++ b/vendor/golang.org/x/text/internal/gen/code.go @@ -117,13 +117,7 @@ func (w *CodeWriter) WriteConst(name string, x interface{}) { switch v.Type().Kind() { case reflect.String: - // See golang.org/issue/13145. - const arbitraryCutoff = 16 - if v.Len() > arbitraryCutoff { - w.printf("var %s %s = ", name, typeName(x)) - } else { - w.printf("const %s %s = ", name, typeName(x)) - } + w.printf("const %s %s = ", name, typeName(x)) w.WriteString(v.String()) w.printf("\n") default: @@ -203,16 +197,27 @@ func (w *CodeWriter) WriteString(s string) { // When starting on its own line, go fmt indents line 2+ an extra level. n, max := maxWidth, maxWidth-4 + // As per https://golang.org/issue/18078, the compiler has trouble + // compiling the concatenation of many strings, s0 + s1 + s2 + ... + sN, + // for large N. We insert redundant, explicit parentheses to work around + // that, lowering the N at any given step: (s0 + s1 + ... + s63) + (s64 + + // ... + s127) + etc + (etc + ... + sN). + explicitParens, extraComment := len(s) > 128*1024, "" + if explicitParens { + w.printf(`(`) + extraComment = "; the redundant, explicit parens are for https://golang.org/issue/18078" + } + // Print "" +\n, if a string does not start on its own line. b := w.buf.Bytes() if p := len(bytes.TrimRight(b, " \t")); p > 0 && b[p-1] != '\n' { - w.printf("\"\" + // Size: %d bytes\n", len(s)) + w.printf("\"\" + // Size: %d bytes%s\n", len(s), extraComment) n, max = maxWidth, maxWidth } w.printf(`"`) - for sz, p := 0, 0; p < len(s); { + for sz, p, nLines := 0, 0, 0; p < len(s); { var r rune r, sz = utf8.DecodeRuneInString(s[p:]) out := s[p : p+sz] @@ -229,6 +234,10 @@ func (w *CodeWriter) WriteString(s string) { chars = len(out) } if n -= chars; n < 0 { + nLines++ + if explicitParens && nLines&63 == 63 { + w.printf("\") + (\"") + } w.printf("\" +\n\"") n = max - len(out) } @@ -236,6 +245,9 @@ func (w *CodeWriter) WriteString(s string) { p += sz } w.printf(`"`) + if explicitParens { + w.printf(`)`) + } } // WriteSlice writes a slice value. diff --git a/vendor/golang.org/x/text/language/tables.go b/vendor/golang.org/x/text/language/tables.go index 1a92e582b9..ccdc1ff0f0 100644 --- a/vendor/golang.org/x/text/language/tables.go +++ b/vendor/golang.org/x/text/language/tables.go @@ -125,7 +125,7 @@ const langPrivateEnd = 0x316e // the second and third letter of the 3-letter ISO code. // - otherwise: a 0 and a by 2 bits right-shifted index into altLangISO3. // For 3-byte language identifiers the 4th byte is 0. -var lang tag.Index = "" + // Size: 5280 bytes +const lang tag.Index = "" + // Size: 5280 bytes "---\x00aaaraai\x00aak\x00aau\x00abbkabi\x00abr\x00abt\x00aby\x00acd\x00a" + "ce\x00ach\x00ada\x00ade\x00adj\x00ady\x00adz\x00aeveaeb\x00aey\x00affrag" + "c\x00agd\x00agg\x00agm\x00ago\x00agq\x00aha\x00ahl\x00aho\x00ajg\x00akka" + @@ -572,7 +572,7 @@ var langNoIndex = [2197]uint8{ // altLangISO3 holds an alphabetically sorted list of 3-letter language code alternatives // to 2-letter language codes that cannot be derived using the method described above. // Each 3-letter code is followed by its 1-byte langID. -var altLangISO3 tag.Index = "---\x00cor\x00hbs\x01heb\x02kin\x03spa\x04yid\x05\xff\xff\xff\xff" +const altLangISO3 tag.Index = "---\x00cor\x00hbs\x01heb\x02kin\x03spa\x04yid\x05\xff\xff\xff\xff" // altLangIndex is used to convert indexes in altLangISO3 to langIDs. // Size: 12 bytes, 6 elements @@ -779,7 +779,7 @@ const ( // script is an alphabetically sorted list of ISO 15924 codes. The index // of the script in the string, divided by 4, is the internal scriptID. -var script tag.Index = "" + // Size: 928 bytes +const script tag.Index = "" + // Size: 928 bytes "----AdlmAfakAghbAhomArabAranArmiArmnAvstBaliBamuBassBatkBengBhksBlisBopo" + "BrahBraiBugiBuhdCakmCansCariChamCherCirtCoptCprtCyrlCyrsDevaDsrtDuplEgyd" + "EgyhEgypElbaEthiGeokGeorGlagGothGranGrekGujrGuruHanbHangHaniHanoHansHant" + @@ -1070,7 +1070,7 @@ var regionTypes = [357]uint8{ // - [A-Z}{2}: the first letter of the 2-letter code plus these two // letters form the 3-letter ISO code. // - 0, n: index into altRegionISO3. -var regionISO tag.Index = "" + // Size: 1308 bytes +const regionISO tag.Index = "" + // Size: 1308 bytes "AAAAACSCADNDAEREAFFGAGTGAIIAALLBAMRMANNTAOGOAQTAARRGASSMATUTAUUSAWBWAXLA" + "AZZEBAIHBBRBBDGDBEELBFFABGGRBHHRBIDIBJENBLLMBMMUBNRNBOOLBQESBRRABSHSBTTN" + "BUURBVVTBWWABYLRBZLZCAANCCCKCDODCFAFCGOGCHHECIIVCKOKCLHLCMMRCNHNCOOLCPPT" + @@ -1094,7 +1094,7 @@ var regionISO tag.Index = "" + // Size: 1308 bytes // altRegionISO3 holds a list of 3-letter region codes that cannot be // mapped to 2-letter codes using the default algorithm. This is a short list. -var altRegionISO3 string = "SCGQUUSGSCOMPRKCYMSPMSRBATFMYTATN" +const altRegionISO3 string = "SCGQUUSGSCOMPRKCYMSPMSRBATFMYTATN" // altRegionIDs holds a list of regionIDs the positions of which match those // of the 3-letter ISO codes in altRegionISO3. diff --git a/vendor/golang.org/x/tools/imports/fix.go b/vendor/golang.org/x/tools/imports/fix.go index a241c29763..c74bdd2c02 100644 --- a/vendor/golang.org/x/tools/imports/fix.go +++ b/vendor/golang.org/x/tools/imports/fix.go @@ -462,6 +462,9 @@ func shouldTraverse(dir string, fi os.FileInfo) bool { if !ts.IsDir() { return false } + if skipDir(ts) { + return false + } realParent, err := filepath.EvalSymlinks(dir) if err != nil { diff --git a/vendor/gopkg.in/check.v1/.travis.yml b/vendor/gopkg.in/check.v1/.travis.yml new file mode 100644 index 0000000000..ead6735fca --- /dev/null +++ b/vendor/gopkg.in/check.v1/.travis.yml @@ -0,0 +1,3 @@ +language: go + +go_import_path: gopkg.in/check.v1 diff --git a/vendor/gopkg.in/check.v1/check.go b/vendor/gopkg.in/check.v1/check.go index 82c26fa736..137a2749a8 100644 --- a/vendor/gopkg.in/check.v1/check.go +++ b/vendor/gopkg.in/check.v1/check.go @@ -156,7 +156,7 @@ func (td *tempDir) newPath() string { } } result := filepath.Join(td.path, strconv.Itoa(td.counter)) - td.counter += 1 + td.counter++ return result } @@ -274,7 +274,7 @@ func (c *C) logString(issue string) { func (c *C) logCaller(skip int) { // This is a bit heavier than it ought to be. - skip += 1 // Our own frame. + skip++ // Our own frame. pc, callerFile, callerLine, ok := runtime.Caller(skip) if !ok { return @@ -284,7 +284,7 @@ func (c *C) logCaller(skip int) { testFunc := runtime.FuncForPC(c.method.PC()) if runtime.FuncForPC(pc) != testFunc { for { - skip += 1 + skip++ if pc, file, line, ok := runtime.Caller(skip); ok { // Note that the test line may be different on // distinct calls for the same test. Showing @@ -460,10 +460,10 @@ func (tracker *resultTracker) _loopRoutine() { // Calls still running. Can't stop. select { // XXX Reindent this (not now to make diff clear) - case c = <-tracker._expectChan: - tracker._waiting += 1 + case <-tracker._expectChan: + tracker._waiting++ case c = <-tracker._doneChan: - tracker._waiting -= 1 + tracker._waiting-- switch c.status() { case succeededSt: if c.kind == testKd { @@ -498,9 +498,9 @@ func (tracker *resultTracker) _loopRoutine() { select { case tracker._stopChan <- true: return - case c = <-tracker._expectChan: - tracker._waiting += 1 - case c = <-tracker._doneChan: + case <-tracker._expectChan: + tracker._waiting++ + case <-tracker._doneChan: panic("Tracker got an unexpected done call.") } } @@ -568,13 +568,13 @@ func newSuiteRunner(suite interface{}, runConf *RunConf) *suiteRunner { var filterRegexp *regexp.Regexp if conf.Filter != "" { - if regexp, err := regexp.Compile(conf.Filter); err != nil { + regexp, err := regexp.Compile(conf.Filter) + if err != nil { msg := "Bad filter expression: " + err.Error() runner.tracker.result.RunError = errors.New(msg) return runner - } else { - filterRegexp = regexp } + filterRegexp = regexp } for i := 0; i != suiteNumMethods; i++ { diff --git a/vendor/gopkg.in/check.v1/checkers.go b/vendor/gopkg.in/check.v1/checkers.go index bac338729c..3749545873 100644 --- a/vendor/gopkg.in/check.v1/checkers.go +++ b/vendor/gopkg.in/check.v1/checkers.go @@ -212,7 +212,7 @@ type hasLenChecker struct { // The HasLen checker verifies that the obtained value has the // provided length. In many cases this is superior to using Equals -// in conjuction with the len function because in case the check +// in conjunction with the len function because in case the check // fails the value itself will be printed, instead of its length, // providing more details for figuring the problem. // diff --git a/vendor/gopkg.in/urfave/cli.v1/.travis.yml b/vendor/gopkg.in/urfave/cli.v1/.travis.yml index 273d017b46..94836d750e 100644 --- a/vendor/gopkg.in/urfave/cli.v1/.travis.yml +++ b/vendor/gopkg.in/urfave/cli.v1/.travis.yml @@ -7,34 +7,33 @@ cache: - node_modules go: -- 1.2.2 -- 1.3.3 -- 1.4 -- 1.5.4 -- 1.6.2 +- 1.2.x +- 1.3.x +- 1.4.2 +- 1.5.x +- 1.6.x +- 1.7.x - master matrix: allow_failures: - go: master include: - - go: 1.6.2 + - go: 1.6.x + os: osx + - go: 1.7.x os: osx - - go: 1.1.2 - install: go get -v . - before_script: echo skipping gfmxr on $TRAVIS_GO_VERSION - script: - - ./runtests vet - - ./runtests test before_script: -- go get github.com/urfave/gfmxr/... +- go get github.com/urfave/gfmrun/... || true +- go get golang.org/x/tools/... || true - if [ ! -f node_modules/.bin/markdown-toc ] ; then npm install markdown-toc ; fi script: +- ./runtests gen - ./runtests vet - ./runtests test -- ./runtests gfmxr +- ./runtests gfmrun - ./runtests toc diff --git a/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md b/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md index be5b3893f6..07f75464b4 100644 --- a/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md +++ b/vendor/gopkg.in/urfave/cli.v1/CHANGELOG.md @@ -4,6 +4,57 @@ ## [Unreleased] +## [1.19.1] - 2016-11-21 + +### Fixed + +- Fixes regression introduced in 1.19.0 where using an `ActionFunc` as + the `Action` for a command would cause it to error rather than calling the + function. Should not have a affected declarative cases using `func(c + *cli.Context) err)`. +- Shell completion now handles the case where the user specifies + `--generate-bash-completion` immediately after a flag that takes an argument. + Previously it call the application with `--generate-bash-completion` as the + flag value. + +## [1.19.0] - 2016-11-19 +### Added +- `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`) +- A `Description` field was added to `App` for a more detailed description of + the application (similar to the existing `Description` field on `Command`) +- Flag type code generation via `go generate` +- Write to stderr and exit 1 if action returns non-nil error +- Added support for TOML to the `altsrc` loader +- `SkipArgReorder` was added to allow users to skip the argument reordering. + This is useful if you want to consider all "flags" after an argument as + arguments rather than flags (the default behavior of the stdlib `flag` + library). This is backported functionality from the [removal of the flag + reordering](https://github.com/urfave/cli/pull/398) in the unreleased version + 2 +- For formatted errors (those implementing `ErrorFormatter`), the errors will + be formatted during output. Compatible with `pkg/errors`. + +### Changed +- Raise minimum tested/supported Go version to 1.2+ + +### Fixed +- Consider empty environment variables as set (previously environment variables + with the equivalent of `""` would be skipped rather than their value used). +- Return an error if the value in a given environment variable cannot be parsed + as the flag type. Previously these errors were silently swallowed. +- Print full error when an invalid flag is specified (which includes the invalid flag) +- `App.Writer` defaults to `stdout` when `nil` +- If no action is specified on a command or app, the help is now printed instead of `panic`ing +- `App.Metadata` is initialized automatically now (previously was `nil` unless initialized) +- Correctly show help message if `-h` is provided to a subcommand +- `context.(Global)IsSet` now respects environment variables. Previously it + would return `false` if a flag was specified in the environment rather than + as an argument +- Removed deprecation warnings to STDERR to avoid them leaking to the end-user +- `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This + fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well + as `altsrc` where Go would complain that the types didn't match + ## [1.18.1] - 2016-08-28 ### Fixed - Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported) diff --git a/vendor/gopkg.in/urfave/cli.v1/README.md b/vendor/gopkg.in/urfave/cli.v1/README.md index ebb1d74138..bb5f61eafd 100644 --- a/vendor/gopkg.in/urfave/cli.v1/README.md +++ b/vendor/gopkg.in/urfave/cli.v1/README.md @@ -23,15 +23,16 @@ applications in an expressive way. - [Installation](#installation) * [Supported platforms](#supported-platforms) * [Using the `v2` branch](#using-the-v2-branch) - * [Pinning to the `v1` branch](#pinning-to-the-v1-branch) + * [Pinning to the `v1` releases](#pinning-to-the-v1-releases) - [Getting Started](#getting-started) - [Examples](#examples) * [Arguments](#arguments) * [Flags](#flags) + [Placeholder Values](#placeholder-values) + [Alternate Names](#alternate-names) + + [Ordering](#ordering) + [Values from the Environment](#values-from-the-environment) - + [Values from alternate input sources (YAML and others)](#values-from-alternate-input-sources-yaml-and-others) + + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) * [Subcommands](#subcommands) * [Subcommands categories](#subcommands-categories) * [Exit code](#exit-code) @@ -60,18 +61,16 @@ organized, and expressive! ## Installation -Make sure you have a working Go environment. Go version 1.1+ is required for -core cli, whereas use of the [`./altsrc`](./altsrc) input extensions requires Go -version 1.2+. [See the install -instructions](http://golang.org/doc/install.html). +Make sure you have a working Go environment. Go version 1.2+ is supported. [See +the install instructions for Go](http://golang.org/doc/install.html). To install cli, simply run: ``` $ go get github.com/urfave/cli ``` -Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands -can be easily used: +Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can +be easily used: ``` export PATH=$PATH:$GOPATH/bin ``` @@ -106,11 +105,11 @@ import ( ... ``` -### Pinning to the `v1` branch +### Pinning to the `v1` releases Similarly to the section above describing use of the `v2` branch, if one wants to avoid any unexpected compatibility pains once `v2` becomes `master`, then -pinning to the `v1` branch is an acceptable option, e.g.: +pinning to `v1` is an acceptable option, e.g.: ``` $ go get gopkg.in/urfave/cli.v1 @@ -124,6 +123,8 @@ import ( ... ``` +This will pull the latest tagged `v1` release (e.g. `v1.18.1` at the time of writing). + ## Getting Started One of the philosophies behind cli is that an API should be playful and full of @@ -450,6 +451,56 @@ That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error. +#### Ordering + +Flags for the application and commands are shown in the order they are defined. +However, it's possible to sort them from outside this library by using `FlagsByName` +with `sort`. + +For example this: + + +``` go +package main + +import ( + "os" + "sort" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "Language for the greeting", + }, + cli.StringFlag{ + Name: "config, c", + Usage: "Load configuration from `FILE`", + }, + } + + sort.Sort(cli.FlagsByName(app.Flags)) + + app.Run(os.Args) +} +``` + +Will result in help output like: + +``` +--config FILE, -c FILE Load configuration from FILE +--lang value, -l value Language for the greeting (default: "english") +``` + #### Values from the Environment You can also have the default value set from the environment via `EnvVar`. e.g. @@ -515,10 +566,14 @@ func main() { } ``` -#### Values from alternate input sources (YAML and others) +#### Values from alternate input sources (YAML, TOML, and others) There is a separate package altsrc that adds support for getting flag values -from other input sources like YAML. +from other file input sources. + +Currently supported input source formats: +* YAML +* TOML In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below: @@ -540,9 +595,9 @@ the yaml input source for any flags that are defined on that command. As a note the "load" flag used would also have to be defined on the command flags in order for this code snipped to work. -Currently only YAML files are supported but developers can add support for other -input sources by implementing the altsrc.InputSourceContext for their given -sources. +Currently only the aboved specified formats are supported but developers can +add support for other input sources by implementing the +altsrc.InputSourceContext for their given sources. Here is a more complete sample of a command using YAML support: @@ -845,7 +900,7 @@ func main() { ### Generated Help Text -The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked +The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked by the cli internals in order to print generated help text for the app, command, or subcommand, and break execution. @@ -950,12 +1005,12 @@ is checked by the cli internals in order to print the `App.Version` via #### Customization -The default flag may be cusomized to something other than `-v/--version` by +The default flag may be customized to something other than `-v/--version` by setting `cli.VersionFlag`, e.g.: ``` go package main @@ -974,7 +1029,7 @@ func main() { app := cli.NewApp() app.Name = "partay" - app.Version = "v19.99.0" + app.Version = "19.99.0" app.Run(os.Args) } ``` @@ -983,7 +1038,7 @@ Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e. ``` go package main @@ -1006,7 +1061,7 @@ func main() { app := cli.NewApp() app.Name = "partay" - app.Version = "v19.99.0" + app.Version = "19.99.0" app.Run(os.Args) } ``` @@ -1085,7 +1140,7 @@ func (g *genericType) String() string { func main() { app := cli.NewApp() app.Name = "kənˈtrīv" - app.Version = "v19.99.0" + app.Version = "19.99.0" app.Compiled = time.Now() app.Authors = []cli.Author{ cli.Author{ diff --git a/vendor/gopkg.in/urfave/cli.v1/app.go b/vendor/gopkg.in/urfave/cli.v1/app.go index 2a519528f5..95ffc0b976 100644 --- a/vendor/gopkg.in/urfave/cli.v1/app.go +++ b/vendor/gopkg.in/urfave/cli.v1/app.go @@ -6,9 +6,7 @@ import ( "io/ioutil" "os" "path/filepath" - "reflect" "sort" - "strings" "time" ) @@ -19,11 +17,8 @@ var ( contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." - errNonFuncAction = NewExitError("ERROR invalid Action type. "+ - fmt.Sprintf("Must be a func of type `cli.ActionFunc`. %s", contactSysadmin)+ - fmt.Sprintf("See %s", appActionDeprecationURL), 2) - errInvalidActionSignature = NewExitError("ERROR invalid Action signature. "+ - fmt.Sprintf("Must be `cli.ActionFunc`. %s", contactSysadmin)+ + errInvalidActionType = NewExitError("ERROR invalid Action type. "+ + fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+ fmt.Sprintf("See %s", appActionDeprecationURL), 2) ) @@ -42,6 +37,8 @@ type App struct { ArgsUsage string // Version of the program Version string + // Description of the program + Description string // List of commands to execute Commands []Command // List of flags to parse @@ -62,6 +59,7 @@ type App struct { // An action to execute after any subcommands are run, but after the subcommand has finished // It is run even if Action() panics After AfterFunc + // The action to execute when no subcommands are specified // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}` // *Note*: support for the deprecated `Action` signature will be removed in a future version @@ -147,10 +145,6 @@ func (a *App) Setup() { } } - if a.EnableBashCompletion { - a.appendFlag(BashCompletionFlag) - } - if !a.HideVersion { a.appendFlag(VersionFlag) } @@ -160,6 +154,14 @@ func (a *App) Setup() { a.categories = a.categories.AddCommand(command.Category, command) } sort.Sort(a.categories) + + if a.Metadata == nil { + a.Metadata = make(map[string]interface{}) + } + + if a.Writer == nil { + a.Writer = os.Stdout + } } // Run is the entry point to the cli app. Parses the arguments slice and routes @@ -167,8 +169,20 @@ func (a *App) Setup() { func (a *App) Run(arguments []string) (err error) { a.Setup() + // handle the completion flag separately from the flagset since + // completion could be attempted after a flag, but before its value was put + // on the command line. this causes the flagset to interpret the completion + // flag name as the value of the flag before it which is undesirable + // note that we can only do this because the shell autocomplete function + // always appends the completion flag at the end of the command + shellComplete, arguments := checkShellCompleteFlag(a, arguments) + // parse flags - set := flagSet(a.Name, a.Flags) + set, err := flagSet(a.Name, a.Flags) + if err != nil { + return err + } + set.SetOutput(ioutil.Discard) err = set.Parse(arguments[1:]) nerr := normalizeFlags(a.Flags, set) @@ -178,6 +192,7 @@ func (a *App) Run(arguments []string) (err error) { ShowAppHelp(context) return nerr } + context.shellComplete = shellComplete if checkCompletions(context) { return nil @@ -189,7 +204,7 @@ func (a *App) Run(arguments []string) (err error) { HandleExitCoder(err) return err } - fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.") + fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) ShowAppHelp(context) return err } @@ -236,6 +251,10 @@ func (a *App) Run(arguments []string) (err error) { } } + if a.Action == nil { + a.Action = helpCommand.Action + } + // Run default Action err = HandleAction(a.Action, context) @@ -277,13 +296,12 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } a.Commands = newCmds - // append flags - if a.EnableBashCompletion { - a.appendFlag(BashCompletionFlag) + // parse flags + set, err := flagSet(a.Name, a.Flags) + if err != nil { + return err } - // parse flags - set := flagSet(a.Name, a.Flags) set.SetOutput(ioutil.Discard) err = set.Parse(ctx.Args().Tail()) nerr := normalizeFlags(a.Flags, set) @@ -310,7 +328,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { HandleExitCoder(err) return err } - fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.") + fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) ShowSubcommandHelp(context) return err } @@ -451,47 +469,24 @@ type Author struct { func (a Author) String() string { e := "" if a.Email != "" { - e = "<" + a.Email + "> " + e = " <" + a.Email + ">" } - return fmt.Sprintf("%v %v", a.Name, e) + return fmt.Sprintf("%v%v", a.Name, e) } -// HandleAction uses ✧✧✧reflection✧✧✧ to figure out if the given Action is an -// ActionFunc, a func with the legacy signature for Action, or some other -// invalid thing. If it's an ActionFunc or a func with the legacy signature for -// Action, the func is run! +// HandleAction attempts to figure out which Action signature was used. If +// it's an ActionFunc or a func with the legacy signature for Action, the func +// is run! func HandleAction(action interface{}, context *Context) (err error) { - defer func() { - if r := recover(); r != nil { - // Try to detect a known reflection error from *this scope*, rather than - // swallowing all panics that may happen when calling an Action func. - s := fmt.Sprintf("%v", r) - if strings.HasPrefix(s, "reflect: ") && strings.Contains(s, "too many input arguments") { - err = NewExitError(fmt.Sprintf("ERROR unknown Action error: %v. See %s", r, appActionDeprecationURL), 2) - } else { - panic(r) - } - } - }() - - if reflect.TypeOf(action).Kind() != reflect.Func { - return errNonFuncAction - } - - vals := reflect.ValueOf(action).Call([]reflect.Value{reflect.ValueOf(context)}) - - if len(vals) == 0 { + if a, ok := action.(ActionFunc); ok { + return a(context) + } else if a, ok := action.(func(*Context) error); ok { + return a(context) + } else if a, ok := action.(func(*Context)); ok { // deprecated function signature + a(context) return nil + } else { + return errInvalidActionType } - - if len(vals) > 1 { - return errInvalidActionSignature - } - - if retErr, ok := vals[0].Interface().(error); vals[0].IsValid() && ok { - return retErr - } - - return err } diff --git a/vendor/gopkg.in/urfave/cli.v1/appveyor.yml b/vendor/gopkg.in/urfave/cli.v1/appveyor.yml index 173086e5fc..698b188e12 100644 --- a/vendor/gopkg.in/urfave/cli.v1/appveyor.yml +++ b/vendor/gopkg.in/urfave/cli.v1/appveyor.yml @@ -10,16 +10,15 @@ environment: PYTHON: C:\Python27-x64 PYTHON_VERSION: 2.7.x PYTHON_ARCH: 64 - GFMXR_DEBUG: 1 install: - set PATH=%GOPATH%\bin;C:\go\bin;%PATH% - go version - go env -- go get github.com/urfave/gfmxr/... +- go get github.com/urfave/gfmrun/... - go get -v -t ./... build_script: - python runtests vet - python runtests test -- python runtests gfmxr +- python runtests gfmrun diff --git a/vendor/gopkg.in/urfave/cli.v1/cli.go b/vendor/gopkg.in/urfave/cli.v1/cli.go index f0440c563f..74fd101f45 100644 --- a/vendor/gopkg.in/urfave/cli.v1/cli.go +++ b/vendor/gopkg.in/urfave/cli.v1/cli.go @@ -17,3 +17,5 @@ // app.Run(os.Args) // } package cli + +//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go diff --git a/vendor/gopkg.in/urfave/cli.v1/command.go b/vendor/gopkg.in/urfave/cli.v1/command.go index 8950ccae43..2628fbf48a 100644 --- a/vendor/gopkg.in/urfave/cli.v1/command.go +++ b/vendor/gopkg.in/urfave/cli.v1/command.go @@ -46,6 +46,11 @@ type Command struct { Flags []Flag // Treat all flags as normal arguments if true SkipFlagParsing bool + // Skip argument reordering which attempts to move flags before arguments, + // but only works if all flags appear after all arguments. This behavior was + // removed n version 2 since it only works under specific conditions so we + // backport here by exposing it as an option for compatibility. + SkipArgReorder bool // Boolean to hide built-in help command HideHelp bool // Boolean to hide this command from help or completion @@ -82,14 +87,15 @@ func (c Command) Run(ctx *Context) (err error) { ) } - if ctx.App.EnableBashCompletion { - c.Flags = append(c.Flags, BashCompletionFlag) + set, err := flagSet(c.Name, c.Flags) + if err != nil { + return err } - - set := flagSet(c.Name, c.Flags) set.SetOutput(ioutil.Discard) - if !c.SkipFlagParsing { + if c.SkipFlagParsing { + err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) + } else if !c.SkipArgReorder { firstFlagIndex := -1 terminatorIndex := -1 for index, arg := range ctx.Args() { @@ -122,21 +128,7 @@ func (c Command) Run(ctx *Context) (err error) { err = set.Parse(ctx.Args().Tail()) } } else { - if c.SkipFlagParsing { - err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) - } - } - - if err != nil { - if c.OnUsageError != nil { - err := c.OnUsageError(ctx, err, false) - HandleExitCoder(err) - return err - } - fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.") - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) - return err + err = set.Parse(ctx.Args().Tail()) } nerr := normalizeFlags(c.Flags, set) @@ -148,11 +140,22 @@ func (c Command) Run(ctx *Context) (err error) { } context := NewContext(ctx.App, set, ctx) - if checkCommandCompletions(context, c.Name) { return nil } + if err != nil { + if c.OnUsageError != nil { + err := c.OnUsageError(ctx, err, false) + HandleExitCoder(err) + return err + } + fmt.Fprintln(ctx.App.Writer, "Incorrect Usage:", err.Error()) + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + return err + } + if checkCommandHelp(context, c.Name) { return nil } @@ -182,6 +185,10 @@ func (c Command) Run(ctx *Context) (err error) { } } + if c.Action == nil { + c.Action = helpSubcommand.Action + } + context.Command = c err = HandleAction(c.Action, context) diff --git a/vendor/gopkg.in/urfave/cli.v1/context.go b/vendor/gopkg.in/urfave/cli.v1/context.go index 879bae5ecc..cb89e92a08 100644 --- a/vendor/gopkg.in/urfave/cli.v1/context.go +++ b/vendor/gopkg.in/urfave/cli.v1/context.go @@ -3,9 +3,9 @@ package cli import ( "errors" "flag" - "strconv" + "reflect" "strings" - "time" + "syscall" ) // Context is a type that is passed through to @@ -13,201 +13,23 @@ import ( // can be used to retrieve context-specific Args and // parsed command-line options. type Context struct { - App *App - Command Command - flagSet *flag.FlagSet - setFlags map[string]bool - globalSetFlags map[string]bool - parentContext *Context + App *App + Command Command + shellComplete bool + flagSet *flag.FlagSet + setFlags map[string]bool + parentContext *Context } // NewContext creates a new context. For use in when invoking an App or Command action. func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { - return &Context{App: app, flagSet: set, parentContext: parentCtx} -} + c := &Context{App: app, flagSet: set, parentContext: parentCtx} -// Int looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Int(name string) int { - return lookupInt(name, c.flagSet) -} - -// Int64 looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Int64(name string) int64 { - return lookupInt64(name, c.flagSet) -} - -// Uint looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Uint(name string) uint { - return lookupUint(name, c.flagSet) -} - -// Uint64 looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Uint64(name string) uint64 { - return lookupUint64(name, c.flagSet) -} - -// Duration looks up the value of a local time.Duration flag, returns 0 if no -// time.Duration flag exists -func (c *Context) Duration(name string) time.Duration { - return lookupDuration(name, c.flagSet) -} - -// Float64 looks up the value of a local float64 flag, returns 0 if no float64 -// flag exists -func (c *Context) Float64(name string) float64 { - return lookupFloat64(name, c.flagSet) -} - -// Bool looks up the value of a local bool flag, returns false if no bool flag exists -func (c *Context) Bool(name string) bool { - return lookupBool(name, c.flagSet) -} - -// BoolT looks up the value of a local boolT flag, returns false if no bool flag exists -func (c *Context) BoolT(name string) bool { - return lookupBoolT(name, c.flagSet) -} - -// String looks up the value of a local string flag, returns "" if no string flag exists -func (c *Context) String(name string) string { - return lookupString(name, c.flagSet) -} - -// StringSlice looks up the value of a local string slice flag, returns nil if no -// string slice flag exists -func (c *Context) StringSlice(name string) []string { - return lookupStringSlice(name, c.flagSet) -} - -// IntSlice looks up the value of a local int slice flag, returns nil if no int -// slice flag exists -func (c *Context) IntSlice(name string) []int { - return lookupIntSlice(name, c.flagSet) -} - -// Int64Slice looks up the value of a local int slice flag, returns nil if no int -// slice flag exists -func (c *Context) Int64Slice(name string) []int64 { - return lookupInt64Slice(name, c.flagSet) -} - -// Generic looks up the value of a local generic flag, returns nil if no generic -// flag exists -func (c *Context) Generic(name string) interface{} { - return lookupGeneric(name, c.flagSet) -} - -// GlobalInt looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalInt(name string) int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt(name, fs) + if parentCtx != nil { + c.shellComplete = parentCtx.shellComplete } - return 0 -} -// GlobalInt64 looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalInt64(name string) int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64(name, fs) - } - return 0 -} - -// GlobalUint looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalUint(name string) uint { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint(name, fs) - } - return 0 -} - -// GlobalUint64 looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalUint64(name string) uint64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint64(name, fs) - } - return 0 -} - -// GlobalFloat64 looks up the value of a global float64 flag, returns float64(0) -// if no float64 flag exists -func (c *Context) GlobalFloat64(name string) float64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupFloat64(name, fs) - } - return float64(0) -} - -// GlobalDuration looks up the value of a global time.Duration flag, returns 0 -// if no time.Duration flag exists -func (c *Context) GlobalDuration(name string) time.Duration { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupDuration(name, fs) - } - return 0 -} - -// GlobalBool looks up the value of a global bool flag, returns false if no bool -// flag exists -func (c *Context) GlobalBool(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBool(name, fs) - } - return false -} - -// GlobalBoolT looks up the value of a global bool flag, returns true if no bool -// flag exists -func (c *Context) GlobalBoolT(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBoolT(name, fs) - } - return false -} - -// GlobalString looks up the value of a global string flag, returns "" if no -// string flag exists -func (c *Context) GlobalString(name string) string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupString(name, fs) - } - return "" -} - -// GlobalStringSlice looks up the value of a global string slice flag, returns -// nil if no string slice flag exists -func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupStringSlice(name, fs) - } - return nil -} - -// GlobalIntSlice looks up the value of a global int slice flag, returns nil if -// no int slice flag exists -func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupIntSlice(name, fs) - } - return nil -} - -// GlobalInt64Slice looks up the value of a global int slice flag, returns nil if -// no int slice flag exists -func (c *Context) GlobalInt64Slice(name string) []int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64Slice(name, fs) - } - return nil -} - -// GlobalGeneric looks up the value of a global generic flag, returns nil if no -// generic flag exists -func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupGeneric(name, fs) - } - return nil + return c } // NumFlags returns the number of flags set @@ -229,28 +51,78 @@ func (c *Context) GlobalSet(name, value string) error { func (c *Context) IsSet(name string) bool { if c.setFlags == nil { c.setFlags = make(map[string]bool) + c.flagSet.Visit(func(f *flag.Flag) { c.setFlags[f.Name] = true }) + + c.flagSet.VisitAll(func(f *flag.Flag) { + if _, ok := c.setFlags[f.Name]; ok { + return + } + c.setFlags[f.Name] = false + }) + + // XXX hack to support IsSet for flags with EnvVar + // + // There isn't an easy way to do this with the current implementation since + // whether a flag was set via an environment variable is very difficult to + // determine here. Instead, we intend to introduce a backwards incompatible + // change in version 2 to add `IsSet` to the Flag interface to push the + // responsibility closer to where the information required to determine + // whether a flag is set by non-standard means such as environment + // variables is avaliable. + // + // See https://github.com/urfave/cli/issues/294 for additional discussion + flags := c.Command.Flags + if c.Command.Name == "" { // cannot == Command{} since it contains slice types + if c.App != nil { + flags = c.App.Flags + } + } + for _, f := range flags { + eachName(f.GetName(), func(name string) { + if isSet, ok := c.setFlags[name]; isSet || !ok { + return + } + + val := reflect.ValueOf(f) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + + envVarValue := val.FieldByName("EnvVar") + if !envVarValue.IsValid() { + return + } + + eachName(envVarValue.String(), func(envVar string) { + envVar = strings.TrimSpace(envVar) + if _, ok := syscall.Getenv(envVar); ok { + c.setFlags[name] = true + return + } + }) + }) + } } - return c.setFlags[name] == true + + return c.setFlags[name] } // GlobalIsSet determines if the global flag was actually set func (c *Context) GlobalIsSet(name string) bool { - if c.globalSetFlags == nil { - c.globalSetFlags = make(map[string]bool) - ctx := c - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext { - ctx.flagSet.Visit(func(f *flag.Flag) { - c.globalSetFlags[f.Name] = true - }) + ctx := c + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + + for ; ctx != nil; ctx = ctx.parentContext { + if ctx.IsSet(name) { + return true } } - return c.globalSetFlags[name] + return false } // FlagNames returns a slice of flag names used in this context. @@ -282,6 +154,11 @@ func (c *Context) Parent() *Context { return c.parentContext } +// value returns the value of the flag coressponding to `name` +func (c *Context) value(name string) interface{} { + return c.flagSet.Lookup(name).Value.(flag.Getter).Get() +} + // Args contains apps console arguments type Args []string @@ -357,156 +234,6 @@ func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { return nil } -func lookupInt(name string, set *flag.FlagSet) int { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return int(val) - } - - return 0 -} - -func lookupInt64(name string, set *flag.FlagSet) int64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupUint(name string, set *flag.FlagSet) uint { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return uint(val) - } - - return 0 -} - -func lookupUint64(name string, set *flag.FlagSet) uint64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupDuration(name string, set *flag.FlagSet) time.Duration { - f := set.Lookup(name) - if f != nil { - val, err := time.ParseDuration(f.Value.String()) - if err == nil { - return val - } - } - - return 0 -} - -func lookupFloat64(name string, set *flag.FlagSet) float64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseFloat(f.Value.String(), 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupString(name string, set *flag.FlagSet) string { - f := set.Lookup(name) - if f != nil { - return f.Value.String() - } - - return "" -} - -func lookupStringSlice(name string, set *flag.FlagSet) []string { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*StringSlice)).Value() - - } - - return nil -} - -func lookupIntSlice(name string, set *flag.FlagSet) []int { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*IntSlice)).Value() - - } - - return nil -} - -func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*Int64Slice)).Value() - - } - - return nil -} - -func lookupGeneric(name string, set *flag.FlagSet) interface{} { - f := set.Lookup(name) - if f != nil { - return f.Value - } - return nil -} - -func lookupBool(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return val - } - - return false -} - -func lookupBoolT(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return true - } - return val - } - - return false -} - func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { switch ff.Value.(type) { case *StringSlice: diff --git a/vendor/gopkg.in/urfave/cli.v1/errors.go b/vendor/gopkg.in/urfave/cli.v1/errors.go index ea551be16a..0206ff4911 100644 --- a/vendor/gopkg.in/urfave/cli.v1/errors.go +++ b/vendor/gopkg.in/urfave/cli.v1/errors.go @@ -24,7 +24,7 @@ func NewMultiError(err ...error) MultiError { return MultiError{Errors: err} } -// Error implents the error interface. +// Error implements the error interface. func (m MultiError) Error() string { errs := make([]string, len(m.Errors)) for i, err := range m.Errors { @@ -34,6 +34,10 @@ func (m MultiError) Error() string { return strings.Join(errs, "\n") } +type ErrorFormatter interface { + Format(s fmt.State, verb rune) +} + // ExitCoder is the interface checked by `App` and `Command` for a custom exit // code type ExitCoder interface { @@ -44,11 +48,11 @@ type ExitCoder interface { // ExitError fulfills both the builtin `error` interface and `ExitCoder` type ExitError struct { exitCode int - message string + message interface{} } // NewExitError makes a new *ExitError -func NewExitError(message string, exitCode int) *ExitError { +func NewExitError(message interface{}, exitCode int) *ExitError { return &ExitError{ exitCode: exitCode, message: message, @@ -58,7 +62,7 @@ func NewExitError(message string, exitCode int) *ExitError { // Error returns the string message, fulfilling the interface required by // `error` func (ee *ExitError) Error() string { - return ee.message + return fmt.Sprintf("%v", ee.message) } // ExitCode returns the exit code, fulfilling the interface required by @@ -78,7 +82,11 @@ func HandleExitCoder(err error) { if exitErr, ok := err.(ExitCoder); ok { if err.Error() != "" { - fmt.Fprintln(ErrWriter, err) + if _, ok := exitErr.(ErrorFormatter); ok { + fmt.Fprintf(ErrWriter, "%+v\n", err) + } else { + fmt.Fprintln(ErrWriter, err) + } } OsExiter(exitErr.ExitCode()) return @@ -88,5 +96,15 @@ func HandleExitCoder(err error) { for _, merr := range multiErr.Errors { HandleExitCoder(merr) } + return } + + if err.Error() != "" { + if _, ok := err.(ErrorFormatter); ok { + fmt.Fprintf(ErrWriter, "%+v\n", err) + } else { + fmt.Fprintln(ErrWriter, err) + } + } + OsExiter(1) } diff --git a/vendor/gopkg.in/urfave/cli.v1/flag-types.json b/vendor/gopkg.in/urfave/cli.v1/flag-types.json new file mode 100644 index 0000000000..1223107859 --- /dev/null +++ b/vendor/gopkg.in/urfave/cli.v1/flag-types.json @@ -0,0 +1,93 @@ +[ + { + "name": "Bool", + "type": "bool", + "value": false, + "context_default": "false", + "parser": "strconv.ParseBool(f.Value.String())" + }, + { + "name": "BoolT", + "type": "bool", + "value": false, + "doctail": " that is true by default", + "context_default": "false", + "parser": "strconv.ParseBool(f.Value.String())" + }, + { + "name": "Duration", + "type": "time.Duration", + "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", + "context_default": "0", + "parser": "time.ParseDuration(f.Value.String())" + }, + { + "name": "Float64", + "type": "float64", + "context_default": "0", + "parser": "strconv.ParseFloat(f.Value.String(), 64)" + }, + { + "name": "Generic", + "type": "Generic", + "dest": false, + "context_default": "nil", + "context_type": "interface{}" + }, + { + "name": "Int64", + "type": "int64", + "context_default": "0", + "parser": "strconv.ParseInt(f.Value.String(), 0, 64)" + }, + { + "name": "Int", + "type": "int", + "context_default": "0", + "parser": "strconv.ParseInt(f.Value.String(), 0, 64)", + "parser_cast": "int(parsed)" + }, + { + "name": "IntSlice", + "type": "*IntSlice", + "dest": false, + "context_default": "nil", + "context_type": "[]int", + "parser": "(f.Value.(*IntSlice)).Value(), error(nil)" + }, + { + "name": "Int64Slice", + "type": "*Int64Slice", + "dest": false, + "context_default": "nil", + "context_type": "[]int64", + "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)" + }, + { + "name": "String", + "type": "string", + "context_default": "\"\"", + "parser": "f.Value.String(), error(nil)" + }, + { + "name": "StringSlice", + "type": "*StringSlice", + "dest": false, + "context_default": "nil", + "context_type": "[]string", + "parser": "(f.Value.(*StringSlice)).Value(), error(nil)" + }, + { + "name": "Uint64", + "type": "uint64", + "context_default": "0", + "parser": "strconv.ParseUint(f.Value.String(), 0, 64)" + }, + { + "name": "Uint", + "type": "uint", + "context_default": "0", + "parser": "strconv.ParseUint(f.Value.String(), 0, 64)", + "parser_cast": "uint(parsed)" + } +] diff --git a/vendor/gopkg.in/urfave/cli.v1/flag.go b/vendor/gopkg.in/urfave/cli.v1/flag.go index f8a28d119e..7dd8a2c4ab 100644 --- a/vendor/gopkg.in/urfave/cli.v1/flag.go +++ b/vendor/gopkg.in/urfave/cli.v1/flag.go @@ -3,11 +3,11 @@ package cli import ( "flag" "fmt" - "os" "reflect" "runtime" "strconv" "strings" + "syscall" "time" ) @@ -37,6 +37,21 @@ var HelpFlag = BoolFlag{ // to display a flag. var FlagStringer FlagStringFunc = stringifyFlag +// FlagsByName is a slice of Flag. +type FlagsByName []Flag + +func (f FlagsByName) Len() int { + return len(f) +} + +func (f FlagsByName) Less(i, j int) bool { + return f[i].GetName() < f[j].GetName() +} + +func (f FlagsByName) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} + // Flag is a common interface related to parsing flags in cli. // For more advanced flag parsing techniques, it is recommended that // this interface be implemented. @@ -47,13 +62,29 @@ type Flag interface { GetName() string } -func flagSet(name string, flags []Flag) *flag.FlagSet { +// errorableFlag is an interface that allows us to return errors during apply +// it allows flags defined in this library to return errors in a fashion backwards compatible +// TODO remove in v2 and modify the existing Flag interface to return errors +type errorableFlag interface { + Flag + + ApplyWithError(*flag.FlagSet) error +} + +func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { set := flag.NewFlagSet(name, flag.ContinueOnError) for _, f := range flags { - f.Apply(set) + //TODO remove in v2 when errorableFlag is removed + if ef, ok := f.(errorableFlag); ok { + if err := ef.ApplyWithError(set); err != nil { + return nil, err + } + } else { + f.Apply(set) + } } - return set + return set, nil } func eachName(longName string, fn func(string)) { @@ -70,31 +101,24 @@ type Generic interface { String() string } -// GenericFlag is the flag type for types implementing Generic -type GenericFlag struct { - Name string - Value Generic - Usage string - EnvVar string - Hidden bool -} - -// String returns the string representation of the generic flag to display the -// help text to the user (uses the String() method of the generic flag to show -// the value) -func (f GenericFlag) String() string { - return FlagStringer(f) -} - // Apply takes the flagset and calls Set on the generic flag with the value // provided by the user for parsing by the flag +// Ignores parsing errors func (f GenericFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error { val := f.Value if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - val.Set(envVal) + if envVal, ok := syscall.Getenv(envVar); ok { + if err := val.Set(envVal); err != nil { + return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err) + } break } } @@ -103,14 +127,11 @@ func (f GenericFlag) Apply(set *flag.FlagSet) { eachName(f.Name, func(name string) { set.Var(f.Value, name, f.Usage) }) + + return nil } -// GetName returns the name of a flag. -func (f GenericFlag) GetName() string { - return f.Name -} - -// StringSlice is an opaque type for []string to satisfy flag.Value +// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter type StringSlice []string // Set appends the string value to the list of values @@ -129,31 +150,29 @@ func (f *StringSlice) Value() []string { return *f } -// StringSliceFlag is a string flag that can be specified multiple times on the -// command-line -type StringSliceFlag struct { - Name string - Value *StringSlice - Usage string - EnvVar string - Hidden bool -} - -// String returns the usage -func (f StringSliceFlag) String() string { - return FlagStringer(f) +// Get returns the slice of strings set by this flag +func (f *StringSlice) Get() interface{} { + return *f } // Apply populates the flag given the flag set and environment +// Ignores errors func (f StringSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { newVal := &StringSlice{} for _, s := range strings.Split(envVal, ",") { s = strings.TrimSpace(s) - newVal.Set(s) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err) + } } f.Value = newVal break @@ -167,14 +186,11 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) { } set.Var(f.Value, name, f.Usage) }) + + return nil } -// GetName returns the name of a flag. -func (f StringSliceFlag) GetName() string { - return f.Name -} - -// IntSlice is an opaque type for []int to satisfy flag.Value +// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter type IntSlice []int // Set parses the value into an integer and appends it to the list of values @@ -197,33 +213,28 @@ func (f *IntSlice) Value() []int { return *f } -// IntSliceFlag is an int flag that can be specified multiple times on the -// command-line -type IntSliceFlag struct { - Name string - Value *IntSlice - Usage string - EnvVar string - Hidden bool -} - -// String returns the usage -func (f IntSliceFlag) String() string { - return FlagStringer(f) +// Get returns the slice of ints set by this flag +func (f *IntSlice) Get() interface{} { + return *f } // Apply populates the flag given the flag set and environment +// Ignores errors func (f IntSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { newVal := &IntSlice{} for _, s := range strings.Split(envVal, ",") { s = strings.TrimSpace(s) - err := newVal.Set(s) - if err != nil { - fmt.Fprintf(ErrWriter, err.Error()) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err) } } f.Value = newVal @@ -238,14 +249,11 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) { } set.Var(f.Value, name, f.Usage) }) + + return nil } -// GetName returns the name of the flag. -func (f IntSliceFlag) GetName() string { - return f.Name -} - -// Int64Slice is an opaque type for []int to satisfy flag.Value +// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter type Int64Slice []int64 // Set parses the value into an integer and appends it to the list of values @@ -268,33 +276,28 @@ func (f *Int64Slice) Value() []int64 { return *f } -// Int64SliceFlag is an int flag that can be specified multiple times on the -// command-line -type Int64SliceFlag struct { - Name string - Value *Int64Slice - Usage string - EnvVar string - Hidden bool -} - -// String returns the usage -func (f Int64SliceFlag) String() string { - return FlagStringer(f) +// Get returns the slice of ints set by this flag +func (f *Int64Slice) Get() interface{} { + return *f } // Apply populates the flag given the flag set and environment +// Ignores errors func (f Int64SliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { newVal := &Int64Slice{} for _, s := range strings.Split(envVal, ",") { s = strings.TrimSpace(s) - err := newVal.Set(s) - if err != nil { - fmt.Fprintf(ErrWriter, err.Error()) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err) } } f.Value = newVal @@ -309,38 +312,33 @@ func (f Int64SliceFlag) Apply(set *flag.FlagSet) { } set.Var(f.Value, name, f.Usage) }) -} - -// GetName returns the name of the flag. -func (f Int64SliceFlag) GetName() string { - return f.Name -} - -// BoolFlag is a switch that defaults to false -type BoolFlag struct { - Name string - Usage string - EnvVar string - Destination *bool - Hidden bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f BoolFlag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f BoolFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error { val := false if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValBool, err := strconv.ParseBool(envVal) - if err == nil { - val = envValBool + if envVal, ok := syscall.Getenv(envVar); ok { + if envVal == "" { + val = false + break } + + envValBool, err := strconv.ParseBool(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) + } + + val = envValBool break } } @@ -353,40 +351,35 @@ func (f BoolFlag) Apply(set *flag.FlagSet) { } set.Bool(name, val, f.Usage) }) -} -// GetName returns the name of the flag. -func (f BoolFlag) GetName() string { - return f.Name -} - -// BoolTFlag this represents a boolean flag that is true by default, but can -// still be set to false by --some-flag=false -type BoolTFlag struct { - Name string - Usage string - EnvVar string - Destination *bool - Hidden bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f BoolTFlag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f BoolTFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error { val := true if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { - envValBool, err := strconv.ParseBool(envVal) - if err == nil { - val = envValBool + if envVal, ok := syscall.Getenv(envVar); ok { + if envVal == "" { + val = false break } + + envValBool, err := strconv.ParseBool(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) + } + + val = envValBool + break } } } @@ -398,34 +391,22 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) { } set.Bool(name, val, f.Usage) }) -} -// GetName returns the name of the flag. -func (f BoolTFlag) GetName() string { - return f.Name -} - -// StringFlag represents a flag that takes as string value -type StringFlag struct { - Name string - Value string - Usage string - EnvVar string - Destination *string - Hidden bool -} - -// String returns the usage -func (f StringFlag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f StringFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f StringFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { f.Value = envVal break } @@ -439,39 +420,28 @@ func (f StringFlag) Apply(set *flag.FlagSet) { } set.String(name, f.Value, f.Usage) }) -} -// GetName returns the name of the flag. -func (f StringFlag) GetName() string { - return f.Name -} - -// IntFlag is a flag that takes an integer -type IntFlag struct { - Name string - Value int - Usage string - EnvVar string - Destination *int - Hidden bool -} - -// String returns the usage -func (f IntFlag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f IntFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f IntFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err == nil { - f.Value = int(envValInt) - break + if err != nil { + return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) } + f.Value = int(envValInt) + break } } } @@ -483,39 +453,29 @@ func (f IntFlag) Apply(set *flag.FlagSet) { } set.Int(name, f.Value, f.Usage) }) -} -// GetName returns the name of the flag. -func (f IntFlag) GetName() string { - return f.Name -} - -// Int64Flag is a flag that takes a 64-bit integer -type Int64Flag struct { - Name string - Value int64 - Usage string - EnvVar string - Destination *int64 - Hidden bool -} - -// String returns the usage -func (f Int64Flag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f Int64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err == nil { - f.Value = envValInt - break + if err != nil { + return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) } + + f.Value = envValInt + break } } } @@ -527,39 +487,29 @@ func (f Int64Flag) Apply(set *flag.FlagSet) { } set.Int64(name, f.Value, f.Usage) }) -} -// GetName returns the name of the flag. -func (f Int64Flag) GetName() string { - return f.Name -} - -// UintFlag is a flag that takes an unsigned integer -type UintFlag struct { - Name string - Value uint - Usage string - EnvVar string - Destination *uint - Hidden bool -} - -// String returns the usage -func (f UintFlag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f UintFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f UintFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err == nil { - f.Value = uint(envValInt) - break + if err != nil { + return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) } + + f.Value = uint(envValInt) + break } } } @@ -571,39 +521,29 @@ func (f UintFlag) Apply(set *flag.FlagSet) { } set.Uint(name, f.Value, f.Usage) }) -} -// GetName returns the name of the flag. -func (f UintFlag) GetName() string { - return f.Name -} - -// Uint64Flag is a flag that takes an unsigned 64-bit integer -type Uint64Flag struct { - Name string - Value uint64 - Usage string - EnvVar string - Destination *uint64 - Hidden bool -} - -// String returns the usage -func (f Uint64Flag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f Uint64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err == nil { - f.Value = uint64(envValInt) - break + if err != nil { + return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err) } + + f.Value = uint64(envValInt) + break } } } @@ -615,40 +555,29 @@ func (f Uint64Flag) Apply(set *flag.FlagSet) { } set.Uint64(name, f.Value, f.Usage) }) -} -// GetName returns the name of the flag. -func (f Uint64Flag) GetName() string { - return f.Name -} - -// DurationFlag is a flag that takes a duration specified in Go's duration -// format: https://golang.org/pkg/time/#ParseDuration -type DurationFlag struct { - Name string - Value time.Duration - Usage string - EnvVar string - Destination *time.Duration - Hidden bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f DurationFlag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f DurationFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValDuration, err := time.ParseDuration(envVal) - if err == nil { - f.Value = envValDuration - break + if err != nil { + return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err) } + + f.Value = envValDuration + break } } } @@ -660,38 +589,29 @@ func (f DurationFlag) Apply(set *flag.FlagSet) { } set.Duration(name, f.Value, f.Usage) }) -} -// GetName returns the name of the flag. -func (f DurationFlag) GetName() string { - return f.Name -} - -// Float64Flag is a flag that takes an float value -type Float64Flag struct { - Name string - Value float64 - Usage string - EnvVar string - Destination *float64 - Hidden bool -} - -// String returns the usage -func (f Float64Flag) String() string { - return FlagStringer(f) + return nil } // Apply populates the flag given the flag set and environment +// Ignores errors func (f Float64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { if f.EnvVar != "" { for _, envVar := range strings.Split(f.EnvVar, ",") { envVar = strings.TrimSpace(envVar) - if envVal := os.Getenv(envVar); envVal != "" { + if envVal, ok := syscall.Getenv(envVar); ok { envValFloat, err := strconv.ParseFloat(envVal, 10) - if err == nil { - f.Value = float64(envValFloat) + if err != nil { + return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err) } + + f.Value = float64(envValFloat) + break } } } @@ -703,11 +623,8 @@ func (f Float64Flag) Apply(set *flag.FlagSet) { } set.Float64(name, f.Value, f.Usage) }) -} -// GetName returns the name of the flag. -func (f Float64Flag) GetName() string { - return f.Name + return nil } func visibleFlags(fl []Flag) []Flag { diff --git a/vendor/gopkg.in/urfave/cli.v1/flag_generated.go b/vendor/gopkg.in/urfave/cli.v1/flag_generated.go new file mode 100644 index 0000000000..491b61956c --- /dev/null +++ b/vendor/gopkg.in/urfave/cli.v1/flag_generated.go @@ -0,0 +1,627 @@ +package cli + +import ( + "flag" + "strconv" + "time" +) + +// WARNING: This file is generated! + +// BoolFlag is a flag with type bool +type BoolFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolFlag) GetName() string { + return f.Name +} + +// Bool looks up the value of a local BoolFlag, returns +// false if not found +func (c *Context) Bool(name string) bool { + return lookupBool(name, c.flagSet) +} + +// GlobalBool looks up the value of a global BoolFlag, returns +// false if not found +func (c *Context) GlobalBool(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBool(name, fs) + } + return false +} + +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + +// BoolTFlag is a flag with type bool that is true by default +type BoolTFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolTFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolTFlag) GetName() string { + return f.Name +} + +// BoolT looks up the value of a local BoolTFlag, returns +// false if not found +func (c *Context) BoolT(name string) bool { + return lookupBoolT(name, c.flagSet) +} + +// GlobalBoolT looks up the value of a global BoolTFlag, returns +// false if not found +func (c *Context) GlobalBoolT(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBoolT(name, fs) + } + return false +} + +func lookupBoolT(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + +// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) +type DurationFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value time.Duration + Destination *time.Duration +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f DurationFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f DurationFlag) GetName() string { + return f.Name +} + +// Duration looks up the value of a local DurationFlag, returns +// 0 if not found +func (c *Context) Duration(name string) time.Duration { + return lookupDuration(name, c.flagSet) +} + +// GlobalDuration looks up the value of a global DurationFlag, returns +// 0 if not found +func (c *Context) GlobalDuration(name string) time.Duration { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupDuration(name, fs) + } + return 0 +} + +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + parsed, err := time.ParseDuration(f.Value.String()) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// Float64Flag is a flag with type float64 +type Float64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value float64 + Destination *float64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Float64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Float64Flag) GetName() string { + return f.Name +} + +// Float64 looks up the value of a local Float64Flag, returns +// 0 if not found +func (c *Context) Float64(name string) float64 { + return lookupFloat64(name, c.flagSet) +} + +// GlobalFloat64 looks up the value of a global Float64Flag, returns +// 0 if not found +func (c *Context) GlobalFloat64(name string) float64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupFloat64(name, fs) + } + return 0 +} + +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// GenericFlag is a flag with type Generic +type GenericFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value Generic +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f GenericFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f GenericFlag) GetName() string { + return f.Name +} + +// Generic looks up the value of a local GenericFlag, returns +// nil if not found +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + +// GlobalGeneric looks up the value of a global GenericFlag, returns +// nil if not found +func (c *Context) GlobalGeneric(name string) interface{} { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupGeneric(name, fs) + } + return nil +} + +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value, error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Int64Flag is a flag with type int64 +type Int64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int64 + Destination *int64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64Flag) GetName() string { + return f.Name +} + +// Int64 looks up the value of a local Int64Flag, returns +// 0 if not found +func (c *Context) Int64(name string) int64 { + return lookupInt64(name, c.flagSet) +} + +// GlobalInt64 looks up the value of a global Int64Flag, returns +// 0 if not found +func (c *Context) GlobalInt64(name string) int64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt64(name, fs) + } + return 0 +} + +func lookupInt64(name string, set *flag.FlagSet) int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// IntFlag is a flag with type int +type IntFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int + Destination *int +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntFlag) GetName() string { + return f.Name +} + +// Int looks up the value of a local IntFlag, returns +// 0 if not found +func (c *Context) Int(name string) int { + return lookupInt(name, c.flagSet) +} + +// GlobalInt looks up the value of a global IntFlag, returns +// 0 if not found +func (c *Context) GlobalInt(name string) int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt(name, fs) + } + return 0 +} + +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return int(parsed) + } + return 0 +} + +// IntSliceFlag is a flag with type *IntSlice +type IntSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *IntSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntSliceFlag) GetName() string { + return f.Name +} + +// IntSlice looks up the value of a local IntSliceFlag, returns +// nil if not found +func (c *Context) IntSlice(name string) []int { + return lookupIntSlice(name, c.flagSet) +} + +// GlobalIntSlice looks up the value of a global IntSliceFlag, returns +// nil if not found +func (c *Context) GlobalIntSlice(name string) []int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupIntSlice(name, fs) + } + return nil +} + +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Int64SliceFlag is a flag with type *Int64Slice +type Int64SliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *Int64Slice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64SliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64SliceFlag) GetName() string { + return f.Name +} + +// Int64Slice looks up the value of a local Int64SliceFlag, returns +// nil if not found +func (c *Context) Int64Slice(name string) []int64 { + return lookupInt64Slice(name, c.flagSet) +} + +// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns +// nil if not found +func (c *Context) GlobalInt64Slice(name string) []int64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt64Slice(name, fs) + } + return nil +} + +func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// StringFlag is a flag with type string +type StringFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value string + Destination *string +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringFlag) GetName() string { + return f.Name +} + +// String looks up the value of a local StringFlag, returns +// "" if not found +func (c *Context) String(name string) string { + return lookupString(name, c.flagSet) +} + +// GlobalString looks up the value of a global StringFlag, returns +// "" if not found +func (c *Context) GlobalString(name string) string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupString(name, fs) + } + return "" +} + +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value.String(), error(nil) + if err != nil { + return "" + } + return parsed + } + return "" +} + +// StringSliceFlag is a flag with type *StringSlice +type StringSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *StringSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringSliceFlag) GetName() string { + return f.Name +} + +// StringSlice looks up the value of a local StringSliceFlag, returns +// nil if not found +func (c *Context) StringSlice(name string) []string { + return lookupStringSlice(name, c.flagSet) +} + +// GlobalStringSlice looks up the value of a global StringSliceFlag, returns +// nil if not found +func (c *Context) GlobalStringSlice(name string) []string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupStringSlice(name, fs) + } + return nil +} + +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Uint64Flag is a flag with type uint64 +type Uint64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint64 + Destination *uint64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Uint64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Uint64Flag) GetName() string { + return f.Name +} + +// Uint64 looks up the value of a local Uint64Flag, returns +// 0 if not found +func (c *Context) Uint64(name string) uint64 { + return lookupUint64(name, c.flagSet) +} + +// GlobalUint64 looks up the value of a global Uint64Flag, returns +// 0 if not found +func (c *Context) GlobalUint64(name string) uint64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupUint64(name, fs) + } + return 0 +} + +func lookupUint64(name string, set *flag.FlagSet) uint64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// UintFlag is a flag with type uint +type UintFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint + Destination *uint +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f UintFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f UintFlag) GetName() string { + return f.Name +} + +// Uint looks up the value of a local UintFlag, returns +// 0 if not found +func (c *Context) Uint(name string) uint { + return lookupUint(name, c.flagSet) +} + +// GlobalUint looks up the value of a global UintFlag, returns +// 0 if not found +func (c *Context) GlobalUint(name string) uint { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupUint(name, fs) + } + return 0 +} + +func lookupUint(name string, set *flag.FlagSet) uint { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return uint(parsed) + } + return 0 +} diff --git a/vendor/gopkg.in/urfave/cli.v1/generate-flag-types b/vendor/gopkg.in/urfave/cli.v1/generate-flag-types new file mode 100755 index 0000000000..7147381ce3 --- /dev/null +++ b/vendor/gopkg.in/urfave/cli.v1/generate-flag-types @@ -0,0 +1,255 @@ +#!/usr/bin/env python +""" +The flag types that ship with the cli library have many things in common, and +so we can take advantage of the `go generate` command to create much of the +source code from a list of definitions. These definitions attempt to cover +the parts that vary between flag types, and should evolve as needed. + +An example of the minimum definition needed is: + + { + "name": "SomeType", + "type": "sometype", + "context_default": "nil" + } + +In this example, the code generated for the `cli` package will include a type +named `SomeTypeFlag` that is expected to wrap a value of type `sometype`. +Fetching values by name via `*cli.Context` will default to a value of `nil`. + +A more complete, albeit somewhat redundant, example showing all available +definition keys is: + + { + "name": "VeryMuchType", + "type": "*VeryMuchType", + "value": true, + "dest": false, + "doctail": " which really only wraps a []float64, oh well!", + "context_type": "[]float64", + "context_default": "nil", + "parser": "parseVeryMuchType(f.Value.String())", + "parser_cast": "[]float64(parsed)" + } + +The meaning of each field is as follows: + + name (string) - The type "name", which will be suffixed with + `Flag` when generating the type definition + for `cli` and the wrapper type for `altsrc` + type (string) - The type that the generated `Flag` type for `cli` + is expected to "contain" as its `.Value` member + value (bool) - Should the generated `cli` type have a `Value` + member? + dest (bool) - Should the generated `cli` type support a + destination pointer? + doctail (string) - Additional docs for the `cli` flag type comment + context_type (string) - The literal type used in the `*cli.Context` + reader func signature + context_default (string) - The literal value used as the default by the + `*cli.Context` reader funcs when no value is + present + parser (string) - Literal code used to parse the flag `f`, + expected to have a return signature of + (value, error) + parser_cast (string) - Literal code used to cast the `parsed` value + returned from the `parser` code +""" + +from __future__ import print_function, unicode_literals + +import argparse +import json +import os +import subprocess +import sys +import tempfile +import textwrap + + +class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + + +def main(sysargs=sys.argv[:]): + parser = argparse.ArgumentParser( + description='Generate flag type code!', + formatter_class=_FancyFormatter) + parser.add_argument( + 'package', + type=str, default='cli', choices=_WRITEFUNCS.keys(), + help='Package for which flag types will be generated' + ) + parser.add_argument( + '-i', '--in-json', + type=argparse.FileType('r'), + default=sys.stdin, + help='Input JSON file which defines each type to be generated' + ) + parser.add_argument( + '-o', '--out-go', + type=argparse.FileType('w'), + default=sys.stdout, + help='Output file/stream to which generated source will be written' + ) + parser.epilog = __doc__ + + args = parser.parse_args(sysargs[1:]) + _generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json) + return 0 + + +def _generate_flag_types(writefunc, output_go, input_json): + types = json.load(input_json) + + tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False) + writefunc(tmp, types) + tmp.close() + + new_content = subprocess.check_output( + ['goimports', tmp.name] + ).decode('utf-8') + + print(new_content, file=output_go, end='') + output_go.flush() + os.remove(tmp.name) + + +def _set_typedef_defaults(typedef): + typedef.setdefault('doctail', '') + typedef.setdefault('context_type', typedef['type']) + typedef.setdefault('dest', True) + typedef.setdefault('value', True) + typedef.setdefault('parser', 'f.Value, error(nil)') + typedef.setdefault('parser_cast', 'parsed') + + +def _write_cli_flag_types(outfile, types): + _fwrite(outfile, """\ + package cli + + // WARNING: This file is generated! + + """) + + for typedef in types: + _set_typedef_defaults(typedef) + + _fwrite(outfile, """\ + // {name}Flag is a flag with type {type}{doctail} + type {name}Flag struct {{ + Name string + Usage string + EnvVar string + Hidden bool + """.format(**typedef)) + + if typedef['value']: + _fwrite(outfile, """\ + Value {type} + """.format(**typedef)) + + if typedef['dest']: + _fwrite(outfile, """\ + Destination *{type} + """.format(**typedef)) + + _fwrite(outfile, "\n}\n\n") + + _fwrite(outfile, """\ + // String returns a readable representation of this value + // (for usage defaults) + func (f {name}Flag) String() string {{ + return FlagStringer(f) + }} + + // GetName returns the name of the flag + func (f {name}Flag) GetName() string {{ + return f.Name + }} + + // {name} looks up the value of a local {name}Flag, returns + // {context_default} if not found + func (c *Context) {name}(name string) {context_type} {{ + return lookup{name}(name, c.flagSet) + }} + + // Global{name} looks up the value of a global {name}Flag, returns + // {context_default} if not found + func (c *Context) Global{name}(name string) {context_type} {{ + if fs := lookupGlobalFlagSet(name, c); fs != nil {{ + return lookup{name}(name, fs) + }} + return {context_default} + }} + + func lookup{name}(name string, set *flag.FlagSet) {context_type} {{ + f := set.Lookup(name) + if f != nil {{ + parsed, err := {parser} + if err != nil {{ + return {context_default} + }} + return {parser_cast} + }} + return {context_default} + }} + """.format(**typedef)) + + +def _write_altsrc_flag_types(outfile, types): + _fwrite(outfile, """\ + package altsrc + + import ( + "gopkg.in/urfave/cli.v1" + ) + + // WARNING: This file is generated! + + """) + + for typedef in types: + _set_typedef_defaults(typedef) + + _fwrite(outfile, """\ + // {name}Flag is the flag type that wraps cli.{name}Flag to allow + // for other values to be specified + type {name}Flag struct {{ + cli.{name}Flag + set *flag.FlagSet + }} + + // New{name}Flag creates a new {name}Flag + func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{ + return &{name}Flag{{{name}Flag: fl, set: nil}} + }} + + // Apply saves the flagSet for later usage calls, then calls the + // wrapped {name}Flag.Apply + func (f *{name}Flag) Apply(set *flag.FlagSet) {{ + f.set = set + f.{name}Flag.Apply(set) + }} + + // ApplyWithError saves the flagSet for later usage calls, then calls the + // wrapped {name}Flag.ApplyWithError + func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{ + f.set = set + return f.{name}Flag.ApplyWithError(set) + }} + """.format(**typedef)) + + +def _fwrite(outfile, text): + print(textwrap.dedent(text), end='', file=outfile) + + +_WRITEFUNCS = { + 'cli': _write_cli_flag_types, + 'altsrc': _write_altsrc_flag_types +} + +if __name__ == '__main__': + sys.exit(main()) diff --git a/vendor/gopkg.in/urfave/cli.v1/help.go b/vendor/gopkg.in/urfave/cli.v1/help.go index 0f4cf14cd8..c8c1aee057 100644 --- a/vendor/gopkg.in/urfave/cli.v1/help.go +++ b/vendor/gopkg.in/urfave/cli.v1/help.go @@ -13,27 +13,31 @@ import ( // cli.go uses text/template to render templates. You can // render custom help text by setting this variable. var AppHelpTemplate = `NAME: - {{.Name}} - {{.Usage}} + {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} - {{if .Version}}{{if not .HideVersion}} + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + VERSION: - {{.Version}} - {{end}}{{end}}{{if len .Authors}} -AUTHOR(S): - {{range .Authors}}{{.}}{{end}} - {{end}}{{if .VisibleCommands}} + {{.Version}}{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if len .Authors}} + +AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: + {{range $index, $author := .Authors}}{{if $index}} + {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} + COMMANDS:{{range .VisibleCategories}}{{if .Name}} {{.Name}}:{{end}}{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} -{{end}}{{end}}{{if .VisibleFlags}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} + GLOBAL OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}}{{if .Copyright}} + {{range $index, $option := .VisibleFlags}}{{if $index}} + {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} + COPYRIGHT: - {{.Copyright}} - {{end}} + {{.Copyright}}{{end}} ` // CommandHelpTemplate is the text template for the command help topic. @@ -240,7 +244,7 @@ func checkCommandHelp(c *Context, name string) bool { } func checkSubcommandHelp(c *Context) bool { - if c.GlobalBool("h") || c.GlobalBool("help") { + if c.Bool("h") || c.Bool("help") { ShowSubcommandHelp(c) return true } @@ -248,20 +252,43 @@ func checkSubcommandHelp(c *Context) bool { return false } -func checkCompletions(c *Context) bool { - if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion { - ShowCompletions(c) - return true +func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { + if !a.EnableBashCompletion { + return false, arguments } - return false + pos := len(arguments) - 1 + lastArg := arguments[pos] + + if lastArg != "--"+BashCompletionFlag.Name { + return false, arguments + } + + return true, arguments[:pos] +} + +func checkCompletions(c *Context) bool { + if !c.shellComplete { + return false + } + + if args := c.Args(); args.Present() { + name := args.First() + if cmd := c.App.Command(name); cmd != nil { + // let the command handle the completion + return false + } + } + + ShowCompletions(c) + return true } func checkCommandCompletions(c *Context, name string) bool { - if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { - ShowCommandCompletions(c, name) - return true + if !c.shellComplete { + return false } - return false + ShowCommandCompletions(c, name) + return true } diff --git a/vendor/gopkg.in/urfave/cli.v1/runtests b/vendor/gopkg.in/urfave/cli.v1/runtests index 0a7b483e31..ee22bdeed5 100755 --- a/vendor/gopkg.in/urfave/cli.v1/runtests +++ b/vendor/gopkg.in/urfave/cli.v1/runtests @@ -18,8 +18,9 @@ def main(sysargs=sys.argv[:]): targets = { 'vet': _vet, 'test': _test, - 'gfmxr': _gfmxr, + 'gfmrun': _gfmrun, 'toc': _toc, + 'gen': _gen, } parser = argparse.ArgumentParser() @@ -34,7 +35,7 @@ def main(sysargs=sys.argv[:]): def _test(): if check_output('go version'.split()).split()[2] < 'go1.2': - _run('go test -v .'.split()) + _run('go test -v .') return coverprofiles = [] @@ -51,29 +52,45 @@ def _test(): ]) combined_name = _combine_coverprofiles(coverprofiles) - _run('go tool cover -func={}'.format(combined_name).split()) + _run('go tool cover -func={}'.format(combined_name)) os.remove(combined_name) -def _gfmxr(): - _run(['gfmxr', '-c', str(_gfmxr_count()), '-s', 'README.md']) +def _gfmrun(): + go_version = check_output('go version'.split()).split()[2] + if go_version < 'go1.3': + print('runtests: skip on {}'.format(go_version), file=sys.stderr) + return + _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md']) def _vet(): - _run('go vet ./...'.split()) + _run('go vet ./...') def _toc(): - _run(['node_modules/.bin/markdown-toc', '-i', 'README.md']) - _run(['git', 'diff', '--quiet']) + _run('node_modules/.bin/markdown-toc -i README.md') + _run('git diff --exit-code') + + +def _gen(): + go_version = check_output('go version'.split()).split()[2] + if go_version < 'go1.5': + print('runtests: skip on {}'.format(go_version), file=sys.stderr) + return + + _run('go generate ./...') + _run('git diff --exit-code') def _run(command): + if hasattr(command, 'split'): + command = command.split() print('runtests: {}'.format(' '.join(command)), file=sys.stderr) check_call(command) -def _gfmxr_count(): +def _gfmrun_count(): with open('README.md') as infile: lines = infile.read().splitlines() return len(filter(_is_go_runnable, lines)) diff --git a/whisper/shhapi/api.go b/whisper/shhapi/api.go index f9f9ed962a..3bcf32e5ab 100644 --- a/whisper/shhapi/api.go +++ b/whisper/shhapi/api.go @@ -23,6 +23,7 @@ import ( mathrand "math/rand" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/crypto" "github.com/ubiq/go-ubiq/logger" "github.com/ubiq/go-ubiq/logger/glog" @@ -55,17 +56,33 @@ func APIs() []rpc.API { } } -// Version returns the Whisper version this node offers. -func (api *PublicWhisperAPI) Version() (*rpc.HexNumber, error) { +// Start starts the Whisper worker threads. +func (api *PublicWhisperAPI) Start() error { if api.whisper == nil { - return rpc.NewHexNumber(0), whisperOffLineErr + return whisperOffLineErr } - return rpc.NewHexNumber(api.whisper.Version()), nil + return api.whisper.Start(nil) +} + +// Stop stops the Whisper worker threads. +func (api *PublicWhisperAPI) Stop() error { + if api.whisper == nil { + return whisperOffLineErr + } + return api.whisper.Stop() +} + +// Version returns the Whisper version this node offers. +func (api *PublicWhisperAPI) Version() (hexutil.Uint, error) { + if api.whisper == nil { + return 0, whisperOffLineErr + } + return hexutil.Uint(api.whisper.Version()), nil } // MarkPeerTrusted marks specific peer trusted, which will allow it // to send historic (expired) messages. -func (api *PublicWhisperAPI) MarkPeerTrusted(peerID rpc.HexBytes) error { +func (api *PublicWhisperAPI) MarkPeerTrusted(peerID hexutil.Bytes) error { if api.whisper == nil { return whisperOffLineErr } @@ -76,7 +93,7 @@ func (api *PublicWhisperAPI) MarkPeerTrusted(peerID rpc.HexBytes) error { // data contains parameters (time frame, payment details, etc.), required // by the remote email-like server. Whisper is not aware about the data format, // it will just forward the raw data to the server. -func (api *PublicWhisperAPI) RequestHistoricMessages(peerID rpc.HexBytes, data rpc.HexBytes) error { +func (api *PublicWhisperAPI) RequestHistoricMessages(peerID hexutil.Bytes, data hexutil.Bytes) error { if api.whisper == nil { return whisperOffLineErr } @@ -161,14 +178,10 @@ func (api *PublicWhisperAPI) NewFilter(args WhisperFilterArgs) (uint32, error) { Messages: make(map[common.Hash]*whisperv5.ReceivedMessage), AcceptP2P: args.AcceptP2P, } - if len(filter.KeySym) > 0 { filter.SymKeyHash = crypto.Keccak256Hash(filter.KeySym) } - - for _, t := range args.Topics { - filter.Topics = append(filter.Topics, t) - } + filter.Topics = append(filter.Topics, args.Topics...) if len(args.Topics) == 0 { info := "NewFilter: at least one topic must be specified" @@ -372,12 +385,12 @@ type PostArgs struct { To string `json:"to"` KeyName string `json:"keyname"` Topic whisperv5.TopicType `json:"topic"` - Padding rpc.HexBytes `json:"padding"` - Payload rpc.HexBytes `json:"payload"` + Padding hexutil.Bytes `json:"padding"` + Payload hexutil.Bytes `json:"payload"` WorkTime uint32 `json:"worktime"` PoW float64 `json:"pow"` FilterID uint32 `json:"filterID"` - PeerID rpc.HexBytes `json:"peerID"` + PeerID hexutil.Bytes `json:"peerID"` } type WhisperFilterArgs struct { diff --git a/whisper/shhapi/api_test.go b/whisper/shhapi/api_test.go index cabe1830ba..a75f0acc43 100644 --- a/whisper/shhapi/api_test.go +++ b/whisper/shhapi/api_test.go @@ -38,8 +38,8 @@ func TestBasic(t *testing.T) { t.Fatalf("failed generateFilter: %s.", err) } - if ver.Uint64() != whisperv5.ProtocolVersion { - t.Fatalf("wrong version: %d.", ver.Uint64()) + if uint64(ver) != whisperv5.ProtocolVersion { + t.Fatalf("wrong version: %d.", ver) } mail := api.GetFilterChanges(1) @@ -252,7 +252,7 @@ func TestUnmarshalPostArgs(t *testing.T) { if a.FilterID != 64 { t.Fatalf("wrong FilterID: %d.", a.FilterID) } - if bytes.Compare(a.PeerID[:], a.Topic[:]) != 0 { + if !bytes.Equal(a.PeerID[:], a.Topic[:]) { t.Fatalf("wrong PeerID: %x.", a.PeerID) } } @@ -276,6 +276,9 @@ func TestIntegrationAsym(t *testing.T) { t.Fatalf("failed to create API.") } + api.Start() + defer api.Stop() + sig, err := api.NewIdentity() if err != nil { t.Fatalf("failed NewIdentity: %s.", err) @@ -374,6 +377,9 @@ func TestIntegrationSym(t *testing.T) { t.Fatalf("failed to create API.") } + api.Start() + defer api.Stop() + keyname := "schluessel" err := api.GenerateSymKey(keyname) if err != nil { @@ -470,6 +476,9 @@ func TestIntegrationSymWithFilter(t *testing.T) { t.Fatalf("failed to create API.") } + api.Start() + defer api.Stop() + keyname := "schluessel" err := api.GenerateSymKey(keyname) if err != nil { diff --git a/whisper/whisperv2/api.go b/whisper/whisperv2/api.go index 9cdd2a507b..383f6417bb 100644 --- a/whisper/whisperv2/api.go +++ b/whisper/whisperv2/api.go @@ -23,8 +23,8 @@ import ( "time" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/common/hexutil" "github.com/ubiq/go-ubiq/crypto" - "github.com/ubiq/go-ubiq/rpc" ) // PublicWhisperAPI provides the whisper RPC service. @@ -32,7 +32,7 @@ type PublicWhisperAPI struct { w *Whisper messagesMu sync.RWMutex - messages map[int]*whisperFilter + messages map[hexutil.Uint]*whisperFilter } type whisperOfflineError struct{} @@ -46,15 +46,15 @@ var whisperOffLineErr = new(whisperOfflineError) // NewPublicWhisperAPI create a new RPC whisper service. func NewPublicWhisperAPI(w *Whisper) *PublicWhisperAPI { - return &PublicWhisperAPI{w: w, messages: make(map[int]*whisperFilter)} + return &PublicWhisperAPI{w: w, messages: make(map[hexutil.Uint]*whisperFilter)} } // Version returns the Whisper version this node offers. -func (s *PublicWhisperAPI) Version() (*rpc.HexNumber, error) { +func (s *PublicWhisperAPI) Version() (hexutil.Uint, error) { if s.w == nil { - return rpc.NewHexNumber(0), whisperOffLineErr + return 0, whisperOffLineErr } - return rpc.NewHexNumber(s.w.Version()), nil + return hexutil.Uint(s.w.Version()), nil } // HasIdentity checks if the the whisper node is configured with the private key @@ -84,12 +84,12 @@ type NewFilterArgs struct { } // NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages. -func (s *PublicWhisperAPI) NewFilter(args NewFilterArgs) (*rpc.HexNumber, error) { +func (s *PublicWhisperAPI) NewFilter(args NewFilterArgs) (hexutil.Uint, error) { if s.w == nil { - return nil, whisperOffLineErr + return 0, whisperOffLineErr } - var id int + var id hexutil.Uint filter := Filter{ To: crypto.ToECDSAPub(common.FromHex(args.To)), From: crypto.ToECDSAPub(common.FromHex(args.From)), @@ -103,23 +103,22 @@ func (s *PublicWhisperAPI) NewFilter(args NewFilterArgs) (*rpc.HexNumber, error) } }, } - - id = s.w.Watch(filter) + id = hexutil.Uint(s.w.Watch(filter)) s.messagesMu.Lock() s.messages[id] = newWhisperFilter(id, s.w) s.messagesMu.Unlock() - return rpc.NewHexNumber(id), nil + return id, nil } // GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval. -func (s *PublicWhisperAPI) GetFilterChanges(filterId rpc.HexNumber) []WhisperMessage { +func (s *PublicWhisperAPI) GetFilterChanges(filterId hexutil.Uint) []WhisperMessage { s.messagesMu.RLock() defer s.messagesMu.RUnlock() - if s.messages[filterId.Int()] != nil { - if changes := s.messages[filterId.Int()].retrieve(); changes != nil { + if s.messages[filterId] != nil { + if changes := s.messages[filterId].retrieve(); changes != nil { return changes } } @@ -127,26 +126,26 @@ func (s *PublicWhisperAPI) GetFilterChanges(filterId rpc.HexNumber) []WhisperMes } // UninstallFilter disables and removes an existing filter. -func (s *PublicWhisperAPI) UninstallFilter(filterId rpc.HexNumber) bool { +func (s *PublicWhisperAPI) UninstallFilter(filterId hexutil.Uint) bool { s.messagesMu.Lock() defer s.messagesMu.Unlock() - if _, ok := s.messages[filterId.Int()]; ok { - delete(s.messages, filterId.Int()) + if _, ok := s.messages[filterId]; ok { + delete(s.messages, filterId) return true } return false } // GetMessages retrieves all the known messages that match a specific filter. -func (s *PublicWhisperAPI) GetMessages(filterId rpc.HexNumber) []WhisperMessage { +func (s *PublicWhisperAPI) GetMessages(filterId hexutil.Uint) []WhisperMessage { // Retrieve all the cached messages matching a specific, existing filter s.messagesMu.RLock() defer s.messagesMu.RUnlock() var messages []*Message - if s.messages[filterId.Int()] != nil { - messages = s.messages[filterId.Int()].messages() + if s.messages[filterId] != nil { + messages = s.messages[filterId].messages() } return returnWhisperMessages(messages) @@ -217,12 +216,12 @@ type WhisperMessage struct { func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { var obj struct { - From string `json:"from"` - To string `json:"to"` - Topics []string `json:"topics"` - Payload string `json:"payload"` - Priority rpc.HexNumber `json:"priority"` - TTL rpc.HexNumber `json:"ttl"` + From string `json:"from"` + To string `json:"to"` + Topics []string `json:"topics"` + Payload string `json:"payload"` + Priority hexutil.Uint64 `json:"priority"` + TTL hexutil.Uint64 `json:"ttl"` } if err := json.Unmarshal(data, &obj); err != nil { @@ -232,8 +231,8 @@ func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { args.From = obj.From args.To = obj.To args.Payload = obj.Payload - args.Priority = obj.Priority.Int64() - args.TTL = obj.TTL.Int64() + args.Priority = int64(obj.Priority) // TODO(gluk256): handle overflow + args.TTL = int64(obj.TTL) // ... here too ... // decode topic strings args.Topics = make([][]byte, len(obj.Topics)) @@ -328,8 +327,8 @@ func (args *NewFilterArgs) UnmarshalJSON(b []byte) (err error) { // whisperFilter is the message cache matching a specific filter, accumulating // inbound messages until the are requested by the client. type whisperFilter struct { - id int // Filter identifier for old message retrieval - ref *Whisper // Whisper reference for old message retrieval + id hexutil.Uint // Filter identifier for old message retrieval + ref *Whisper // Whisper reference for old message retrieval cache []WhisperMessage // Cache of messages not yet polled skip map[common.Hash]struct{} // List of retrieved messages to avoid duplication @@ -348,7 +347,7 @@ func (w *whisperFilter) messages() []*Message { w.update = time.Now() w.skip = make(map[common.Hash]struct{}) - messages := w.ref.Messages(w.id) + messages := w.ref.Messages(int(w.id)) for _, message := range messages { w.skip[message.Hash] = struct{}{} } @@ -388,11 +387,10 @@ func (w *whisperFilter) activity() time.Time { } // newWhisperFilter creates a new serialized, poll based whisper topic filter. -func newWhisperFilter(id int, ref *Whisper) *whisperFilter { +func newWhisperFilter(id hexutil.Uint, ref *Whisper) *whisperFilter { return &whisperFilter{ - id: id, - ref: ref, - + id: id, + ref: ref, update: time.Now(), skip: make(map[common.Hash]struct{}), } diff --git a/whisper/whisperv2/envelope_test.go b/whisper/whisperv2/envelope_test.go index 36bb3e2ec1..2d9c527d2f 100644 --- a/whisper/whisperv2/envelope_test.go +++ b/whisper/whisperv2/envelope_test.go @@ -40,14 +40,14 @@ func TestEnvelopeOpen(t *testing.T) { if opened.Flags != message.Flags { t.Fatalf("flags mismatch: have %d, want %d", opened.Flags, message.Flags) } - if bytes.Compare(opened.Signature, message.Signature) != 0 { + if !bytes.Equal(opened.Signature, message.Signature) { t.Fatalf("signature mismatch: have 0x%x, want 0x%x", opened.Signature, message.Signature) } - if bytes.Compare(opened.Payload, message.Payload) != 0 { + if !bytes.Equal(opened.Payload, message.Payload) { t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, message.Payload) } if opened.Sent.Unix() != message.Sent.Unix() { - t.Fatalf("send time mismatch: have %d, want %d", opened.Sent, message.Sent) + t.Fatalf("send time mismatch: have %v, want %v", opened.Sent, message.Sent) } if opened.TTL/time.Second != DefaultTTL/time.Second { t.Fatalf("message TTL mismatch: have %v, want %v", opened.TTL, DefaultTTL) @@ -71,7 +71,7 @@ func TestEnvelopeAnonymousOpenUntargeted(t *testing.T) { if opened.To != nil { t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) } - if bytes.Compare(opened.Payload, payload) != 0 { + if !bytes.Equal(opened.Payload, payload) { t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, payload) } } @@ -96,7 +96,7 @@ func TestEnvelopeAnonymousOpenTargeted(t *testing.T) { if opened.To != nil { t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) } - if bytes.Compare(opened.Payload, payload) == 0 { + if bytes.Equal(opened.Payload, payload) { t.Fatalf("payload match, should have been encrypted: 0x%x", opened.Payload) } } @@ -127,7 +127,7 @@ func TestEnvelopeIdentifiedOpenUntargeted(t *testing.T) { if opened.To != nil { t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) } - if bytes.Compare(opened.Payload, payload) != 0 { + if !bytes.Equal(opened.Payload, payload) { t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, payload) } } @@ -152,7 +152,7 @@ func TestEnvelopeIdentifiedOpenTargeted(t *testing.T) { if opened.To != nil { t.Fatalf("recipient mismatch: have 0x%x, want nil", opened.To) } - if bytes.Compare(opened.Payload, payload) != 0 { + if !bytes.Equal(opened.Payload, payload) { t.Fatalf("payload mismatch: have 0x%x, want 0x%x", opened.Payload, payload) } } diff --git a/whisper/whisperv2/filter.go b/whisper/whisperv2/filter.go index 22d80c096e..1673774bd4 100644 --- a/whisper/whisperv2/filter.go +++ b/whisper/whisperv2/filter.go @@ -116,14 +116,11 @@ func (self filterer) Compare(f filter.Filter) bool { topics := make([]Topic, len(filter.matcher.conditions)) for i, group := range filter.matcher.conditions { // Message should contain a single topic entry, extract - for topics[i], _ = range group { + for topics[i] = range group { break } } - if !self.matcher.Matches(topics) { - return false - } - return true + return self.matcher.Matches(topics) } // Trigger is called when a filter successfully matches an inbound message. diff --git a/whisper/whisperv2/filter_test.go b/whisper/whisperv2/filter_test.go index 5a14a84bbd..ffdfd7b349 100644 --- a/whisper/whisperv2/filter_test.go +++ b/whisper/whisperv2/filter_test.go @@ -91,7 +91,7 @@ func TestFilterTopicsCreation(t *testing.T) { continue } for k := 0; k < len(condition); k++ { - if bytes.Compare(condition[k][:], tt.filter[j][k][:]) != 0 { + if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) } } @@ -115,7 +115,7 @@ func TestFilterTopicsCreation(t *testing.T) { continue } for k := 0; k < len(condition); k++ { - if bytes.Compare(condition[k][:], tt.filter[j][k][:]) != 0 { + if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) } } @@ -135,7 +135,7 @@ func TestFilterTopicsCreation(t *testing.T) { continue } for k := 0; k < len(condition); k++ { - if bytes.Compare(condition[k][:], tt.filter[j][k][:]) != 0 { + if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) } } @@ -156,7 +156,7 @@ func TestFilterTopicsCreation(t *testing.T) { continue } for k := 0; k < len(condition); k++ { - if bytes.Compare(condition[k][:], tt.filter[j][k][:]) != 0 { + if !bytes.Equal(condition[k][:], tt.filter[j][k][:]) { t.Errorf("test %d, condition %d, segment %d: filter mismatch: have 0x%x, want 0x%x", i, j, k, condition[k], tt.filter[j][k]) } } diff --git a/whisper/whisperv2/message_test.go b/whisper/whisperv2/message_test.go index ffff82653e..b8ca0b51d1 100644 --- a/whisper/whisperv2/message_test.go +++ b/whisper/whisperv2/message_test.go @@ -40,7 +40,7 @@ func TestMessageSimpleWrap(t *testing.T) { if len(msg.Signature) != 0 { t.Fatalf("signature found for simple wrapping: 0x%x", msg.Signature) } - if bytes.Compare(msg.Payload, payload) != 0 { + if !bytes.Equal(msg.Payload, payload) { t.Fatalf("payload mismatch after wrapping: have 0x%x, want 0x%x", msg.Payload, payload) } if msg.TTL/time.Second != DefaultTTL/time.Second { @@ -65,7 +65,7 @@ func TestMessageCleartextSignRecover(t *testing.T) { if msg.Flags&signatureFlag != signatureFlag { t.Fatalf("signature flag mismatch: have %d, want %d", msg.Flags&signatureFlag, signatureFlag) } - if bytes.Compare(msg.Payload, payload) != 0 { + if !bytes.Equal(msg.Payload, payload) { t.Fatalf("payload mismatch after signing: have 0x%x, want 0x%x", msg.Payload, payload) } diff --git a/whisper/whisperv2/peer.go b/whisper/whisperv2/peer.go index a65d6ed5b4..62c08b6f1f 100644 --- a/whisper/whisperv2/peer.go +++ b/whisper/whisperv2/peer.go @@ -149,7 +149,7 @@ func (self *peer) expire() { return true }) // Dump all known but unavailable - for hash, _ := range unmark { + for hash := range unmark { self.known.Remove(hash) } } diff --git a/whisper/whisperv2/peer_test.go b/whisper/whisperv2/peer_test.go index 4b5bba9670..d6a639cff3 100644 --- a/whisper/whisperv2/peer_test.go +++ b/whisper/whisperv2/peer_test.go @@ -221,7 +221,7 @@ func TestPeerMessageExpiration(t *testing.T) { t.Fatalf("peer pool size mismatch: have %v, want %v", peers, 1) } var peer *peer - for peer, _ = range tester.client.peers { + for peer = range tester.client.peers { break } tester.client.peerMu.RUnlock() diff --git a/whisper/whisperv2/topic_test.go b/whisper/whisperv2/topic_test.go index efd4a2c61b..bb65689963 100644 --- a/whisper/whisperv2/topic_test.go +++ b/whisper/whisperv2/topic_test.go @@ -33,13 +33,13 @@ func TestTopicCreation(t *testing.T) { // Create the topics individually for i, tt := range topicCreationTests { topic := NewTopic(tt.data) - if bytes.Compare(topic[:], tt.hash[:]) != 0 { + if !bytes.Equal(topic[:], tt.hash[:]) { t.Errorf("binary test %d: hash mismatch: have %v, want %v.", i, topic, tt.hash) } } for i, tt := range topicCreationTests { topic := NewTopicFromString(string(tt.data)) - if bytes.Compare(topic[:], tt.hash[:]) != 0 { + if !bytes.Equal(topic[:], tt.hash[:]) { t.Errorf("textual test %d: hash mismatch: have %v, want %v.", i, topic, tt.hash) } } @@ -55,13 +55,13 @@ func TestTopicCreation(t *testing.T) { topics := NewTopics(binaryData...) for i, tt := range topicCreationTests { - if bytes.Compare(topics[i][:], tt.hash[:]) != 0 { + if !bytes.Equal(topics[i][:], tt.hash[:]) { t.Errorf("binary batch test %d: hash mismatch: have %v, want %v.", i, topics[i], tt.hash) } } topics = NewTopicsFromStrings(textualData...) for i, tt := range topicCreationTests { - if bytes.Compare(topics[i][:], tt.hash[:]) != 0 { + if !bytes.Equal(topics[i][:], tt.hash[:]) { t.Errorf("textual batch test %d: hash mismatch: have %v, want %v.", i, topics[i], tt.hash) } } @@ -73,30 +73,30 @@ var topicMatcherCreationTest = struct { matcher []map[[4]byte]struct{} }{ binary: [][][]byte{ - [][]byte{}, - [][]byte{ + {}, + { []byte("Topic A"), }, - [][]byte{ + { []byte("Topic B1"), []byte("Topic B2"), []byte("Topic B3"), }, }, textual: [][]string{ - []string{}, - []string{"Topic A"}, - []string{"Topic B1", "Topic B2", "Topic B3"}, + {}, + {"Topic A"}, + {"Topic B1", "Topic B2", "Topic B3"}, }, matcher: []map[[4]byte]struct{}{ - map[[4]byte]struct{}{}, - map[[4]byte]struct{}{ - [4]byte{0x25, 0xfc, 0x95, 0x66}: struct{}{}, + {}, + { + {0x25, 0xfc, 0x95, 0x66}: {}, }, - map[[4]byte]struct{}{ - [4]byte{0x93, 0x6d, 0xec, 0x09}: struct{}{}, - [4]byte{0x25, 0x23, 0x34, 0xd3}: struct{}{}, - [4]byte{0x6b, 0xc2, 0x73, 0xd1}: struct{}{}, + { + {0x93, 0x6d, 0xec, 0x09}: {}, + {0x25, 0x23, 0x34, 0xd3}: {}, + {0x6b, 0xc2, 0x73, 0xd1}: {}, }, }, } @@ -106,14 +106,14 @@ func TestTopicMatcherCreation(t *testing.T) { matcher := newTopicMatcherFromBinary(test.binary...) for i, cond := range matcher.conditions { - for topic, _ := range cond { + for topic := range cond { if _, ok := test.matcher[i][topic]; !ok { t.Errorf("condition %d; extra topic found: 0x%x", i, topic[:]) } } } for i, cond := range test.matcher { - for topic, _ := range cond { + for topic := range cond { if _, ok := matcher.conditions[i][topic]; !ok { t.Errorf("condition %d; topic not found: 0x%x", i, topic[:]) } @@ -122,14 +122,14 @@ func TestTopicMatcherCreation(t *testing.T) { matcher = newTopicMatcherFromStrings(test.textual...) for i, cond := range matcher.conditions { - for topic, _ := range cond { + for topic := range cond { if _, ok := test.matcher[i][topic]; !ok { t.Errorf("condition %d; extra topic found: 0x%x", i, topic[:]) } } } for i, cond := range test.matcher { - for topic, _ := range cond { + for topic := range cond { if _, ok := matcher.conditions[i][topic]; !ok { t.Errorf("condition %d; topic not found: 0x%x", i, topic[:]) } @@ -155,49 +155,49 @@ var topicMatcherTests = []struct { }, // Fixed topic matcher should match strictly, but only prefix { - filter: [][]string{[]string{"a"}, []string{"b"}}, + filter: [][]string{{"a"}, {"b"}}, topics: []string{"a"}, match: false, }, { - filter: [][]string{[]string{"a"}, []string{"b"}}, + filter: [][]string{{"a"}, {"b"}}, topics: []string{"a", "b"}, match: true, }, { - filter: [][]string{[]string{"a"}, []string{"b"}}, + filter: [][]string{{"a"}, {"b"}}, topics: []string{"a", "b", "c"}, match: true, }, // Multi-matcher should match any from a sub-group { - filter: [][]string{[]string{"a1", "a2"}}, + filter: [][]string{{"a1", "a2"}}, topics: []string{"a"}, match: false, }, { - filter: [][]string{[]string{"a1", "a2"}}, + filter: [][]string{{"a1", "a2"}}, topics: []string{"a1"}, match: true, }, { - filter: [][]string{[]string{"a1", "a2"}}, + filter: [][]string{{"a1", "a2"}}, topics: []string{"a2"}, match: true, }, // Wild-card condition should match anything { - filter: [][]string{[]string{}, []string{"b"}}, + filter: [][]string{{}, {"b"}}, topics: []string{"a"}, match: false, }, { - filter: [][]string{[]string{}, []string{"b"}}, + filter: [][]string{{}, {"b"}}, topics: []string{"a", "b"}, match: true, }, { - filter: [][]string{[]string{}, []string{"b"}}, + filter: [][]string{{}, {"b"}}, topics: []string{"b", "b"}, match: true, }, diff --git a/whisper/whisperv5/doc.go b/whisper/whisperv5/doc.go index eae375ad4d..8ec81b180c 100644 --- a/whisper/whisperv5/doc.go +++ b/whisper/whisperv5/doc.go @@ -15,9 +15,7 @@ // along with the go-ethereum library. If not, see . /* -Package whisper implements the Whisper PoC-1. - -(https://github.com/ubiq/wiki/wiki/Whisper-PoC-1-Protocol-Spec) +Package whisper implements the Whisper protocol (version 5). Whisper combines aspects of both DHTs and datagram messaging systems (e.g. UDP). As such it may be likened and compared to both, not dissimilar to the @@ -42,11 +40,11 @@ const ( ProtocolVersionStr = "5.0" ProtocolName = "shh" - statusCode = 0 - messagesCode = 1 - p2pCode = 2 - mailRequestCode = 3 - NumberOfMessageCodes = 32 + statusCode = 0 // used by whisper protocol + messagesCode = 1 // normal whisper message + p2pCode = 2 // peer-to-peer message (to be consumed by the peer, but not forwarded any further) + p2pRequestCode = 3 // peer-to-peer message, used by Dapp protocol + NumberOfMessageCodes = 64 paddingMask = byte(3) signatureFlag = byte(4) @@ -57,11 +55,12 @@ const ( saltLength = 12 AESNonceMaxLength = 12 - MaxMessageLength = 0xFFFF // todo: remove this restriction after testing in morden and analizing stats. this should be regulated by MinimumPoW. - MinimumPoW = 10.0 // todo: review + MaxMessageLength = 0xFFFF // todo: remove this restriction after testing. this should be regulated by PoW. + MinimumPoW = 1.0 // todo: review after testing. padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility + messageQueueLimit = 1024 expirationCycle = time.Second transmissionCycle = 300 * time.Millisecond diff --git a/whisper/whisperv5/envelope.go b/whisper/whisperv5/envelope.go index 410df0c16e..933b26183e 100644 --- a/whisper/whisperv5/envelope.go +++ b/whisper/whisperv5/envelope.go @@ -14,14 +14,14 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Contains the Whisper protocol Envelope element. For formal details please see -// the specs at https://github.com/ubiq/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes. +// Contains the Whisper protocol Envelope element. package whisperv5 import ( "crypto/ecdsa" "encoding/binary" + "errors" "fmt" "math" "time" @@ -86,8 +86,8 @@ func (e *Envelope) Ver() uint64 { // Seal closes the envelope by spending the requested amount of time as a proof // of work on hashing the data. -func (e *Envelope) Seal(options *MessageParams) { - var target int +func (e *Envelope) Seal(options *MessageParams) error { + var target, bestBit int if options.PoW == 0 { // adjust for the duration of Seal() execution only if execution time is predefined unconditionally e.Expiry += options.WorkTime @@ -99,7 +99,7 @@ func (e *Envelope) Seal(options *MessageParams) { h := crypto.Keccak256(e.rlpWithoutNonce()) copy(buf[:32], h) - finish, bestBit := time.Now().Add(time.Duration(options.WorkTime)*time.Second).UnixNano(), 0 + finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() for nonce := uint64(0); time.Now().UnixNano() < finish; { for i := 0; i < 1024; i++ { binary.BigEndian.PutUint64(buf[56:], nonce) @@ -108,12 +108,18 @@ func (e *Envelope) Seal(options *MessageParams) { if firstBit > bestBit { e.EnvNonce, bestBit = nonce, firstBit if target > 0 && bestBit >= target { - return + return nil } } nonce++ } } + + if target > 0 && bestBit < target { + return errors.New("Failed to reach the PoW target") + } + + return nil } func (e *Envelope) PoW() float64 { diff --git a/whisper/whisperv5/filter.go b/whisper/whisperv5/filter.go index 4b4e31f29a..94276a8afa 100644 --- a/whisper/whisperv5/filter.go +++ b/whisper/whisperv5/filter.go @@ -21,6 +21,8 @@ import ( "sync" "github.com/ubiq/go-ubiq/common" + "github.com/ubiq/go-ubiq/logger" + "github.com/ubiq/go-ubiq/logger/glog" ) type Filter struct { @@ -75,21 +77,27 @@ func (fs *Filters) Get(i uint32) *Filter { return fs.watchers[i] } -func (fs *Filters) NotifyWatchers(env *Envelope, messageCode uint64) { +func (fs *Filters) NotifyWatchers(env *Envelope, p2pMessage bool) { fs.mutex.RLock() var msg *ReceivedMessage - for _, watcher := range fs.watchers { - if messageCode == p2pCode && !watcher.AcceptP2P { + for j, watcher := range fs.watchers { + if p2pMessage && !watcher.AcceptP2P { + glog.V(logger.Detail).Infof("msg [%x], filter [%d]: p2p messages are not allowed \n", env.Hash(), j) continue } - match := false + var match bool if msg != nil { match = watcher.MatchMessage(msg) } else { match = watcher.MatchEnvelope(env) if match { msg = env.Open(watcher) + if msg == nil { + glog.V(logger.Detail).Infof("msg [%x], filter [%d]: failed to open \n", env.Hash(), j) + } + } else { + glog.V(logger.Detail).Infof("msg [%x], filter [%d]: does not match \n", env.Hash(), j) } } @@ -137,12 +145,12 @@ func (f *Filter) MatchMessage(msg *ReceivedMessage) bool { if f.PoW > 0 && msg.PoW < f.PoW { return false } - if f.Src != nil && !isPubKeyEqual(msg.Src, f.Src) { + if f.Src != nil && !IsPubKeyEqual(msg.Src, f.Src) { return false } if f.expectsAsymmetricEncryption() && msg.isAsymmetricEncryption() { - return isPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic) + return IsPubKeyEqual(&f.KeyAsym.PublicKey, msg.Dst) && f.MatchTopic(msg.Topic) } else if f.expectsSymmetricEncryption() && msg.isSymmetricEncryption() { return f.SymKeyHash == msg.SymKeyHash && f.MatchTopic(msg.Topic) } @@ -176,7 +184,7 @@ func (f *Filter) MatchTopic(topic TopicType) bool { return false } -func isPubKeyEqual(a, b *ecdsa.PublicKey) bool { +func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool { if !ValidatePublicKey(a) { return false } else if !ValidatePublicKey(b) { diff --git a/whisper/whisperv5/filter_test.go b/whisper/whisperv5/filter_test.go index 2e31e052fd..42ec54eaf2 100644 --- a/whisper/whisperv5/filter_test.go +++ b/whisper/whisperv5/filter_test.go @@ -139,7 +139,7 @@ func TestComparePubKey(t *testing.T) { if err != nil { t.Fatalf("failed to generate second key with seed %d: %s.", seed, err) } - if isPubKeyEqual(&key1.PublicKey, &key2.PublicKey) { + if IsPubKeyEqual(&key1.PublicKey, &key2.PublicKey) { t.Fatalf("public keys are equal, seed %d.", seed) } @@ -149,7 +149,7 @@ func TestComparePubKey(t *testing.T) { if err != nil { t.Fatalf("failed to generate third key with seed %d: %s.", seed, err) } - if isPubKeyEqual(&key1.PublicKey, &key3.PublicKey) { + if IsPubKeyEqual(&key1.PublicKey, &key3.PublicKey) { t.Fatalf("key1 == key3, seed %d.", seed) } } @@ -540,7 +540,7 @@ func TestWatchers(t *testing.T) { } for i = 0; i < NumMessages; i++ { - filters.NotifyWatchers(envelopes[i], messagesCode) + filters.NotifyWatchers(envelopes[i], false) } var total int @@ -593,7 +593,7 @@ func TestWatchers(t *testing.T) { } for i = 0; i < NumMessages; i++ { - filters.NotifyWatchers(envelopes[i], messagesCode) + filters.NotifyWatchers(envelopes[i], false) } for i = 0; i < NumFilters; i++ { @@ -629,7 +629,7 @@ func TestWatchers(t *testing.T) { // test AcceptP2P total = 0 - filters.NotifyWatchers(envelopes[0], p2pCode) + filters.NotifyWatchers(envelopes[0], true) for i = 0; i < NumFilters; i++ { mail = tst[i].f.Retrieve() @@ -646,7 +646,7 @@ func TestWatchers(t *testing.T) { } f.AcceptP2P = true total = 0 - filters.NotifyWatchers(envelopes[0], p2pCode) + filters.NotifyWatchers(envelopes[0], true) for i = 0; i < NumFilters; i++ { mail = tst[i].f.Retrieve() diff --git a/whisper/whisperv5/message.go b/whisper/whisperv5/message.go index 197d0edbb0..4c401ba780 100644 --- a/whisper/whisperv5/message.go +++ b/whisper/whisperv5/message.go @@ -14,9 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Contains the Whisper protocol Message element. For formal details please see -// the specs at https://github.com/ubiq/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages. -// todo: fix the spec link, and move it to doc.go +// Contains the Whisper protocol Message element. package whisperv5 @@ -256,7 +254,11 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er } envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg) - envelope.Seal(options) + err = envelope.Seal(options) + if err != nil { + return nil, err + } + return envelope, nil } diff --git a/whisper/whisperv5/message_test.go b/whisper/whisperv5/message_test.go index d8e6935cd0..09af75172d 100644 --- a/whisper/whisperv5/message_test.go +++ b/whisper/whisperv5/message_test.go @@ -30,11 +30,15 @@ func copyFromBuf(dst []byte, src []byte, beg int) int { } func generateMessageParams() (*MessageParams, error) { + // set all the parameters except p.Dst + buf := make([]byte, 1024) randomize(buf) sz := rand.Intn(400) var p MessageParams + p.PoW = 0.01 + p.WorkTime = 1 p.TTL = uint32(rand.Intn(1024)) p.Payload = make([]byte, sz) p.Padding = make([]byte, padSizeLimitUpper) @@ -52,8 +56,6 @@ func generateMessageParams() (*MessageParams, error) { return nil, err } - // p.Dst, p.PoW, p.WorkTime are not set - p.PoW = 0.01 return &p, nil } @@ -75,10 +77,8 @@ func singleMessageTest(t *testing.T, symmetric bool) { text := make([]byte, 0, 512) steg := make([]byte, 0, 512) - raw := make([]byte, 0, 1024) text = append(text, params.Payload...) steg = append(steg, params.Padding...) - raw = append(raw, params.Padding...) msg := NewSentMessage(params) env, err := msg.Wrap(params) @@ -102,10 +102,10 @@ func singleMessageTest(t *testing.T, symmetric bool) { } padsz := len(decrypted.Padding) - if bytes.Compare(steg[:padsz], decrypted.Padding) != 0 { + if !bytes.Equal(steg[:padsz], decrypted.Padding) { t.Fatalf("failed with seed %d: compare padding.", seed) } - if bytes.Compare(text, decrypted.Payload) != 0 { + if !bytes.Equal(text, decrypted.Payload) { t.Fatalf("failed with seed %d: compare payload.", seed) } if !isMessageSigned(decrypted.Raw[0]) { @@ -114,7 +114,7 @@ func singleMessageTest(t *testing.T, symmetric bool) { if len(decrypted.Signature) != signatureLength { t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature)) } - if !isPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) { + if !IsPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) { t.Fatalf("failed with seed %d: signature mismatch.", seed) } } @@ -152,6 +152,16 @@ func TestMessageWrap(t *testing.T) { if pow < target { t.Fatalf("failed Wrap with seed %d: pow < target (%f vs. %f).", seed, pow, target) } + + // set PoW target too high, expect error + msg2 := NewSentMessage(params) + params.TTL = 1000000 + params.WorkTime = 1 + params.PoW = 10000000.0 + env, err = msg2.Wrap(params) + if err == nil { + t.Fatalf("unexpectedly reached the PoW target with seed %d.", seed) + } } func TestMessageSeal(t *testing.T) { @@ -226,10 +236,8 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) { text := make([]byte, 0, 512) steg := make([]byte, 0, 512) - raw := make([]byte, 0, 1024) text = append(text, params.Payload...) steg = append(steg, params.Padding...) - raw = append(raw, params.Padding...) msg := NewSentMessage(params) env, err := msg.Wrap(params) @@ -244,10 +252,10 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) { } padsz := len(decrypted.Padding) - if bytes.Compare(steg[:padsz], decrypted.Padding) != 0 { + if !bytes.Equal(steg[:padsz], decrypted.Padding) { t.Fatalf("failed with seed %d: compare padding.", seed) } - if bytes.Compare(text, decrypted.Payload) != 0 { + if !bytes.Equal(text, decrypted.Payload) { t.Fatalf("failed with seed %d: compare payload.", seed) } if !isMessageSigned(decrypted.Raw[0]) { @@ -256,7 +264,7 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) { if len(decrypted.Signature) != signatureLength { t.Fatalf("failed with seed %d: signature len %d.", seed, len(decrypted.Signature)) } - if !isPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) { + if !IsPubKeyEqual(decrypted.Src, ¶ms.Src.PublicKey) { t.Fatalf("failed with seed %d: signature mismatch.", seed) } if decrypted.isAsymmetricEncryption() == symmetric { @@ -269,8 +277,37 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) { if decrypted.Dst == nil { t.Fatalf("failed with seed %d: dst is nil.", seed) } - if !isPubKeyEqual(decrypted.Dst, &key.PublicKey) { + if !IsPubKeyEqual(decrypted.Dst, &key.PublicKey) { t.Fatalf("failed with seed %d: Dst.", seed) } } } + +func TestEncryptWithZeroKey(t *testing.T) { + InitSingleTest() + + params, err := generateMessageParams() + if err != nil { + t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) + } + + msg := NewSentMessage(params) + + params.KeySym = make([]byte, aesKeyLength) + _, err = msg.Wrap(params) + if err == nil { + t.Fatalf("wrapped with zero key, seed: %d.", seed) + } + + params.KeySym = make([]byte, 0) + _, err = msg.Wrap(params) + if err == nil { + t.Fatalf("wrapped with empty key, seed: %d.", seed) + } + + params.KeySym = nil + _, err = msg.Wrap(params) + if err == nil { + t.Fatalf("wrapped with nil key, seed: %d.", seed) + } +} diff --git a/whisper/whisperv5/peer.go b/whisper/whisperv5/peer.go index 086af1d723..98bbcfcdf3 100644 --- a/whisper/whisperv5/peer.go +++ b/whisper/whisperv5/peer.go @@ -148,7 +148,7 @@ func (peer *Peer) expire() { return true }) // Dump all known but unavailable - for hash, _ := range unmark { + for hash := range unmark { peer.known.Remove(hash) } } diff --git a/whisper/whisperv5/peer_test.go b/whisper/whisperv5/peer_test.go index 29948c8167..420cf46135 100644 --- a/whisper/whisperv5/peer_test.go +++ b/whisper/whisperv5/peer_test.go @@ -118,6 +118,7 @@ func initialize(t *testing.T) { var node TestNode node.shh = NewWhisper(nil) node.shh.test = true + node.shh.Start(nil) topics := make([]TopicType, 0) topics = append(topics, sharedTopic) f := Filter{KeySym: sharedKey, Topics: topics} @@ -166,6 +167,7 @@ func stopServers() { n := nodes[i] if n != nil { n.shh.Unwatch(n.filerId) + n.shh.Stop() n.server.Stop() } } @@ -205,7 +207,7 @@ func checkPropagation(t *testing.T) { func validateMail(t *testing.T, index int, mail []*ReceivedMessage) bool { var cnt int for _, m := range mail { - if bytes.Compare(m.Payload, expectedMessage) == 0 { + if bytes.Equal(m.Payload, expectedMessage) { cnt++ } } diff --git a/whisper/whisperv5/topic.go b/whisper/whisperv5/topic.go index a0b06a0ad4..4f327799a3 100644 --- a/whisper/whisperv5/topic.go +++ b/whisper/whisperv5/topic.go @@ -14,8 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -// Contains the Whisper protocol Topic element. For formal details please see -// the specs at https://github.com/ubiq/wiki/wiki/Whisper-PoC-1-Protocol-Spec#topics. +// Contains the Whisper protocol Topic element. package whisperv5 diff --git a/whisper/whisperv5/whisper.go b/whisper/whisperv5/whisper.go index a92a8d119d..85d3286fc5 100644 --- a/whisper/whisperv5/whisper.go +++ b/whisper/whisperv5/whisper.go @@ -22,6 +22,7 @@ import ( crand "crypto/rand" "crypto/sha256" "fmt" + "runtime" "sync" "time" @@ -45,7 +46,7 @@ type Whisper struct { symKeys map[string][]byte keyMu sync.RWMutex - envelopes map[common.Hash]*Envelope // Pool of messages currently tracked by this node + envelopes map[common.Hash]*Envelope // Pool of envelopes currently tracked by this node messages map[common.Hash]*ReceivedMessage // Pool of successfully decrypted messages, which are not expired yet expirations map[uint32]*set.SetNonTS // Message expiration pool poolMu sync.RWMutex // Mutex to sync the message and expiration pools @@ -55,22 +56,28 @@ type Whisper struct { mailServer MailServer - quit chan struct{} - test bool + messageQueue chan *Envelope + p2pMsgQueue chan *Envelope + quit chan struct{} + + overflow bool + test bool } // New creates a Whisper client ready to communicate through the Ethereum P2P network. // Param s should be passed if you want to implement mail server, otherwise nil. func NewWhisper(server MailServer) *Whisper { whisper := &Whisper{ - privateKeys: make(map[string]*ecdsa.PrivateKey), - symKeys: make(map[string][]byte), - envelopes: make(map[common.Hash]*Envelope), - messages: make(map[common.Hash]*ReceivedMessage), - expirations: make(map[uint32]*set.SetNonTS), - peers: make(map[*Peer]struct{}), - mailServer: server, - quit: make(chan struct{}), + privateKeys: make(map[string]*ecdsa.PrivateKey), + symKeys: make(map[string][]byte), + envelopes: make(map[common.Hash]*Envelope), + messages: make(map[common.Hash]*ReceivedMessage), + expirations: make(map[uint32]*set.SetNonTS), + peers: make(map[*Peer]struct{}), + mailServer: server, + messageQueue: make(chan *Envelope, messageQueueLimit), + p2pMsgQueue: make(chan *Envelope, messageQueueLimit), + quit: make(chan struct{}), } whisper.filters = NewFilters(whisper) @@ -98,7 +105,7 @@ func (w *Whisper) Version() uint { func (w *Whisper) getPeer(peerID []byte) (*Peer, error) { w.peerMu.Lock() defer w.peerMu.Unlock() - for p, _ := range w.peers { + for p := range w.peers { id := p.peer.ID() if bytes.Equal(peerID, id[:]) { return p, nil @@ -124,7 +131,7 @@ func (w *Whisper) RequestHistoricMessages(peerID []byte, data []byte) error { return err } p.trusted = true - return p2p.Send(p.ws, mailRequestCode, data) + return p2p.Send(p.ws, p2pRequestCode, data) } func (w *Whisper) SendP2PMessage(peerID []byte, envelope *Envelope) error { @@ -270,6 +277,12 @@ func (w *Whisper) Send(envelope *Envelope) error { func (w *Whisper) Start(*p2p.Server) error { glog.V(logger.Info).Infoln("Whisper started") go w.update() + + numCPU := runtime.NumCPU() + for i := 0; i < numCPU; i++ { + go w.processQueue() + } + return nil } @@ -350,10 +363,10 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error { return fmt.Errorf("garbage received (directMessage)") } for _, envelope := range envelopes { - wh.postEvent(envelope, p2pCode) + wh.postEvent(envelope, true) } } - case mailRequestCode: + case p2pRequestCode: // Must be processed if mail server is implemented. Otherwise ignore. if wh.mailServer != nil { s := rlp.NewStream(packet.Payload, uint64(packet.Size)) @@ -382,7 +395,7 @@ func (wh *Whisper) add(envelope *Envelope) error { if sent > now { if sent-SynchAllowance > now { - return fmt.Errorf("message created in the future") + return fmt.Errorf("envelope created in the future [%x]", envelope.Hash()) } else { // recalculate PoW, adjusted for the time difference, plus one second for latency envelope.calculatePoW(sent - now + 1) @@ -393,30 +406,31 @@ func (wh *Whisper) add(envelope *Envelope) error { if envelope.Expiry+SynchAllowance*2 < now { return fmt.Errorf("very old message") } else { + glog.V(logger.Debug).Infof("expired envelope dropped [%x]", envelope.Hash()) return nil // drop envelope without error } } if len(envelope.Data) > MaxMessageLength { - return fmt.Errorf("huge messages are not allowed") + return fmt.Errorf("huge messages are not allowed [%x]", envelope.Hash()) } if len(envelope.Version) > 4 { - return fmt.Errorf("oversized Version") + return fmt.Errorf("oversized version [%x]", envelope.Hash()) } if len(envelope.AESNonce) > AESNonceMaxLength { // the standard AES GSM nonce size is 12, // but const gcmStandardNonceSize cannot be accessed directly - return fmt.Errorf("oversized AESNonce") + return fmt.Errorf("oversized AESNonce [%x]", envelope.Hash()) } if len(envelope.Salt) > saltLength { - return fmt.Errorf("oversized Salt") + return fmt.Errorf("oversized salt [%x]", envelope.Hash()) } if envelope.PoW() < MinimumPoW && !wh.test { - glog.V(logger.Debug).Infof("envelope with low PoW dropped: %f", envelope.PoW()) + glog.V(logger.Debug).Infof("envelope with low PoW dropped: %f [%x]", envelope.PoW(), envelope.Hash()) return nil // drop envelope without error } @@ -436,22 +450,59 @@ func (wh *Whisper) add(envelope *Envelope) error { wh.poolMu.Unlock() if alreadyCached { - glog.V(logger.Detail).Infof("whisper envelope already cached: %x\n", envelope) + glog.V(logger.Detail).Infof("whisper envelope already cached [%x]\n", envelope.Hash()) } else { - wh.postEvent(envelope, messagesCode) // notify the local node about the new message - glog.V(logger.Detail).Infof("cached whisper envelope %v\n", envelope) + glog.V(logger.Detail).Infof("cached whisper envelope [%x]: %v\n", envelope.Hash(), envelope) + wh.postEvent(envelope, false) // notify the local node about the new message } return nil } -// postEvent delivers the message to the watchers. -func (w *Whisper) postEvent(envelope *Envelope, messageCode uint64) { +// postEvent queues the message for further processing. +func (w *Whisper) postEvent(envelope *Envelope, isP2P bool) { // if the version of incoming message is higher than // currently supported version, we can not decrypt it, // and therefore just ignore this message if envelope.Ver() <= EnvelopeVersion { - // todo: review if you need an additional thread here - go w.filters.NotifyWatchers(envelope, messageCode) + if isP2P { + w.p2pMsgQueue <- envelope + } else { + w.checkOverflow() + w.messageQueue <- envelope + } + } +} + +// checkOverflow checks if message queue overflow occurs and reports it if necessary. +func (w *Whisper) checkOverflow() { + queueSize := len(w.messageQueue) + + if queueSize == messageQueueLimit { + if !w.overflow { + w.overflow = true + glog.V(logger.Warn).Infoln("message queue overflow") + } + } else if queueSize <= messageQueueLimit/2 { + if w.overflow { + w.overflow = false + } + } +} + +// processQueue delivers the messages to the watchers during the lifetime of the whisper node. +func (w *Whisper) processQueue() { + var e *Envelope + for { + select { + case <-w.quit: + return + + case e = <-w.messageQueue: + w.filters.NotifyWatchers(e, false) + + case e = <-w.p2pMsgQueue: + w.filters.NotifyWatchers(e, true) + } } } diff --git a/whisper/whisperv5/whisper_test.go b/whisper/whisperv5/whisper_test.go index 907b78d2df..7870661a76 100644 --- a/whisper/whisperv5/whisper_test.go +++ b/whisper/whisperv5/whisper_test.go @@ -19,6 +19,7 @@ package whisperv5 import ( "bytes" "testing" + "time" "github.com/ubiq/go-ubiq/common" "github.com/ubiq/go-ubiq/crypto" @@ -49,20 +50,17 @@ func TestWhisperBasic(t *testing.T) { peerID := make([]byte, 64) randomize(peerID) - peer, err := w.getPeer(peerID) + peer, _ := w.getPeer(peerID) if peer != nil { - t.Fatalf("failed GetPeer.") + t.Fatal("found peer for random key.") } - err = w.MarkPeerTrusted(peerID) - if err == nil { + if err := w.MarkPeerTrusted(peerID); err == nil { t.Fatalf("failed MarkPeerTrusted.") } - err = w.RequestHistoricMessages(peerID, peerID) - if err == nil { + if err := w.RequestHistoricMessages(peerID, peerID); err == nil { t.Fatalf("failed RequestHistoricMessages.") } - err = w.SendP2PMessage(peerID, nil) - if err == nil { + if err := w.SendP2PMessage(peerID, nil); err == nil { t.Fatalf("failed SendP2PMessage.") } exist := w.HasSymKey("non-existing") @@ -84,11 +82,10 @@ func TestWhisperBasic(t *testing.T) { var derived []byte ver := uint64(0xDEADBEEF) - derived, err = deriveKeyMaterial(peerID, ver) - if err != unknownVersionError(ver) { + if _, err := deriveKeyMaterial(peerID, ver); err != unknownVersionError(ver) { t.Fatalf("failed deriveKeyMaterial with param = %v: %s.", peerID, err) } - derived, err = deriveKeyMaterial(peerID, 0) + derived, err := deriveKeyMaterial(peerID, 0) if err != nil { t.Fatalf("failed second deriveKeyMaterial with param = %v: %s.", peerID, err) } @@ -238,7 +235,7 @@ func TestWhisperSymKeyManagement(t *testing.T) { if k1 == nil { t.Fatalf("first key does not exist.") } - if bytes.Compare(k1, randomKey) == 0 { + if bytes.Equal(k1, randomKey) { t.Fatalf("k1 == randomKey.") } if k2 != nil { @@ -263,10 +260,10 @@ func TestWhisperSymKeyManagement(t *testing.T) { if k2 == nil { t.Fatalf("k2 does not exist.") } - if bytes.Compare(k1, k2) == 0 { + if bytes.Equal(k1, k2) { t.Fatalf("k1 == k2.") } - if bytes.Compare(k1, randomKey) == 0 { + if bytes.Equal(k1, randomKey) { t.Fatalf("k1 == randomKey.") } if len(k1) != aesKeyLength { @@ -309,3 +306,56 @@ func TestWhisperSymKeyManagement(t *testing.T) { t.Fatalf("failed to delete second key: second key is not nil.") } } + +func TestExpiry(t *testing.T) { + InitSingleTest() + + w := NewWhisper(nil) + w.test = true + w.Start(nil) + defer w.Stop() + + params, err := generateMessageParams() + if err != nil { + t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err) + } + + params.TTL = 1 + msg := NewSentMessage(params) + env, err := msg.Wrap(params) + if err != nil { + t.Fatalf("failed Wrap with seed %d: %s.", seed, err) + } + + err = w.Send(env) + if err != nil { + t.Fatalf("failed to send envelope with seed %d: %s.", seed, err) + } + + // wait till received or timeout + var received, expired bool + for j := 0; j < 20; j++ { + time.Sleep(100 * time.Millisecond) + if len(w.Envelopes()) > 0 { + received = true + break + } + } + + if !received { + t.Fatalf("did not receive the sent envelope, seed: %d.", seed) + } + + // wait till expired or timeout + for j := 0; j < 20; j++ { + time.Sleep(100 * time.Millisecond) + if len(w.Envelopes()) == 0 { + expired = true + break + } + } + + if !expired { + t.Fatalf("expire failed, seed: %d.", seed) + } +}