Merge branch 'master' into localstore

This commit is contained in:
Janos Guljas 2019-01-07 12:36:38 +01:00
commit c1882818ab
183 changed files with 6663 additions and 1909 deletions

View file

@ -156,7 +156,7 @@ matrix:
git: git:
submodules: false # avoid cloning ethereum/tests submodules: false # avoid cloning ethereum/tests
before_install: before_install:
- curl https://storage.googleapis.com/golang/go1.11.2.linux-amd64.tar.gz | tar -xz - curl https://storage.googleapis.com/golang/go1.11.4.linux-amd64.tar.gz | tar -xz
- export PATH=`pwd`/go/bin:$PATH - export PATH=`pwd`/go/bin:$PATH
- export GOROOT=`pwd`/go - export GOROOT=`pwd`/go
- export GOPATH=$HOME/go - export GOPATH=$HOME/go

View file

@ -82,7 +82,7 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) {
// we need to decide whether we're calling a method or an event // we need to decide whether we're calling a method or an event
if method, ok := abi.Methods[name]; ok { if method, ok := abi.Methods[name]; ok {
if len(output)%32 != 0 { if len(output)%32 != 0 {
return fmt.Errorf("abi: improperly formatted output") return fmt.Errorf("abi: improperly formatted output: %s - Bytes: [%+v]", string(output), output)
} }
return method.Outputs.Unpack(v, output) return method.Outputs.Unpack(v, output)
} else if event, ok := abi.Events[name]; ok { } else if event, ok := abi.Events[name]; ok {

View file

@ -202,7 +202,7 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
virtualArgs := 0 virtualArgs := 0
for index, arg := range arguments.NonIndexed() { for index, arg := range arguments.NonIndexed() {
marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data)
if arg.Type.T == ArrayTy { if arg.Type.T == ArrayTy && (*arg.Type.Elem).T != StringTy {
// If we have a static array, like [3]uint256, these are coded as // If we have a static array, like [3]uint256, these are coded as
// just like uint256,uint256,uint256. // just like uint256,uint256,uint256.
// This means that we need to add two 'virtual' arguments when // This means that we need to add two 'virtual' arguments when
@ -272,14 +272,13 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
return ret, nil return ret, nil
} }
// capitalise makes the first character of a string upper case, also removing any // ToCamelCase converts an under-score string to a camel-case string
// prefixing underscores from the variable names. func ToCamelCase(input string) string {
func capitalise(input string) string { parts := strings.Split(input, "_")
for len(input) > 0 && input[0] == '_' { for i, s := range parts {
input = input[1:] if len(s) > 0 {
parts[i] = strings.ToUpper(s[:1]) + s[1:]
} }
if len(input) == 0 {
return ""
} }
return strings.ToUpper(input[:1]) + input[1:] return strings.Join(parts, "")
} }

View file

@ -38,7 +38,7 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra
type CallOpts struct { type CallOpts struct {
Pending bool // Whether to operate on the pending state or the last known one Pending bool // Whether to operate on the pending state or the last known one
From common.Address // Optional the sender address, otherwise the first account is used From common.Address // Optional the sender address, otherwise the first account is used
BlockNumber *big.Int // Optional the block number on which the call should be performed
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
} }
@ -148,10 +148,10 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
} }
} }
} else { } else {
output, err = c.caller.CallContract(ctx, msg, nil) output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber)
if err == nil && len(output) == 0 { if err == nil && len(output) == 0 {
// Make sure we have a contract to operate on, and bail out otherwise. // Make sure we have a contract to operate on, and bail out otherwise.
if code, err = c.caller.CodeAt(ctx, c.address, nil); err != nil { if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil {
return err return err
} else if len(code) == 0 { } else if len(code) == 0 {
return ErrNoCode return ErrNoCode

View file

@ -0,0 +1,64 @@
package bind_test
import (
"context"
"math/big"
"testing"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)
type mockCaller struct {
codeAtBlockNumber *big.Int
callContractBlockNumber *big.Int
}
func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
mc.codeAtBlockNumber = blockNumber
return []byte{1, 2, 3}, nil
}
func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
mc.callContractBlockNumber = blockNumber
return nil, nil
}
func TestPassingBlockNumber(t *testing.T) {
mc := &mockCaller{}
bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{
Methods: map[string]abi.Method{
"something": {
Name: "something",
Outputs: abi.Arguments{},
},
},
}, mc, nil, nil)
var ret string
blockNumber := big.NewInt(42)
bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something")
if mc.callContractBlockNumber != blockNumber {
t.Fatalf("CallContract() was not passed the block number")
}
if mc.codeAtBlockNumber != blockNumber {
t.Fatalf("CodeAt() was not passed the block number")
}
bc.Call(&bind.CallOpts{}, &ret, "something")
if mc.callContractBlockNumber != nil {
t.Fatalf("CallContract() was passed a block number when it should not have been")
}
if mc.codeAtBlockNumber != nil {
t.Fatalf("CodeAt() was passed a block number when it should not have been")
}
}

View file

@ -381,54 +381,23 @@ func namedTypeJava(javaKind string, solKind abi.Type) string {
// methodNormalizer is a name transformer that modifies Solidity method names to // methodNormalizer is a name transformer that modifies Solidity method names to
// conform to target language naming concentions. // conform to target language naming concentions.
var methodNormalizer = map[Lang]func(string) string{ var methodNormalizer = map[Lang]func(string) string{
LangGo: capitalise, LangGo: abi.ToCamelCase,
LangJava: decapitalise, LangJava: decapitalise,
} }
// capitalise makes a camel-case string which starts with an upper case character. // capitalise makes a camel-case string which starts with an upper case character.
func capitalise(input string) string { func capitalise(input string) string {
for len(input) > 0 && input[0] == '_' { return abi.ToCamelCase(input)
input = input[1:]
}
if len(input) == 0 {
return ""
}
return toCamelCase(strings.ToUpper(input[:1]) + input[1:])
} }
// decapitalise makes a camel-case string which starts with a lower case character. // decapitalise makes a camel-case string which starts with a lower case character.
func decapitalise(input string) string { func decapitalise(input string) string {
for len(input) > 0 && input[0] == '_' {
input = input[1:]
}
if len(input) == 0 { if len(input) == 0 {
return "" return input
} }
return toCamelCase(strings.ToLower(input[:1]) + input[1:])
}
// toCamelCase converts an under-score string to a camel-case string goForm := abi.ToCamelCase(input)
func toCamelCase(input string) string { return strings.ToLower(goForm[:1]) + goForm[1:]
toupper := false
result := ""
for k, v := range input {
switch {
case k == 0:
result = strings.ToUpper(string(input[0]))
case toupper:
result += strings.ToUpper(string(v))
toupper = false
case v == '_':
toupper = true
default:
result += string(v)
}
}
return result
} }
// structured checks whether a list of ABI data types has enough information to // structured checks whether a list of ABI data types has enough information to

View file

@ -77,6 +77,8 @@ func set(dst, src reflect.Value, output Argument) error {
switch { switch {
case dstType.AssignableTo(srcType): case dstType.AssignableTo(srcType):
dst.Set(src) dst.Set(src)
case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice:
return setSlice(dst, src, output)
case dstType.Kind() == reflect.Interface: case dstType.Kind() == reflect.Interface:
dst.Set(src) dst.Set(src)
case dstType.Kind() == reflect.Ptr: case dstType.Kind() == reflect.Ptr:
@ -87,6 +89,19 @@ func set(dst, src reflect.Value, output Argument) error {
return nil return nil
} }
// setSlice attempts to assign src to dst when slices are not assignable by default
// e.g. src: [][]byte -> dst: [][15]byte
func setSlice(dst, src reflect.Value, output Argument) error {
slice := reflect.MakeSlice(dst.Type(), src.Len(), src.Len())
for i := 0; i < src.Len(); i++ {
v := src.Index(i)
reflect.Copy(slice.Index(i), v)
}
dst.Set(slice)
return nil
}
// requireAssignable assures that `dest` is a pointer and it's not an interface. // requireAssignable assures that `dest` is a pointer and it's not an interface.
func requireAssignable(dst, src reflect.Value) error { func requireAssignable(dst, src reflect.Value) error {
if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface { if dst.Kind() != reflect.Ptr && dst.Kind() != reflect.Interface {
@ -171,7 +186,7 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
for _, arg := range args { for _, arg := range args {
abiFieldName := arg.Name abiFieldName := arg.Name
structFieldName := capitalise(abiFieldName) structFieldName := ToCamelCase(abiFieldName)
if structFieldName == "" { if structFieldName == "" {
return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct")

View file

@ -195,8 +195,15 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
switch t.T { switch t.T {
case SliceTy: case SliceTy:
if (*t.Elem).T == StringTy {
return forEachUnpack(t, output[begin:], 0, end)
}
return forEachUnpack(t, output, begin, end) return forEachUnpack(t, output, begin, end)
case ArrayTy: case ArrayTy:
if (*t.Elem).T == StringTy {
offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:]))
return forEachUnpack(t, output[offset:], 0, t.Size)
}
return forEachUnpack(t, output, index, t.Size) return forEachUnpack(t, output, index, t.Size)
case StringTy: // variable arrays are written at the end of the return bytes case StringTy: // variable arrays are written at the end of the return bytes
return string(output[begin : begin+end]), nil return string(output[begin : begin+end]), nil

View file

@ -241,6 +241,16 @@ var unpackTests = []unpackTest{
enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
}, },
{
def: `[{"type": "string[4]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b476f2d657468657265756d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000",
want: [4]string{"Hello", "World", "Go-ethereum", "Ethereum"},
},
{
def: `[{"type": "string[]"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b676f2d657468657265756d000000000000000000000000000000000000000000",
want: []string{"Ethereum", "go-ethereum"},
},
{ {
def: `[{"type": "int8[]"}]`, def: `[{"type": "int8[]"}]`,
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
@ -300,6 +310,53 @@ var unpackTests = []unpackTest{
Int2 *big.Int Int2 *big.Int
}{big.NewInt(1), big.NewInt(2)}, }{big.NewInt(1), big.NewInt(2)},
}, },
{
def: `[{"name":"int_one","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
}{big.NewInt(1)},
},
{
def: `[{"name":"int__one","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
}{big.NewInt(1)},
},
{
def: `[{"name":"int_one_","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
}{big.NewInt(1)},
},
{
def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
Intone *big.Int
}{big.NewInt(1), big.NewInt(2)},
},
{
def: `[{"name":"___","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
Intone *big.Int
}{},
err: "abi: purely underscored output cannot unpack to struct",
},
{
def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
Int2 *big.Int
}{},
err: "abi: multiple outputs mapping to the same struct field 'IntOne'",
},
{ {
def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`, def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
@ -364,6 +421,55 @@ func TestUnpack(t *testing.T) {
} }
} }
func TestUnpackSetDynamicArrayOutput(t *testing.T) {
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
if err != nil {
t.Fatal(err)
}
var (
marshalledReturn32 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783132333435363738393000000000000000000000000000000000000000003078303938373635343332310000000000000000000000000000000000000000")
marshalledReturn15 = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000230783031323334350000000000000000000000000000000000000000000000003078393837363534000000000000000000000000000000000000000000000000")
out32 [][32]byte
out15 [][15]byte
)
// test 32
err = abi.Unpack(&out32, "testDynamicFixedBytes32", marshalledReturn32)
if err != nil {
t.Fatal(err)
}
if len(out32) != 2 {
t.Fatalf("expected array with 2 values, got %d", len(out32))
}
expected := common.Hex2Bytes("3078313233343536373839300000000000000000000000000000000000000000")
if !bytes.Equal(out32[0][:], expected) {
t.Errorf("expected %x, got %x\n", expected, out32[0])
}
expected = common.Hex2Bytes("3078303938373635343332310000000000000000000000000000000000000000")
if !bytes.Equal(out32[1][:], expected) {
t.Errorf("expected %x, got %x\n", expected, out32[1])
}
// test 15
err = abi.Unpack(&out15, "testDynamicFixedBytes32", marshalledReturn15)
if err != nil {
t.Fatal(err)
}
if len(out15) != 2 {
t.Fatalf("expected array with 2 values, got %d", len(out15))
}
expected = common.Hex2Bytes("307830313233343500000000000000")
if !bytes.Equal(out15[0][:], expected) {
t.Errorf("expected %x, got %x\n", expected, out15[0])
}
expected = common.Hex2Bytes("307839383736353400000000000000")
if !bytes.Equal(out15[1][:], expected) {
t.Errorf("expected %x, got %x\n", expected, out15[1])
}
}
type methodMultiOutput struct { type methodMultiOutput struct {
Int *big.Int Int *big.Int
String string String string
@ -467,6 +573,57 @@ func TestMultiReturnWithArray(t *testing.T) {
} }
} }
func TestMultiReturnWithStringArray(t *testing.T) {
const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]`
abi, err := JSON(strings.NewReader(definition))
if err != nil {
t.Fatal(err)
}
buff := new(bytes.Buffer)
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000005c1b78ea0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000ab1257528b3782fb40d7ed5f72e624b744dffb2f00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001048656c6c6f2c20457468657265756d2100000000000000000000000000000000"))
temp, _ := big.NewInt(0).SetString("30000000000000000000", 10)
ret1, ret1Exp := new([3]*big.Int), [3]*big.Int{big.NewInt(1545304298), big.NewInt(6), temp}
ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f")
ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"}
ret4, ret4Exp := new(bool), false
if err := abi.Unpack(&[]interface{}{ret1, ret2, ret3, ret4}, "multi", buff.Bytes()); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(*ret1, ret1Exp) {
t.Error("big.Int array result", *ret1, "!= Expected", ret1Exp)
}
if !reflect.DeepEqual(*ret2, ret2Exp) {
t.Error("address result", *ret2, "!= Expected", ret2Exp)
}
if !reflect.DeepEqual(*ret3, ret3Exp) {
t.Error("string array result", *ret3, "!= Expected", ret3Exp)
}
if !reflect.DeepEqual(*ret4, ret4Exp) {
t.Error("bool result", *ret4, "!= Expected", ret4Exp)
}
}
func TestMultiReturnWithStringSlice(t *testing.T) {
const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]`
abi, err := JSON(strings.NewReader(definition))
if err != nil {
t.Fatal(err)
}
buff := new(bytes.Buffer)
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008657468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b676f2d657468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000065"))
ret1, ret1Exp := new([]string), []string{"ethereum", "go-ethereum"}
ret2, ret2Exp := new([]*big.Int), []*big.Int{big.NewInt(100), big.NewInt(101)}
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(*ret1, ret1Exp) {
t.Error("string slice result", *ret1, "!= Expected", ret1Exp)
}
if !reflect.DeepEqual(*ret2, ret2Exp) {
t.Error("uint256 slice result", *ret2, "!= Expected", ret2Exp)
}
}
func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
// Similar to TestMultiReturnWithArray, but with a special case in mind: // Similar to TestMultiReturnWithArray, but with a special case in mind:
// values of nested static arrays count towards the size as well, and any element following // values of nested static arrays count towards the size as well, and any element following

View file

@ -52,8 +52,8 @@ func (w *keystoreWallet) Status() (string, error) {
// is no connection or decryption step necessary to access the list of accounts. // is no connection or decryption step necessary to access the list of accounts.
func (w *keystoreWallet) Open(passphrase string) error { return nil } func (w *keystoreWallet) Open(passphrase string) error { return nil }
// Close implements accounts.Wallet, but is a noop for plain wallets since is no // Close implements accounts.Wallet, but is a noop for plain wallets since there
// meaningful open operation. // is no meaningful open operation.
func (w *keystoreWallet) Close() error { return nil } func (w *keystoreWallet) Close() error { return nil }
// Accounts implements accounts.Wallet, returning an account list consisting of // Accounts implements accounts.Wallet, returning an account list consisting of

View file

@ -23,8 +23,8 @@ environment:
install: install:
- git submodule update --init - git submodule update --init
- rmdir C:\go /s /q - rmdir C:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.2.windows-%GETH_ARCH%.zip - appveyor DownloadFile https://storage.googleapis.com/golang/go1.11.4.windows-%GETH_ARCH%.zip
- 7z x go1.11.2.windows-%GETH_ARCH%.zip -y -oC:\ > NUL - 7z x go1.11.4.windows-%GETH_ARCH%.zip -y -oC:\ > NUL
- go version - go version
- gcc --version - gcc --version

View file

@ -1,3 +1,19 @@
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build none // +build none
/* /*

View file

@ -174,7 +174,11 @@ func (spec *alethGenesisSpec) setPrecompile(address byte, data *alethGenesisSpec
if spec.Accounts == nil { if spec.Accounts == nil {
spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount) spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount)
} }
spec.Accounts[common.UnprefixedAddress(common.BytesToAddress([]byte{address}))].Precompiled = data addr := common.UnprefixedAddress(common.BytesToAddress([]byte{address}))
if _, exist := spec.Accounts[addr]; !exist {
spec.Accounts[addr] = &alethGenesisSpecAccount{}
}
spec.Accounts[addr].Precompiled = data
} }
func (spec *alethGenesisSpec) setAccount(address common.Address, account core.GenesisAccount) { func (spec *alethGenesisSpec) setAccount(address common.Address, account core.GenesisAccount) {

View file

@ -33,11 +33,11 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
swarmapi "github.com/ethereum/go-ethereum/swarm/api/client" swarmapi "github.com/ethereum/go-ethereum/swarm/api/client"
"github.com/ethereum/go-ethereum/swarm/testutil" "github.com/ethereum/go-ethereum/swarm/testutil"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -598,7 +598,7 @@ func TestKeypairSanity(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
hasher.Write(salt) hasher.Write(salt)
shared, err := hex.DecodeString(sharedSecret) shared, err := hex.DecodeString(sharedSecret)
if err != nil { if err != nil {

View file

@ -164,10 +164,6 @@ var (
Name: "topic", Name: "topic",
Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters", Usage: "User-defined topic this feed is tracking, hex encoded. Limited to 64 hexadecimal characters",
} }
SwarmFeedDataOnCreateFlag = cli.StringFlag{
Name: "data",
Usage: "Initializes the feed with the given hex-encoded data. Data must be prefixed by 0x",
}
SwarmFeedManifestFlag = cli.StringFlag{ SwarmFeedManifestFlag = cli.StringFlag{
Name: "manifest", Name: "manifest",
Usage: "Refers to the feed through a manifest", Usage: "Refers to the feed through a manifest",

View file

@ -27,7 +27,7 @@ import (
"strings" "strings"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto/sha3" "golang.org/x/crypto/sha3"
) )
// Lengths of hashes and addresses in bytes. // Lengths of hashes and addresses in bytes.
@ -196,7 +196,7 @@ func (a Address) Hash() Hash { return BytesToHash(a[:]) }
// Hex returns an EIP55-compliant hex string representation of the address. // Hex returns an EIP55-compliant hex string representation of the address.
func (a Address) Hex() string { func (a Address) Hex() string {
unchecksummed := hex.EncodeToString(a[:]) unchecksummed := hex.EncodeToString(a[:])
sha := sha3.NewKeccak256() sha := sha3.NewLegacyKeccak256()
sha.Write([]byte(unchecksummed)) sha.Write([]byte(unchecksummed))
hash := sha.Sum(nil) hash := sha.Sum(nil)

View file

@ -33,13 +33,13 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -148,7 +148,7 @@ type SignerFn func(accounts.Account, []byte) ([]byte, error)
// panics. This is done to avoid accidentally using both forms (signature present // panics. This is done to avoid accidentally using both forms (signature present
// or not), which could be abused to produce different hashes for the same header. // or not), which could be abused to produce different hashes for the same header.
func sigHash(header *types.Header) (hash common.Hash) { func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
rlp.Encode(hasher, []interface{}{ rlp.Encode(hasher, []interface{}{
header.ParentHash, header.ParentHash,

View file

@ -30,8 +30,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/bitutil" "github.com/ethereum/go-ethereum/common/bitutil"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -123,7 +123,7 @@ func seedHash(block uint64) []byte {
if block < epochLength { if block < epochLength {
return seed return seed
} }
keccak256 := makeHasher(sha3.NewKeccak256()) keccak256 := makeHasher(sha3.NewLegacyKeccak256())
for i := 0; i < int(block/epochLength); i++ { for i := 0; i < int(block/epochLength); i++ {
keccak256(seed, seed) keccak256(seed, seed)
} }
@ -177,7 +177,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) {
} }
}() }()
// Create a hasher to reuse between invocations // Create a hasher to reuse between invocations
keccak512 := makeHasher(sha3.NewKeccak512()) keccak512 := makeHasher(sha3.NewLegacyKeccak512())
// Sequentially produce the initial dataset // Sequentially produce the initial dataset
keccak512(cache, seed) keccak512(cache, seed)
@ -301,7 +301,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
defer pend.Done() defer pend.Done()
// Create a hasher to reuse between invocations // Create a hasher to reuse between invocations
keccak512 := makeHasher(sha3.NewKeccak512()) keccak512 := makeHasher(sha3.NewLegacyKeccak512())
// Calculate the data segment this thread should generate // Calculate the data segment this thread should generate
batch := uint32((size + hashBytes*uint64(threads) - 1) / (hashBytes * uint64(threads))) batch := uint32((size + hashBytes*uint64(threads) - 1) / (hashBytes * uint64(threads)))
@ -375,7 +375,7 @@ func hashimoto(hash []byte, nonce uint64, size uint64, lookup func(index uint32)
// in-memory cache) in order to produce our final value for a particular header // in-memory cache) in order to produce our final value for a particular header
// hash and nonce. // hash and nonce.
func hashimotoLight(size uint64, cache []uint32, hash []byte, nonce uint64) ([]byte, []byte) { func hashimotoLight(size uint64, cache []uint32, hash []byte, nonce uint64) ([]byte, []byte) {
keccak512 := makeHasher(sha3.NewKeccak512()) keccak512 := makeHasher(sha3.NewLegacyKeccak512())
lookup := func(index uint32) []uint32 { lookup := func(index uint32) []uint32 {
rawData := generateDatasetItem(cache, index, keccak512) rawData := generateDatasetItem(cache, index, keccak512)

View file

@ -31,9 +31,9 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
) )
// Ethash proof-of-work protocol constants. // Ethash proof-of-work protocol constants.
@ -575,7 +575,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header
// SealHash returns the hash of a block prior to it being sealed. // SealHash returns the hash of a block prior to it being sealed.
func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
rlp.Encode(hasher, []interface{}{ rlp.Encode(hasher, []interface{}{
header.ParentHash, header.ParentHash,

View file

@ -23,9 +23,9 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
) )
// Tests block header storage and retrieval operations. // Tests block header storage and retrieval operations.
@ -47,7 +47,7 @@ func TestHeaderStorage(t *testing.T) {
if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil { if entry := ReadHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
t.Fatalf("Stored header RLP not found") t.Fatalf("Stored header RLP not found")
} else { } else {
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
hasher.Write(entry) hasher.Write(entry)
if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() { if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() {
@ -68,7 +68,7 @@ func TestBodyStorage(t *testing.T) {
// Create a test body to move around the database and make sure it's really new // Create a test body to move around the database and make sure it's really new
body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}} body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}}
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
rlp.Encode(hasher, body) rlp.Encode(hasher, body)
hash := common.BytesToHash(hasher.Sum(nil)) hash := common.BytesToHash(hasher.Sum(nil))
@ -85,7 +85,7 @@ func TestBodyStorage(t *testing.T) {
if entry := ReadBodyRLP(db, hash, 0); entry == nil { if entry := ReadBodyRLP(db, hash, 0); entry == nil {
t.Fatalf("Stored body RLP not found") t.Fatalf("Stored body RLP not found")
} else { } else {
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
hasher.Write(entry) hasher.Write(entry)
if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash { if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash {

View file

@ -172,6 +172,26 @@ func (config *TxPoolConfig) sanitize() TxPoolConfig {
log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump) log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump)
conf.PriceBump = DefaultTxPoolConfig.PriceBump conf.PriceBump = DefaultTxPoolConfig.PriceBump
} }
if conf.AccountSlots < 1 {
log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultTxPoolConfig.AccountSlots)
conf.AccountSlots = DefaultTxPoolConfig.AccountSlots
}
if conf.GlobalSlots < 1 {
log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultTxPoolConfig.GlobalSlots)
conf.GlobalSlots = DefaultTxPoolConfig.GlobalSlots
}
if conf.AccountQueue < 1 {
log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultTxPoolConfig.AccountQueue)
conf.AccountQueue = DefaultTxPoolConfig.AccountQueue
}
if conf.GlobalQueue < 1 {
log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultTxPoolConfig.GlobalQueue)
conf.GlobalQueue = DefaultTxPoolConfig.GlobalQueue
}
if conf.Lifetime < 1 {
log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime)
conf.Lifetime = DefaultTxPoolConfig.Lifetime
}
return conf return conf
} }

View file

@ -1095,7 +1095,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig config := testTxPoolConfig
config.GlobalSlots = 0 config.GlobalSlots = 1
pool := NewTxPool(config, params.TestChainConfig, blockchain) pool := NewTxPool(config, params.TestChainConfig, blockchain)
defer pool.Stop() defer pool.Stop()

View file

@ -28,8 +28,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
) )
var ( var (
@ -109,7 +109,7 @@ func (h *Header) Size() common.StorageSize {
} }
func rlpHash(x interface{}) (h common.Hash) { func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256() hw := sha3.NewLegacyKeccak256()
rlp.Encode(hw, x) rlp.Encode(hw, x)
hw.Sum(h[:0]) hw.Sum(h[:0])
return h return h

View file

@ -234,7 +234,7 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
} }
// WithSignature returns a new transaction with the given signature. // WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27). // This signature needs to be in the [R || S || V] format where V is 0 or 1.
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) { func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
r, s, v, err := signer.SignatureValues(tx, sig) r, s, v, err := signer.SignatureValues(tx, sig)
if err != nil { if err != nil {

View file

@ -24,8 +24,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"golang.org/x/crypto/sha3"
) )
var ( var (
@ -387,7 +387,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
data := memory.Get(offset.Int64(), size.Int64()) data := memory.Get(offset.Int64(), size.Int64())
if interpreter.hasher == nil { if interpreter.hasher == nil {
interpreter.hasher = sha3.NewKeccak256().(keccakState) interpreter.hasher = sha3.NewLegacyKeccak256().(keccakState)
} else { } else {
interpreter.hasher.Reset() interpreter.hasher.Reset()
} }

View file

@ -30,8 +30,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
) )
var ( var (
@ -43,7 +43,7 @@ var errInvalidPubkey = errors.New("invalid secp256k1 public key")
// Keccak256 calculates and returns the Keccak256 hash of the input data. // Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte { func Keccak256(data ...[]byte) []byte {
d := sha3.NewKeccak256() d := sha3.NewLegacyKeccak256()
for _, b := range data { for _, b := range data {
d.Write(b) d.Write(b)
} }
@ -53,7 +53,7 @@ func Keccak256(data ...[]byte) []byte {
// Keccak256Hash calculates and returns the Keccak256 hash of the input data, // Keccak256Hash calculates and returns the Keccak256 hash of the input data,
// converting it to an internal Hash data structure. // converting it to an internal Hash data structure.
func Keccak256Hash(data ...[]byte) (h common.Hash) { func Keccak256Hash(data ...[]byte) (h common.Hash) {
d := sha3.NewKeccak256() d := sha3.NewLegacyKeccak256()
for _, b := range data { for _, b := range data {
d.Write(b) d.Write(b)
} }
@ -63,7 +63,7 @@ func Keccak256Hash(data ...[]byte) (h common.Hash) {
// Keccak512 calculates and returns the Keccak512 hash of the input data. // Keccak512 calculates and returns the Keccak512 hash of the input data.
func Keccak512(data ...[]byte) []byte { func Keccak512(data ...[]byte) []byte {
d := sha3.NewKeccak512() d := sha3.NewLegacyKeccak512()
for _, b := range data { for _, b := range data {
d.Write(b) d.Write(b)
} }

View file

@ -1,27 +0,0 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,22 +0,0 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google 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,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

View file

@ -1,297 +0,0 @@
// Copyright 2014 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.
package sha3
// Tests include all the ShortMsgKATs provided by the Keccak team at
// https://github.com/gvanas/KeccakCodePackage
//
// They only include the zero-bit case of the bitwise testvectors
// published by NIST in the draft of FIPS-202.
import (
"bytes"
"compress/flate"
"encoding/hex"
"encoding/json"
"hash"
"os"
"strings"
"testing"
)
const (
testString = "brekeccakkeccak koax koax"
katFilename = "testdata/keccakKats.json.deflate"
)
// Internal-use instances of SHAKE used to test against KATs.
func newHashShake128() hash.Hash {
return &state{rate: 168, dsbyte: 0x1f, outputLen: 512}
}
func newHashShake256() hash.Hash {
return &state{rate: 136, dsbyte: 0x1f, outputLen: 512}
}
// testDigests contains functions returning hash.Hash instances
// with output-length equal to the KAT length for both SHA-3 and
// SHAKE instances.
var testDigests = map[string]func() hash.Hash{
"SHA3-224": New224,
"SHA3-256": New256,
"SHA3-384": New384,
"SHA3-512": New512,
"SHAKE128": newHashShake128,
"SHAKE256": newHashShake256,
}
// testShakes contains functions that return ShakeHash instances for
// testing the ShakeHash-specific interface.
var testShakes = map[string]func() ShakeHash{
"SHAKE128": NewShake128,
"SHAKE256": NewShake256,
}
// structs used to marshal JSON test-cases.
type KeccakKats struct {
Kats map[string][]struct {
Digest string `json:"digest"`
Length int64 `json:"length"`
Message string `json:"message"`
}
}
func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
xorInOrig, copyOutOrig := xorIn, copyOut
xorIn, copyOut = xorInGeneric, copyOutGeneric
testf("generic")
if xorImplementationUnaligned != "generic" {
xorIn, copyOut = xorInUnaligned, copyOutUnaligned
testf("unaligned")
}
xorIn, copyOut = xorInOrig, copyOutOrig
}
// TestKeccakKats tests the SHA-3 and Shake implementations against all the
// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
// (The testvectors are stored in keccakKats.json.deflate due to their length.)
func TestKeccakKats(t *testing.T) {
testUnalignedAndGeneric(t, func(impl string) {
// Read the KATs.
deflated, err := os.Open(katFilename)
if err != nil {
t.Errorf("error opening %s: %s", katFilename, err)
}
file := flate.NewReader(deflated)
dec := json.NewDecoder(file)
var katSet KeccakKats
err = dec.Decode(&katSet)
if err != nil {
t.Errorf("error decoding KATs: %s", err)
}
// Do the KATs.
for functionName, kats := range katSet.Kats {
d := testDigests[functionName]()
for _, kat := range kats {
d.Reset()
in, err := hex.DecodeString(kat.Message)
if err != nil {
t.Errorf("error decoding KAT: %s", err)
}
d.Write(in[:kat.Length/8])
got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
if got != kat.Digest {
t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
functionName, impl, kat.Length, kat.Message, got, kat.Digest)
t.Logf("wanted %+v", kat)
t.FailNow()
}
continue
}
}
})
}
// TestUnalignedWrite tests that writing data in an arbitrary pattern with
// small input buffers.
func TestUnalignedWrite(t *testing.T) {
testUnalignedAndGeneric(t, func(impl string) {
buf := sequentialBytes(0x10000)
for alg, df := range testDigests {
d := df()
d.Reset()
d.Write(buf)
want := d.Sum(nil)
d.Reset()
for i := 0; i < len(buf); {
// Cycle through offsets which make a 137 byte sequence.
// Because 137 is prime this sequence should exercise all corner cases.
offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
for _, j := range offsets {
if v := len(buf) - i; v < j {
j = v
}
d.Write(buf[i : i+j])
i += j
}
}
got := d.Sum(nil)
if !bytes.Equal(got, want) {
t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
}
}
})
}
// TestAppend checks that appending works when reallocation is necessary.
func TestAppend(t *testing.T) {
testUnalignedAndGeneric(t, func(impl string) {
d := New224()
for capacity := 2; capacity <= 66; capacity += 64 {
// The first time around the loop, Sum will have to reallocate.
// The second time, it will not.
buf := make([]byte, 2, capacity)
d.Reset()
d.Write([]byte{0xcc})
buf = d.Sum(buf)
expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
t.Errorf("got %s, want %s", got, expected)
}
}
})
}
// TestAppendNoRealloc tests that appending works when no reallocation is necessary.
func TestAppendNoRealloc(t *testing.T) {
testUnalignedAndGeneric(t, func(impl string) {
buf := make([]byte, 1, 200)
d := New224()
d.Write([]byte{0xcc})
buf = d.Sum(buf)
expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
t.Errorf("%s: got %s, want %s", impl, got, expected)
}
})
}
// TestSqueezing checks that squeezing the full output a single time produces
// the same output as repeatedly squeezing the instance.
func TestSqueezing(t *testing.T) {
testUnalignedAndGeneric(t, func(impl string) {
for functionName, newShakeHash := range testShakes {
d0 := newShakeHash()
d0.Write([]byte(testString))
ref := make([]byte, 32)
d0.Read(ref)
d1 := newShakeHash()
d1.Write([]byte(testString))
var multiple []byte
for range ref {
one := make([]byte, 1)
d1.Read(one)
multiple = append(multiple, one...)
}
if !bytes.Equal(ref, multiple) {
t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
}
}
})
}
// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
func sequentialBytes(size int) []byte {
result := make([]byte, size)
for i := range result {
result[i] = byte(i)
}
return result
}
// BenchmarkPermutationFunction measures the speed of the permutation function
// with no input data.
func BenchmarkPermutationFunction(b *testing.B) {
b.SetBytes(int64(200))
var lanes [25]uint64
for i := 0; i < b.N; i++ {
keccakF1600(&lanes)
}
}
// benchmarkHash tests the speed to hash num buffers of buflen each.
func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
b.StopTimer()
h.Reset()
data := sequentialBytes(size)
b.SetBytes(int64(size * num))
b.StartTimer()
var state []byte
for i := 0; i < b.N; i++ {
for j := 0; j < num; j++ {
h.Write(data)
}
state = h.Sum(state[:0])
}
b.StopTimer()
h.Reset()
}
// benchmarkShake is specialized to the Shake instances, which don't
// require a copy on reading output.
func benchmarkShake(b *testing.B, h ShakeHash, size, num int) {
b.StopTimer()
h.Reset()
data := sequentialBytes(size)
d := make([]byte, 32)
b.SetBytes(int64(size * num))
b.StartTimer()
for i := 0; i < b.N; i++ {
h.Reset()
for j := 0; j < num; j++ {
h.Write(data)
}
h.Read(d)
}
}
func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) }
func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) }
func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) }
func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) }
func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) }
func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) }
func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) }
func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }
func Example_sum() {
buf := []byte("some data to hash")
// A hash needs to be 64 bytes long to have 256-bit collision resistance.
h := make([]byte, 64)
// Compute a 64-byte hash of buf and put it in h.
ShakeSum256(h, buf)
}
func Example_mac() {
k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long")
buf := []byte("and this is some data to authenticate")
// A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key.
h := make([]byte, 32)
d := NewShake256()
// Write the key into the hash.
d.Write(k)
// Now write the data.
d.Write(buf)
// Read 32 bytes of output from the hash into h.
d.Read(h)
}

Binary file not shown.

View file

@ -1488,7 +1488,15 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error {
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
} }
if index, err := d.blockchain.InsertChain(blocks); err != nil { if index, err := d.blockchain.InsertChain(blocks); err != nil {
if index < len(results) {
log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err)
} else {
// The InsertChain method in blockchain.go will sometimes return an out-of-bounds index,
// when it needs to preprocess blocks to import a sidechain.
// The importer will put together a new list of blocks to import, which is a superset
// of the blocks delivered from the downloader, and the indexing will be off.
log.Debug("Downloaded item processing failed on sidechain import", "index", index, "err", err)
}
return errInvalidChain return errInvalidChain
} }
return nil return nil

View file

@ -25,10 +25,10 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"golang.org/x/crypto/sha3"
) )
// stateReq represents a batch of state fetch requests grouped together into // stateReq represents a batch of state fetch requests grouped together into
@ -240,7 +240,7 @@ func newStateSync(d *Downloader, root common.Hash) *stateSync {
return &stateSync{ return &stateSync{
d: d, d: d,
sched: state.NewStateSync(root, d.stateDB), sched: state.NewStateSync(root, d.stateDB),
keccak: sha3.NewKeccak256(), keccak: sha3.NewLegacyKeccak256(),
tasks: make(map[common.Hash]*stateTask), tasks: make(map[common.Hash]*stateTask),
deliver: make(chan *stateReq), deliver: make(chan *stateReq),
cancel: make(chan struct{}), cancel: make(chan struct{}),
@ -398,9 +398,8 @@ func (s *stateSync) fillTasks(n int, req *stateReq) {
// process iterates over a batch of delivered state data, injecting each item // process iterates over a batch of delivered state data, injecting each item
// into a running state sync, re-queuing any items that were requested but not // into a running state sync, re-queuing any items that were requested but not
// delivered. // delivered. Returns whether the peer actually managed to deliver anything of
// Returns whether the peer actually managed to deliver anything of value, // value, and any error that occurred.
// and any error that occurred
func (s *stateSync) process(req *stateReq) (int, error) { func (s *stateSync) process(req *stateReq) (int, error) {
// Collect processing stats and update progress if valid data was received // Collect processing stats and update progress if valid data was received
duplicate, unexpected, successful := 0, 0, 0 duplicate, unexpected, successful := 0, 0, 0
@ -412,14 +411,12 @@ func (s *stateSync) process(req *stateReq) (int, error) {
}(time.Now()) }(time.Now())
// Iterate over all the delivered data and inject one-by-one into the trie // Iterate over all the delivered data and inject one-by-one into the trie
progress := false
for _, blob := range req.response { for _, blob := range req.response {
prog, hash, err := s.processNodeData(blob) _, hash, err := s.processNodeData(blob)
switch err { switch err {
case nil: case nil:
s.numUncommitted++ s.numUncommitted++
s.bytesUncommitted += len(blob) s.bytesUncommitted += len(blob)
progress = progress || prog
successful++ successful++
case trie.ErrNotRequested: case trie.ErrNotRequested:
unexpected++ unexpected++

File diff suppressed because one or more lines are too long

View file

@ -38,7 +38,7 @@
var op = log.op.toString(); var op = log.op.toString();
} }
// If a new contract is being created, add to the call stack // If a new contract is being created, add to the call stack
if (syscall && op == 'CREATE') { if (syscall && (op == 'CREATE' || op == "CREATE2")) {
var inOff = log.stack.peek(1).valueOf(); var inOff = log.stack.peek(1).valueOf();
var inEnd = inOff + log.stack.peek(2).valueOf(); var inEnd = inOff + log.stack.peek(2).valueOf();
@ -116,7 +116,7 @@
// Pop off the last call and get the execution results // Pop off the last call and get the execution results
var call = this.callstack.pop(); var call = this.callstack.pop();
if (call.type == 'CREATE') { if (call.type == 'CREATE' || call.type == "CREATE2") {
// If the call was a CREATE, retrieve the contract address and output code // If the call was a CREATE, retrieve the contract address and output code
call.gasUsed = '0x' + bigInt(call.gasIn - call.gasCost - log.getGas()).toString(16); call.gasUsed = '0x' + bigInt(call.gasIn - call.gasCost - log.getGas()).toString(16);
delete call.gasIn; delete call.gasCost; delete call.gasIn; delete call.gasCost;

View file

@ -86,6 +86,14 @@
var from = log.contract.getAddress(); var from = log.contract.getAddress();
this.lookupAccount(toContract(from, db.getNonce(from)), db); this.lookupAccount(toContract(from, db.getNonce(from)), db);
break; break;
case "CREATE2":
var from = log.contract.getAddress();
// stack: salt, size, offset, endowment
var offset = log.stack.peek(1).valueOf()
var size = log.stack.peek(2).valueOf()
var end = offset + size
this.lookupAccount(toContract2(from, log.stack.peek(3).toString(16), log.memory.slice(offset, end)), db);
break;
case "CALL": case "CALLCODE": case "DELEGATECALL": case "STATICCALL": case "CALL": case "CALLCODE": case "DELEGATECALL": case "STATICCALL":
this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db); this.lookupAccount(toAddress(log.stack.peek(1).toString(16)), db);
break; break;

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
//go:generate go-bindata -nometadata -o assets.go -pkg tracers -ignore ((tracers)|(assets)).go ./... //go:generate go-bindata -nometadata -o assets.go -pkg tracers -ignore tracers.go -ignore assets.go ./...
//go:generate gofmt -s -w assets.go //go:generate gofmt -s -w assets.go
// Package tracers contains the actual JavaScript tracer assets. // Package tracers contains the actual JavaScript tracer assets.

View file

@ -367,6 +367,28 @@ func New(code string) (*Tracer, error) {
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
return 1 return 1
}) })
tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int {
var from common.Address
if ptr, size := ctx.GetBuffer(-3); ptr != nil {
from = common.BytesToAddress(makeSlice(ptr, size))
} else {
from = common.HexToAddress(ctx.GetString(-3))
}
// Retrieve salt hex string from js stack
salt := common.HexToHash(ctx.GetString(-2))
// Retrieve code slice from js stack
var code []byte
if ptr, size := ctx.GetBuffer(-1); ptr != nil {
code = common.CopyBytes(makeSlice(ptr, size))
} else {
code = common.FromHex(ctx.GetString(-1))
}
codeHash := crypto.Keccak256(code)
ctx.Pop3()
contract := crypto.CreateAddress2(from, salt, codeHash)
copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:])
return 1
})
tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int {
_, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))] _, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))]
ctx.PushBoolean(ok) ctx.PushBoolean(ok)

View file

@ -17,6 +17,8 @@
package tracers package tracers
import ( import (
"crypto/ecdsa"
"crypto/rand"
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
@ -31,7 +33,9 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
) )
@ -116,6 +120,83 @@ type callTracerTest struct {
Result *callTrace `json:"result"` Result *callTrace `json:"result"`
} }
func TestPrestateTracerCreate2(t *testing.T) {
unsigned_tx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"),
new(big.Int), 5000000, big.NewInt(1), []byte{})
privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
if err != nil {
t.Fatalf("err %v", err)
}
signer := types.NewEIP155Signer(big.NewInt(1))
tx, err := types.SignTx(unsigned_tx, signer, privateKeyECDSA)
if err != nil {
t.Fatalf("err %v", err)
}
/**
This comes from one of the test-vectors on the Skinny Create2 - EIP
address 0x00000000000000000000000000000000deadbeef
salt 0x00000000000000000000000000000000000000000000000000000000cafebabe
init_code 0xdeadbeef
gas (assuming no mem expansion): 32006
result: 0x60f3f640a8508fC6a86d45DF051962668E1e8AC7
*/
origin, _ := signer.Sender(tx)
context := vm.Context{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Origin: origin,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000),
Time: new(big.Int).SetUint64(5),
Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000),
GasPrice: big.NewInt(1),
}
alloc := core.GenesisAlloc{}
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns
// the address
alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{
Nonce: 1,
Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"),
Balance: big.NewInt(1),
}
alloc[origin] = core.GenesisAccount{
Nonce: 1,
Code: []byte{},
Balance: big.NewInt(500000000000000),
}
statedb := tests.MakePreState(ethdb.NewMemDatabase(), alloc)
// Create the tracer, the EVM environment and run it
tracer, err := New("prestateTracer")
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
evm := vm.NewEVM(context, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
msg, err := tx.AsMessage(signer)
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, _, _, err = st.TransitionDb(); err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}
// Retrieve the trace result and compare against the etalon
res, err := tracer.GetResult()
if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err)
}
ret := make(map[string]interface{})
if err := json.Unmarshal(res, &ret); err != nil {
t.Fatalf("failed to unmarshal trace result: %v", err)
}
if _, has := ret["0x60f3f640a8508fc6a86d45df051962668e1e8ac7"]; !has {
t.Fatalf("Expected 0x60f3f640a8508fc6a86d45df051962668e1e8ac7 in result")
}
}
// Iterates over all the input-output datasets in the tracer test harness and // Iterates over all the input-output datasets in the tracer test harness and
// runs the JavaScript tracers against them. // runs the JavaScript tracers against them.
func TestCallTracer(t *testing.T) { func TestCallTracer(t *testing.T) {
@ -185,8 +266,9 @@ func TestCallTracer(t *testing.T) {
if err := json.Unmarshal(res, ret); err != nil { if err := json.Unmarshal(res, ret); err != nil {
t.Fatalf("failed to unmarshal trace result: %v", err) t.Fatalf("failed to unmarshal trace result: %v", err)
} }
if !reflect.DeepEqual(ret, test.Result) { if !reflect.DeepEqual(ret, test.Result) {
t.Fatalf("trace mismatch: have %+v, want %+v", ret, test.Result) t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result)
} }
}) })
} }

View file

@ -18,6 +18,7 @@
package web3ext package web3ext
var Modules = map[string]string{ var Modules = map[string]string{
"accounting": Accounting_JS,
"admin": Admin_JS, "admin": Admin_JS,
"chequebook": Chequebook_JS, "chequebook": Chequebook_JS,
"clique": Clique_JS, "clique": Clique_JS,
@ -704,3 +705,47 @@ web3._extend({
] ]
}); });
` `
const Accounting_JS = `
web3._extend({
property: 'accounting',
methods: [
new web3._extend.Property({
name: 'balance',
getter: 'account_balance'
}),
new web3._extend.Property({
name: 'balanceCredit',
getter: 'account_balanceCredit'
}),
new web3._extend.Property({
name: 'balanceDebit',
getter: 'account_balanceDebit'
}),
new web3._extend.Property({
name: 'bytesCredit',
getter: 'account_bytesCredit'
}),
new web3._extend.Property({
name: 'bytesDebit',
getter: 'account_bytesDebit'
}),
new web3._extend.Property({
name: 'msgCredit',
getter: 'account_msgCredit'
}),
new web3._extend.Property({
name: 'msgDebit',
getter: 'account_msgDebit'
}),
new web3._extend.Property({
name: 'peerDrops',
getter: 'account_peerDrops'
}),
new web3._extend.Property({
name: 'selfDrops',
getter: 'account_selfDrops'
}),
]
});
`

View file

@ -27,10 +27,10 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
) )
var ( var (
@ -1234,7 +1234,7 @@ func (net *Network) checkTopicRegister(data *topicRegister) (*pong, error) {
} }
func rlpHash(x interface{}) (h common.Hash) { func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256() hw := sha3.NewLegacyKeccak256()
rlp.Encode(hw, x) rlp.Encode(hw, x)
hw.Sum(h[:0]) hw.Sum(h[:0])
return h return h

View file

@ -23,9 +23,9 @@ import (
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
) )
// List of known secure identity schemes. // List of known secure identity schemes.
@ -48,7 +48,7 @@ func SignV4(r *enr.Record, privkey *ecdsa.PrivateKey) error {
cpy.Set(enr.ID("v4")) cpy.Set(enr.ID("v4"))
cpy.Set(Secp256k1(privkey.PublicKey)) cpy.Set(Secp256k1(privkey.PublicKey))
h := sha3.NewKeccak256() h := sha3.NewLegacyKeccak256()
rlp.Encode(h, cpy.AppendElements(nil)) rlp.Encode(h, cpy.AppendElements(nil))
sig, err := crypto.Sign(h.Sum(nil), privkey) sig, err := crypto.Sign(h.Sum(nil), privkey)
if err != nil { if err != nil {
@ -69,7 +69,7 @@ func (V4ID) Verify(r *enr.Record, sig []byte) error {
return fmt.Errorf("invalid public key") return fmt.Errorf("invalid public key")
} }
h := sha3.NewKeccak256() h := sha3.NewLegacyKeccak256()
rlp.Encode(h, r.AppendElements(nil)) rlp.Encode(h, r.AppendElements(nil))
if !crypto.VerifySignature(entry, h.Sum(nil), sig) { if !crypto.VerifySignature(entry, h.Sum(nil), sig) {
return enr.ErrInvalidSig return enr.ErrInvalidSig

View file

@ -0,0 +1,94 @@
package protocols
import (
"errors"
)
// Textual version number of accounting API
const AccountingVersion = "1.0"
var errNoAccountingMetrics = errors.New("accounting metrics not enabled")
// AccountingApi provides an API to access account related information
type AccountingApi struct {
metrics *AccountingMetrics
}
// NewAccountingApi creates a new AccountingApi
// m will be used to check if accounting metrics are enabled
func NewAccountingApi(m *AccountingMetrics) *AccountingApi {
return &AccountingApi{m}
}
// Balance returns local node balance (units credited - units debited)
func (self *AccountingApi) Balance() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
balance := mBalanceCredit.Count() - mBalanceDebit.Count()
return balance, nil
}
// BalanceCredit returns total amount of units credited by local node
func (self *AccountingApi) BalanceCredit() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mBalanceCredit.Count(), nil
}
// BalanceCredit returns total amount of units debited by local node
func (self *AccountingApi) BalanceDebit() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mBalanceDebit.Count(), nil
}
// BytesCredit returns total amount of bytes credited by local node
func (self *AccountingApi) BytesCredit() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mBytesCredit.Count(), nil
}
// BalanceCredit returns total amount of bytes debited by local node
func (self *AccountingApi) BytesDebit() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mBytesDebit.Count(), nil
}
// MsgCredit returns total amount of messages credited by local node
func (self *AccountingApi) MsgCredit() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mMsgCredit.Count(), nil
}
// MsgDebit returns total amount of messages debited by local node
func (self *AccountingApi) MsgDebit() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mMsgDebit.Count(), nil
}
// PeerDrops returns number of times when local node had to drop remote peers
func (self *AccountingApi) PeerDrops() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mPeerDrops.Count(), nil
}
// SelfDrops returns number of times when local node was overdrafted and dropped
func (self *AccountingApi) SelfDrops() (int64, error) {
if self.metrics == nil {
return 0, errNoAccountingMetrics
}
return mSelfDrops.Count(), nil
}

View file

@ -39,9 +39,9 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/golang/snappy" "github.com/golang/snappy"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -253,10 +253,10 @@ func (h *encHandshake) secrets(auth, authResp []byte) (secrets, error) {
} }
// setup sha3 instances for the MACs // setup sha3 instances for the MACs
mac1 := sha3.NewKeccak256() mac1 := sha3.NewLegacyKeccak256()
mac1.Write(xor(s.MAC, h.respNonce)) mac1.Write(xor(s.MAC, h.respNonce))
mac1.Write(auth) mac1.Write(auth)
mac2 := sha3.NewKeccak256() mac2 := sha3.NewLegacyKeccak256()
mac2.Write(xor(s.MAC, h.initNonce)) mac2.Write(xor(s.MAC, h.initNonce))
mac2.Write(authResp) mac2.Write(authResp)
if h.initiator { if h.initiator {

View file

@ -34,9 +34,9 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/p2p/simulations/pipes" "github.com/ethereum/go-ethereum/p2p/simulations/pipes"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
) )
func TestSharedSecret(t *testing.T) { func TestSharedSecret(t *testing.T) {
@ -334,8 +334,8 @@ func TestRLPXFrameRW(t *testing.T) {
s1 := secrets{ s1 := secrets{
AES: aesSecret, AES: aesSecret,
MAC: macSecret, MAC: macSecret,
EgressMAC: sha3.NewKeccak256(), EgressMAC: sha3.NewLegacyKeccak256(),
IngressMAC: sha3.NewKeccak256(), IngressMAC: sha3.NewLegacyKeccak256(),
} }
s1.EgressMAC.Write(egressMACinit) s1.EgressMAC.Write(egressMACinit)
s1.IngressMAC.Write(ingressMACinit) s1.IngressMAC.Write(ingressMACinit)
@ -344,8 +344,8 @@ func TestRLPXFrameRW(t *testing.T) {
s2 := secrets{ s2 := secrets{
AES: aesSecret, AES: aesSecret,
MAC: macSecret, MAC: macSecret,
EgressMAC: sha3.NewKeccak256(), EgressMAC: sha3.NewLegacyKeccak256(),
IngressMAC: sha3.NewKeccak256(), IngressMAC: sha3.NewLegacyKeccak256(),
} }
s2.EgressMAC.Write(ingressMACinit) s2.EgressMAC.Write(ingressMACinit)
s2.IngressMAC.Write(egressMACinit) s2.IngressMAC.Write(egressMACinit)

View file

@ -26,10 +26,10 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
"golang.org/x/crypto/sha3"
) )
// func init() { // func init() {
@ -48,8 +48,8 @@ func newTestTransport(rpub *ecdsa.PublicKey, fd net.Conn) transport {
wrapped.rw = newRLPXFrameRW(fd, secrets{ wrapped.rw = newRLPXFrameRW(fd, secrets{
MAC: zero16, MAC: zero16,
AES: zero16, AES: zero16,
IngressMAC: sha3.NewKeccak256(), IngressMAC: sha3.NewLegacyKeccak256(),
EgressMAC: sha3.NewKeccak256(), EgressMAC: sha3.NewLegacyKeccak256(),
}) })
return &testTransport{rpub: rpub, rlpx: wrapped} return &testTransport{rpub: rpub, rlpx: wrapped}
} }

View file

@ -46,7 +46,7 @@ import (
func init() { func init() {
// Register a reexec function to start a simulation node when the current binary is // Register a reexec function to start a simulation node when the current binary is
// executed as "p2p-node" (rather than whataver the main() function would normally do). // executed as "p2p-node" (rather than whatever the main() function would normally do).
reexec.Register("p2p-node", execP2PNode) reexec.Register("p2p-node", execP2PNode)
} }

View file

@ -130,7 +130,7 @@ func (s *SimAdapter) Dial(dest *enode.Node) (conn net.Conn, err error) {
return nil, err return nil, err
} }
// this is simulated 'listening' // this is simulated 'listening'
// asynchronously call the dialed destintion node's p2p server // asynchronously call the dialed destination node's p2p server
// to set up connection on the 'listening' side // to set up connection on the 'listening' side
go srv.SetupConn(pipe1, 0, nil) go srv.SetupConn(pipe1, 0, nil)
return pipe2, nil return pipe2, nil

View file

@ -25,6 +25,7 @@ import (
) )
func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) { func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) {
t.Helper()
adapter := adapters.NewSimAdapter(adapters.Services{ adapter := adapters.NewSimAdapter(adapters.Services{
"noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) { "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
return NewNoopService(nil), nil return NewNoopService(nil), nil

View file

@ -35,7 +35,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
colorable "github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
) )
var ( var (
@ -294,6 +294,7 @@ var testServices = adapters.Services{
} }
func testHTTPServer(t *testing.T) (*Network, *httptest.Server) { func testHTTPServer(t *testing.T) (*Network, *httptest.Server) {
t.Helper()
adapter := adapters.NewSimAdapter(testServices) adapter := adapters.NewSimAdapter(testServices)
network := NewNetwork(adapter, &NetworkConfig{ network := NewNetwork(adapter, &NetworkConfig{
DefaultService: "test", DefaultService: "test",

View file

@ -15,7 +15,7 @@
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package simulations simulates p2p networks. // Package simulations simulates p2p networks.
// A mokcer simulates starting and stopping real nodes in a network. // A mocker simulates starting and stopping real nodes in a network.
package simulations package simulations
import ( import (
@ -135,13 +135,13 @@ func TestMocker(t *testing.T) {
wg.Wait() wg.Wait()
//check there are nodeCount number of nodes in the network //check there are nodeCount number of nodes in the network
nodes_info, err := client.GetNodes() nodesInfo, err := client.GetNodes()
if err != nil { if err != nil {
t.Fatalf("Could not get nodes list: %s", err) t.Fatalf("Could not get nodes list: %s", err)
} }
if len(nodes_info) != nodeCount { if len(nodesInfo) != nodeCount {
t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodes_info)) t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodesInfo))
} }
//stop the mocker //stop the mocker
@ -160,12 +160,12 @@ func TestMocker(t *testing.T) {
} }
//now the number of nodes in the network should be zero //now the number of nodes in the network should be zero
nodes_info, err = client.GetNodes() nodesInfo, err = client.GetNodes()
if err != nil { if err != nil {
t.Fatalf("Could not get nodes list: %s", err) t.Fatalf("Could not get nodes list: %s", err)
} }
if len(nodes_info) != 0 { if len(nodesInfo) != 0 {
t.Fatalf("Expected empty list of nodes, got: %d", len(nodes_info)) t.Fatalf("Expected empty list of nodes, got: %d", len(nodesInfo))
} }
} }

View file

@ -518,7 +518,7 @@ func (net *Network) getConn(oneID, otherID enode.ID) *Conn {
return net.Conns[i] return net.Conns[i]
} }
// InitConn(one, other) retrieves the connectiton model for the connection between // InitConn(one, other) retrieves the connection model for the connection between
// peers one and other, or creates a new one if it does not exist // peers one and other, or creates a new one if it does not exist
// the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i)
// it checks if the connection is already up, and if the nodes are running // it checks if the connection is already up, and if the nodes are running
@ -564,8 +564,8 @@ func (net *Network) Shutdown() {
close(net.quitc) close(net.quitc)
} }
//Reset resets all network properties: // Reset resets all network properties:
//emtpies the nodes and the connection list // empties the nodes and the connection list
func (net *Network) Reset() { func (net *Network) Reset() {
net.lock.Lock() net.lock.Lock()
defer net.lock.Unlock() defer net.lock.Unlock()

View file

@ -18,14 +18,266 @@ package simulations
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"strconv"
"strings"
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
) )
// Tests that a created snapshot with a minimal service only contains the expected connections
// and that a network when loaded with this snapshot only contains those same connections
func TestSnapshot(t *testing.T) {
// PART I
// create snapshot from ring network
// this is a minimal service, whose protocol will take exactly one message OR close of connection before quitting
adapter := adapters.NewSimAdapter(adapters.Services{
"noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
return NewNoopService(nil), nil
},
})
// create network
network := NewNetwork(adapter, &NetworkConfig{
DefaultService: "noopwoop",
})
// \todo consider making a member of network, set to true threadsafe when shutdown
runningOne := true
defer func() {
if runningOne {
network.Shutdown()
}
}()
// create and start nodes
nodeCount := 20
ids := make([]enode.ID, nodeCount)
for i := 0; i < nodeCount; i++ {
conf := adapters.RandomNodeConfig()
node, err := network.NewNodeWithConfig(conf)
if err != nil {
t.Fatalf("error creating node: %s", err)
}
if err := network.Start(node.ID()); err != nil {
t.Fatalf("error starting node: %s", err)
}
ids[i] = node.ID()
}
// subscribe to peer events
evC := make(chan *Event)
sub := network.Events().Subscribe(evC)
defer sub.Unsubscribe()
// connect nodes in a ring
// spawn separate thread to avoid deadlock in the event listeners
go func() {
for i, id := range ids {
peerID := ids[(i+1)%len(ids)]
if err := network.Connect(id, peerID); err != nil {
t.Fatal(err)
}
}
}()
// collect connection events up to expected number
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
defer cancel()
checkIds := make(map[enode.ID][]enode.ID)
connEventCount := nodeCount
OUTER:
for {
select {
case <-ctx.Done():
t.Fatal(ctx.Err())
case ev := <-evC:
if ev.Type == EventTypeConn && !ev.Control {
// fail on any disconnect
if !ev.Conn.Up {
t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other)
}
checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other)
checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One)
connEventCount--
log.Debug("ev", "count", connEventCount)
if connEventCount == 0 {
break OUTER
}
}
}
}
// create snapshot of current network
snap, err := network.Snapshot()
if err != nil {
t.Fatal(err)
}
j, err := json.Marshal(snap)
if err != nil {
t.Fatal(err)
}
log.Debug("snapshot taken", "nodes", len(snap.Nodes), "conns", len(snap.Conns), "json", string(j))
// verify that the snap element numbers check out
if len(checkIds) != len(snap.Conns) || len(checkIds) != len(snap.Nodes) {
t.Fatalf("snapshot wrong node,conn counts %d,%d != %d", len(snap.Nodes), len(snap.Conns), len(checkIds))
}
// shut down sim network
runningOne = false
sub.Unsubscribe()
network.Shutdown()
// check that we have all the expected connections in the snapshot
for nodid, nodConns := range checkIds {
for _, nodConn := range nodConns {
var match bool
for _, snapConn := range snap.Conns {
if snapConn.One == nodid && snapConn.Other == nodConn {
match = true
break
} else if snapConn.Other == nodid && snapConn.One == nodConn {
match = true
break
}
}
if !match {
t.Fatalf("snapshot missing conn %v -> %v", nodid, nodConn)
}
}
}
log.Info("snapshot checked")
// PART II
// load snapshot and verify that exactly same connections are formed
adapter = adapters.NewSimAdapter(adapters.Services{
"noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
return NewNoopService(nil), nil
},
})
network = NewNetwork(adapter, &NetworkConfig{
DefaultService: "noopwoop",
})
defer func() {
network.Shutdown()
}()
// subscribe to peer events
// every node up and conn up event will generate one additional control event
// therefore multiply the count by two
evC = make(chan *Event, (len(snap.Conns)*2)+(len(snap.Nodes)*2))
sub = network.Events().Subscribe(evC)
defer sub.Unsubscribe()
// load the snapshot
// spawn separate thread to avoid deadlock in the event listeners
err = network.Load(snap)
if err != nil {
t.Fatal(err)
}
// collect connection events up to expected number
ctx, cancel = context.WithTimeout(context.TODO(), time.Second*3)
defer cancel()
connEventCount = nodeCount
OUTER_TWO:
for {
select {
case <-ctx.Done():
t.Fatal(ctx.Err())
case ev := <-evC:
if ev.Type == EventTypeConn && !ev.Control {
// fail on any disconnect
if !ev.Conn.Up {
t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other)
}
log.Debug("conn", "on", ev.Conn.One, "other", ev.Conn.Other)
checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other)
checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One)
connEventCount--
log.Debug("ev", "count", connEventCount)
if connEventCount == 0 {
break OUTER_TWO
}
}
}
}
// check that we have all expected connections in the network
for _, snapConn := range snap.Conns {
var match bool
for nodid, nodConns := range checkIds {
for _, nodConn := range nodConns {
if snapConn.One == nodid && snapConn.Other == nodConn {
match = true
break
} else if snapConn.Other == nodid && snapConn.One == nodConn {
match = true
break
}
}
}
if !match {
t.Fatalf("network missing conn %v -> %v", snapConn.One, snapConn.Other)
}
}
// verify that network didn't generate any other additional connection events after the ones we have collected within a reasonable period of time
ctx, cancel = context.WithTimeout(context.TODO(), time.Second)
defer cancel()
select {
case <-ctx.Done():
case ev := <-evC:
if ev.Type == EventTypeConn {
t.Fatalf("Superfluous conn found %v -> %v", ev.Conn.One, ev.Conn.Other)
}
}
// This test validates if all connections from the snapshot
// are created in the network.
t.Run("conns after load", func(t *testing.T) {
// Create new network.
n := NewNetwork(
adapters.NewSimAdapter(adapters.Services{
"noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
return NewNoopService(nil), nil
},
}),
&NetworkConfig{
DefaultService: "noopwoop",
},
)
defer n.Shutdown()
// Load the same snapshot.
err := n.Load(snap)
if err != nil {
t.Fatal(err)
}
// Check every connection from the snapshot
// if it is in the network, too.
for _, c := range snap.Conns {
if n.GetConn(c.One, c.Other) == nil {
t.Errorf("missing connection: %s -> %s", c.One, c.Other)
}
}
})
}
// TestNetworkSimulation creates a multi-node simulation network with each node // TestNetworkSimulation creates a multi-node simulation network with each node
// connected in a ring topology, checks that all nodes successfully handshake // connected in a ring topology, checks that all nodes successfully handshake
// with each other and that a snapshot fully represents the desired topology // with each other and that a snapshot fully represents the desired topology
@ -158,3 +410,78 @@ func triggerChecks(ctx context.Context, ids []enode.ID, trigger chan enode.ID, i
} }
} }
} }
// \todo: refactor to implement shapshots
// and connect configuration methods once these are moved from
// swarm/network/simulations/connect.go
func BenchmarkMinimalService(b *testing.B) {
b.Run("ring/32", benchmarkMinimalServiceTmp)
}
func benchmarkMinimalServiceTmp(b *testing.B) {
// stop timer to discard setup time pollution
args := strings.Split(b.Name(), "/")
nodeCount, err := strconv.ParseInt(args[2], 10, 16)
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
// this is a minimal service, whose protocol will close a channel upon run of protocol
// making it possible to bench the time it takes for the service to start and protocol actually to be run
protoCMap := make(map[enode.ID]map[enode.ID]chan struct{})
adapter := adapters.NewSimAdapter(adapters.Services{
"noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
protoCMap[ctx.Config.ID] = make(map[enode.ID]chan struct{})
svc := NewNoopService(protoCMap[ctx.Config.ID])
return svc, nil
},
})
// create network
network := NewNetwork(adapter, &NetworkConfig{
DefaultService: "noopwoop",
})
defer network.Shutdown()
// create and start nodes
ids := make([]enode.ID, nodeCount)
for i := 0; i < int(nodeCount); i++ {
conf := adapters.RandomNodeConfig()
node, err := network.NewNodeWithConfig(conf)
if err != nil {
b.Fatalf("error creating node: %s", err)
}
if err := network.Start(node.ID()); err != nil {
b.Fatalf("error starting node: %s", err)
}
ids[i] = node.ID()
}
// ready, set, go
b.ResetTimer()
// connect nodes in a ring
for i, id := range ids {
peerID := ids[(i+1)%len(ids)]
if err := network.Connect(id, peerID); err != nil {
b.Fatal(err)
}
}
// wait for all protocols to signal to close down
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
defer cancel()
for nodid, peers := range protoCMap {
for peerid, peerC := range peers {
log.Debug("getting ", "node", nodid, "peer", peerid)
select {
case <-ctx.Done():
b.Fatal(ctx.Err())
case <-peerC:
}
}
}
}
}

View file

@ -20,13 +20,31 @@ package rpc
import ( import (
"context" "context"
"fmt"
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"github.com/ethereum/go-ethereum/log"
) )
/*
#include <sys/un.h>
int max_socket_path_size() {
struct sockaddr_un s;
return sizeof(s.sun_path);
}
*/
import "C"
// ipcListen will create a Unix socket on the given endpoint. // ipcListen will create a Unix socket on the given endpoint.
func ipcListen(endpoint string) (net.Listener, error) { func ipcListen(endpoint string) (net.Listener, error) {
if len(endpoint) > int(C.max_socket_path_size()) {
log.Warn(fmt.Sprintf("The ipc endpoint is longer than %d characters. ", C.max_socket_path_size()),
"endpoint", endpoint)
}
// Ensure the IPC path exists and remove any previous leftover // Ensure the IPC path exists and remove any previous leftover
if err := os.MkdirAll(filepath.Dir(endpoint), 0751); err != nil { if err := os.MkdirAll(filepath.Dir(endpoint), 0751); err != nil {
return nil, err return nil, err

View file

@ -15,11 +15,11 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/log"
"github.com/ethereum/go-ethereum/swarm/sctx" "github.com/ethereum/go-ethereum/swarm/sctx"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
"golang.org/x/crypto/scrypt" "golang.org/x/crypto/scrypt"
"golang.org/x/crypto/sha3"
cli "gopkg.in/urfave/cli.v1" cli "gopkg.in/urfave/cli.v1"
) )
@ -336,7 +336,7 @@ func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.Priva
} }
func (a *API) getACTDecryptionKey(ctx context.Context, actManifestAddress storage.Address, sessionKey []byte) (found bool, ciphertext, decryptionKey []byte, err error) { func (a *API) getACTDecryptionKey(ctx context.Context, actManifestAddress storage.Address, sessionKey []byte) (found bool, ciphertext, decryptionKey []byte, err error) {
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
hasher.Write(append(sessionKey, 0)) hasher.Write(append(sessionKey, 0))
lookupKey := hasher.Sum(nil) lookupKey := hasher.Sum(nil)
hasher.Reset() hasher.Reset()
@ -462,7 +462,7 @@ func DoACT(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees
return nil, nil, nil, err return nil, nil, nil, err
} }
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
hasher.Write(append(sessionKey, 0)) hasher.Write(append(sessionKey, 0))
lookupKey := hasher.Sum(nil) lookupKey := hasher.Sum(nil)
@ -484,7 +484,7 @@ func DoACT(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
hasher := sha3.NewKeccak256() hasher := sha3.NewLegacyKeccak256()
hasher.Write(append(sessionKey, 0)) hasher.Write(append(sessionKey, 0))
lookupKey := hasher.Sum(nil) lookupKey := hasher.Sum(nil)

View file

@ -50,10 +50,6 @@ import (
opentracing "github.com/opentracing/opentracing-go" opentracing "github.com/opentracing/opentracing-go"
) )
var (
ErrNotFound = errors.New("not found")
)
var ( var (
apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil) apiResolveCount = metrics.NewRegisteredCounter("api.resolve.count", nil)
apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil) apiResolveFail = metrics.NewRegisteredCounter("api.resolve.fail", nil)
@ -136,13 +132,6 @@ func MultiResolverOptionWithResolver(r ResolveValidator, tld string) MultiResolv
} }
} }
// MultiResolverOptionWithNameHash is unused at the time of this writing
func MultiResolverOptionWithNameHash(nameHash func(string) common.Hash) MultiResolverOption {
return func(m *MultiResolver) {
m.nameHash = nameHash
}
}
// NewMultiResolver creates a new instance of MultiResolver. // NewMultiResolver creates a new instance of MultiResolver.
func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) { func NewMultiResolver(opts ...MultiResolverOption) (m *MultiResolver) {
m = &MultiResolver{ m = &MultiResolver{
@ -173,40 +162,6 @@ func (m *MultiResolver) Resolve(addr string) (h common.Hash, err error) {
return return
} }
// ValidateOwner checks the ENS to validate that the owner of the given domain is the given eth address
func (m *MultiResolver) ValidateOwner(name string, address common.Address) (bool, error) {
rs, err := m.getResolveValidator(name)
if err != nil {
return false, err
}
var addr common.Address
for _, r := range rs {
addr, err = r.Owner(m.nameHash(name))
// we hide the error if it is not for the last resolver we check
if err == nil {
return addr == address, nil
}
}
return false, err
}
// HeaderByNumber uses the validator of the given domainname and retrieves the header for the given block number
func (m *MultiResolver) HeaderByNumber(ctx context.Context, name string, blockNr *big.Int) (*types.Header, error) {
rs, err := m.getResolveValidator(name)
if err != nil {
return nil, err
}
for _, r := range rs {
var header *types.Header
header, err = r.HeaderByNumber(ctx, blockNr)
// we hide the error if it is not for the last resolver we check
if err == nil {
return header, nil
}
}
return nil, err
}
// getResolveValidator uses the hostname to retrieve the resolver associated with the top level domain // getResolveValidator uses the hostname to retrieve the resolver associated with the top level domain
func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, error) { func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, error) {
rs := m.resolvers[""] rs := m.resolvers[""]
@ -224,11 +179,6 @@ func (m *MultiResolver) getResolveValidator(name string) ([]ResolveValidator, er
return rs, nil return rs, nil
} }
// SetNameHash sets the hasher function that hashes the domain into a name hash that ENS uses
func (m *MultiResolver) SetNameHash(nameHash func(string) common.Hash) {
m.nameHash = nameHash
}
/* /*
API implements webserver/file system related content storage and retrieval API implements webserver/file system related content storage and retrieval
on top of the FileStore on top of the FileStore
@ -265,9 +215,6 @@ func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt b
return a.fileStore.Store(ctx, data, size, toEncrypt) return a.fileStore.Store(ctx, data, size, toEncrypt)
} }
// ErrResolve is returned when an URI cannot be resolved from ENS.
type ErrResolve error
// Resolve a name into a content-addressed hash // Resolve a name into a content-addressed hash
// where address could be an ENS name, or a content addressed hash // where address could be an ENS name, or a content addressed hash
func (a *API) Resolve(ctx context.Context, address string) (storage.Address, error) { func (a *API) Resolve(ctx context.Context, address string) (storage.Address, error) {
@ -980,11 +927,6 @@ func (a *API) FeedsUpdate(ctx context.Context, request *feed.Request) (storage.A
return a.feed.Update(ctx, request) return a.feed.Update(ctx, request)
} }
// FeedsHashSize returned the size of the digest produced by Swarm feeds' hashing function
func (a *API) FeedsHashSize() int {
return a.feed.HashSize
}
// ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails // ErrCannotLoadFeedManifest is returned when looking up a feeds manifest fails
var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest") var ErrCannotLoadFeedManifest = errors.New("Cannot load feed manifest")

View file

@ -45,11 +45,6 @@ import (
"github.com/pborman/uuid" "github.com/pborman/uuid"
) )
var (
DefaultGateway = "http://localhost:8500"
DefaultClient = NewClient(DefaultGateway)
)
var ( var (
ErrUnauthorized = errors.New("unauthorized") ErrUnauthorized = errors.New("unauthorized")
) )

View file

@ -20,8 +20,8 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/swarm/storage/encryption" "github.com/ethereum/go-ethereum/swarm/storage/encryption"
"golang.org/x/crypto/sha3"
) )
type RefEncryption struct { type RefEncryption struct {
@ -39,12 +39,12 @@ func NewRefEncryption(refSize int) *RefEncryption {
} }
func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) { func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) {
spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewKeccak256) spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewLegacyKeccak256)
encryptedSpan, err := spanEncryption.Encrypt(re.span) encryptedSpan, err := spanEncryption.Encrypt(re.span)
if err != nil { if err != nil {
return nil, err return nil, err
} }
dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewKeccak256) dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewLegacyKeccak256)
encryptedData, err := dataEncryption.Encrypt(ref) encryptedData, err := dataEncryption.Encrypt(ref)
if err != nil { if err != nil {
return nil, err return nil, err
@ -57,7 +57,7 @@ func (re *RefEncryption) Encrypt(ref []byte, key []byte) ([]byte, error) {
} }
func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) { func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) {
spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewKeccak256) spanEncryption := encryption.New(key, 0, uint32(re.refSize/32), sha3.NewLegacyKeccak256)
decryptedSpan, err := spanEncryption.Decrypt(ref[:8]) decryptedSpan, err := spanEncryption.Decrypt(ref[:8])
if err != nil { if err != nil {
return nil, err return nil, err
@ -68,7 +68,7 @@ func (re *RefEncryption) Decrypt(ref []byte, key []byte) ([]byte, error) {
return nil, errors.New("invalid span in encrypted reference") return nil, errors.New("invalid span in encrypted reference")
} }
dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewKeccak256) dataEncryption := encryption.New(key, re.refSize, 0, sha3.NewLegacyKeccak256)
decryptedRef, err := dataEncryption.Decrypt(ref[8:]) decryptedRef, err := dataEncryption.Decrypt(ref[8:])
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -80,7 +80,7 @@ func InitLoggingResponseWriter(h http.Handler) http.Handler {
h.ServeHTTP(writer, r) h.ServeHTTP(writer, r)
ts := time.Since(tn) ts := time.Since(tn)
log.Info("request served", "ruid", GetRUID(r.Context()), "code", writer.statusCode, "time", ts*time.Millisecond) log.Info("request served", "ruid", GetRUID(r.Context()), "code", writer.statusCode, "time", ts)
metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.time", r.Method), nil).Update(ts) metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.time", r.Method), nil).Update(ts)
metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.%d.time", r.Method, writer.statusCode), nil).Update(ts) metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.%d.time", r.Method, writer.statusCode), nil).Update(ts)
}) })

View file

@ -83,23 +83,3 @@ func (s *Storage) Get(ctx context.Context, bzzpath string) (*Response, error) {
} }
return &Response{mimeType, status, expsize, string(body[:size])}, err return &Response{mimeType, status, expsize, string(body[:size])}, err
} }
// Modify(rootHash, basePath, contentHash, contentType) takes th e manifest trie rooted in rootHash,
// and merge on to it. creating an entry w conentType (mime)
//
// DEPRECATED: Use the HTTP API instead
func (s *Storage) Modify(ctx context.Context, rootHash, path, contentHash, contentType string) (newRootHash string, err error) {
uri, err := Parse("bzz:/" + rootHash)
if err != nil {
return "", err
}
addr, err := s.api.Resolve(ctx, uri.Addr)
if err != nil {
return "", err
}
addr, err = s.api.Modify(ctx, addr, path, contentHash, contentType)
if err != nil {
return "", err
}
return addr.Hex(), nil
}

View file

@ -29,18 +29,6 @@ func NewControl(api *API, hive *network.Hive) *Control {
return &Control{api, hive} return &Control{api, hive}
} }
//func (self *Control) BlockNetworkRead(on bool) {
// self.hive.BlockNetworkRead(on)
//}
//
//func (self *Control) SyncEnabled(on bool) {
// self.hive.SyncEnabled(on)
//}
//
//func (self *Control) SwapEnabled(on bool) {
// self.hive.SwapEnabled(on)
//}
//
func (c *Control) Hive() string { func (c *Control) Hive() string {
return c.hive.String() return c.hive.String()
} }

View file

@ -33,8 +33,6 @@ func TestParseURI(t *testing.T) {
expectImmutable bool expectImmutable bool
expectList bool expectList bool
expectHash bool expectHash bool
expectDeprecatedRaw bool
expectDeprecatedImmutable bool
expectValidKey bool expectValidKey bool
expectAddr storage.Address expectAddr storage.Address
} }

View file

@ -61,7 +61,7 @@ const (
) )
// BaseHasherFunc is a hash.Hash constructor function used for the base hash of the BMT. // BaseHasherFunc is a hash.Hash constructor function used for the base hash of the BMT.
// implemented by Keccak256 SHA3 sha3.NewKeccak256 // implemented by Keccak256 SHA3 sha3.NewLegacyKeccak256
type BaseHasherFunc func() hash.Hash type BaseHasherFunc func() hash.Hash
// Hasher a reusable hasher for fixed maximum size chunks representing a BMT // Hasher a reusable hasher for fixed maximum size chunks representing a BMT

View file

@ -26,8 +26,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/swarm/testutil" "github.com/ethereum/go-ethereum/swarm/testutil"
"golang.org/x/crypto/sha3"
) )
// the actual data length generated (could be longer than max datalength of the BMT) // the actual data length generated (could be longer than max datalength of the BMT)
@ -44,7 +44,7 @@ var counts = []int{1, 2, 3, 4, 5, 8, 9, 15, 16, 17, 32, 37, 42, 53, 63, 64, 65,
// calculates the Keccak256 SHA3 hash of the data // calculates the Keccak256 SHA3 hash of the data
func sha3hash(data ...[]byte) []byte { func sha3hash(data ...[]byte) []byte {
h := sha3.NewKeccak256() h := sha3.NewLegacyKeccak256()
return doSum(h, nil, data...) return doSum(h, nil, data...)
} }
@ -121,7 +121,7 @@ func TestRefHasher(t *testing.T) {
t.Run(fmt.Sprintf("%d_segments_%d_bytes", segmentCount, length), func(t *testing.T) { t.Run(fmt.Sprintf("%d_segments_%d_bytes", segmentCount, length), func(t *testing.T) {
data := testutil.RandomBytes(i, length) data := testutil.RandomBytes(i, length)
expected := x.expected(data) expected := x.expected(data)
actual := NewRefHasher(sha3.NewKeccak256, segmentCount).Hash(data) actual := NewRefHasher(sha3.NewLegacyKeccak256, segmentCount).Hash(data)
if !bytes.Equal(actual, expected) { if !bytes.Equal(actual, expected) {
t.Fatalf("expected %x, got %x", expected, actual) t.Fatalf("expected %x, got %x", expected, actual)
} }
@ -133,7 +133,7 @@ func TestRefHasher(t *testing.T) {
// tests if hasher responds with correct hash comparing the reference implementation return value // tests if hasher responds with correct hash comparing the reference implementation return value
func TestHasherEmptyData(t *testing.T) { func TestHasherEmptyData(t *testing.T) {
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
var data []byte var data []byte
for _, count := range counts { for _, count := range counts {
t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) {
@ -153,7 +153,7 @@ func TestHasherEmptyData(t *testing.T) {
// tests sequential write with entire max size written in one go // tests sequential write with entire max size written in one go
func TestSyncHasherCorrectness(t *testing.T) { func TestSyncHasherCorrectness(t *testing.T) {
data := testutil.RandomBytes(1, BufferSize) data := testutil.RandomBytes(1, BufferSize)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
size := hasher().Size() size := hasher().Size()
var err error var err error
@ -179,7 +179,7 @@ func TestSyncHasherCorrectness(t *testing.T) {
// tests order-neutral concurrent writes with entire max size written in one go // tests order-neutral concurrent writes with entire max size written in one go
func TestAsyncCorrectness(t *testing.T) { func TestAsyncCorrectness(t *testing.T) {
data := testutil.RandomBytes(1, BufferSize) data := testutil.RandomBytes(1, BufferSize)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
size := hasher().Size() size := hasher().Size()
whs := []whenHash{first, last, random} whs := []whenHash{first, last, random}
@ -226,7 +226,7 @@ func TestHasherReuse(t *testing.T) {
// tests if bmt reuse is not corrupting result // tests if bmt reuse is not corrupting result
func testHasherReuse(poolsize int, t *testing.T) { func testHasherReuse(poolsize int, t *testing.T) {
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
pool := NewTreePool(hasher, segmentCount, poolsize) pool := NewTreePool(hasher, segmentCount, poolsize)
defer pool.Drain(0) defer pool.Drain(0)
bmt := New(pool) bmt := New(pool)
@ -243,7 +243,7 @@ func testHasherReuse(poolsize int, t *testing.T) {
// Tests if pool can be cleanly reused even in concurrent use by several hasher // Tests if pool can be cleanly reused even in concurrent use by several hasher
func TestBMTConcurrentUse(t *testing.T) { func TestBMTConcurrentUse(t *testing.T) {
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
pool := NewTreePool(hasher, segmentCount, PoolSize) pool := NewTreePool(hasher, segmentCount, PoolSize)
defer pool.Drain(0) defer pool.Drain(0)
cycles := 100 cycles := 100
@ -277,7 +277,7 @@ LOOP:
// Tests BMT Hasher io.Writer interface is working correctly // Tests BMT Hasher io.Writer interface is working correctly
// even multiple short random write buffers // even multiple short random write buffers
func TestBMTWriterBuffers(t *testing.T) { func TestBMTWriterBuffers(t *testing.T) {
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
for _, count := range counts { for _, count := range counts {
t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) { t.Run(fmt.Sprintf("%d_segments", count), func(t *testing.T) {
@ -410,7 +410,7 @@ func BenchmarkPool(t *testing.B) {
// benchmarks simple sha3 hash on chunks // benchmarks simple sha3 hash on chunks
func benchmarkSHA3(t *testing.B, n int) { func benchmarkSHA3(t *testing.B, n int) {
data := testutil.RandomBytes(1, n) data := testutil.RandomBytes(1, n)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
h := hasher() h := hasher()
t.ReportAllocs() t.ReportAllocs()
@ -426,7 +426,7 @@ func benchmarkSHA3(t *testing.B, n int) {
// the premise is that this is the minimum computation needed for a BMT // the premise is that this is the minimum computation needed for a BMT
// therefore this serves as a theoretical optimum for concurrent implementations // therefore this serves as a theoretical optimum for concurrent implementations
func benchmarkBMTBaseline(t *testing.B, n int) { func benchmarkBMTBaseline(t *testing.B, n int) {
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
hashSize := hasher().Size() hashSize := hasher().Size()
data := testutil.RandomBytes(1, hashSize) data := testutil.RandomBytes(1, hashSize)
@ -453,7 +453,7 @@ func benchmarkBMTBaseline(t *testing.B, n int) {
// benchmarks BMT Hasher // benchmarks BMT Hasher
func benchmarkBMT(t *testing.B, n int) { func benchmarkBMT(t *testing.B, n int) {
data := testutil.RandomBytes(1, n) data := testutil.RandomBytes(1, n)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
pool := NewTreePool(hasher, segmentCount, PoolSize) pool := NewTreePool(hasher, segmentCount, PoolSize)
bmt := New(pool) bmt := New(pool)
@ -467,7 +467,7 @@ func benchmarkBMT(t *testing.B, n int) {
// benchmarks BMT hasher with asynchronous concurrent segment/section writes // benchmarks BMT hasher with asynchronous concurrent segment/section writes
func benchmarkBMTAsync(t *testing.B, n int, wh whenHash, double bool) { func benchmarkBMTAsync(t *testing.B, n int, wh whenHash, double bool) {
data := testutil.RandomBytes(1, n) data := testutil.RandomBytes(1, n)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
pool := NewTreePool(hasher, segmentCount, PoolSize) pool := NewTreePool(hasher, segmentCount, PoolSize)
bmt := New(pool).NewAsyncWriter(double) bmt := New(pool).NewAsyncWriter(double)
idxs, segments := splitAndShuffle(bmt.SectionSize(), data) idxs, segments := splitAndShuffle(bmt.SectionSize(), data)
@ -485,7 +485,7 @@ func benchmarkBMTAsync(t *testing.B, n int, wh whenHash, double bool) {
// benchmarks 100 concurrent bmt hashes with pool capacity // benchmarks 100 concurrent bmt hashes with pool capacity
func benchmarkPool(t *testing.B, poolsize, n int) { func benchmarkPool(t *testing.B, poolsize, n int) {
data := testutil.RandomBytes(1, n) data := testutil.RandomBytes(1, n)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
pool := NewTreePool(hasher, segmentCount, poolsize) pool := NewTreePool(hasher, segmentCount, poolsize)
cycles := 100 cycles := 100
@ -508,7 +508,7 @@ func benchmarkPool(t *testing.B, poolsize, n int) {
// benchmarks the reference hasher // benchmarks the reference hasher
func benchmarkRefHasher(t *testing.B, n int) { func benchmarkRefHasher(t *testing.B, n int) {
data := testutil.RandomBytes(1, n) data := testutil.RandomBytes(1, n)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
rbmt := NewRefHasher(hasher, 128) rbmt := NewRefHasher(hasher, 128)
t.ReportAllocs() t.ReportAllocs()

23
swarm/docker/Dockerfile Normal file
View file

@ -0,0 +1,23 @@
FROM golang:1.11-alpine as builder
ARG VERSION
RUN apk add --update git gcc g++ linux-headers
RUN mkdir -p $GOPATH/src/github.com/ethereum && \
cd $GOPATH/src/github.com/ethereum && \
git clone https://github.com/ethersphere/go-ethereum && \
cd $GOPATH/src/github.com/ethereum/go-ethereum && \
git checkout ${VERSION} && \
go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm && \
go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/swarm/swarm-smoke && \
go install -ldflags "-X main.gitCommit=${VERSION}" ./cmd/geth && \
cp $GOPATH/bin/swarm /swarm && cp $GOPATH/bin/geth /geth && cp $GOPATH/bin/swarm-smoke /swarm-smoke
# Release image with the required binaries and scripts
FROM alpine:3.8
WORKDIR /
COPY --from=builder /swarm /geth /swarm-smoke /
ADD run.sh /run.sh
ADD run-smoke.sh /run-smoke.sh
ENTRYPOINT ["/run.sh"]

7
swarm/docker/run-smoke.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
set -o errexit
set -o pipefail
set -o nounset
/swarm-smoke $@ 2>&1 || true

26
swarm/docker/run.sh Executable file
View file

@ -0,0 +1,26 @@
#!/bin/sh
set -o errexit
set -o pipefail
set -o nounset
PASSWORD=${PASSWORD:-}
DATADIR=${DATADIR:-/root/.ethereum/}
if [ "$PASSWORD" == "" ]; then echo "Password must be set, in order to use swarm non-interactively." && exit 1; fi
echo $PASSWORD > /password
KEYFILE=`find $DATADIR | grep UTC | head -n 1` || true
if [ ! -f "$KEYFILE" ]; then echo "No keyfile found. Generating..." && /geth --datadir $DATADIR --password /password account new; fi
KEYFILE=`find $DATADIR | grep UTC | head -n 1` || true
if [ ! -f "$KEYFILE" ]; then echo "Could not find nor generate a BZZ keyfile." && exit 1; else echo "Found keyfile $KEYFILE"; fi
VERSION=`/swarm version`
echo "Running Swarm:"
echo $VERSION
export BZZACCOUNT="`echo -n $KEYFILE | tail -c 40`" || true
if [ "$BZZACCOUNT" == "" ]; then echo "Could not parse BZZACCOUNT from keyfile." && exit 1; fi
exec /swarm --bzzaccount=$BZZACCOUNT --password /password --datadir $DATADIR $@ 2>&1

View file

@ -60,7 +60,3 @@ func (bv *BitVector) Set(i int, v bool) {
func (bv *BitVector) Bytes() []byte { func (bv *BitVector) Bytes() []byte {
return bv.b return bv.b
} }
func (bv *BitVector) Length() int {
return bv.len
}

View file

@ -161,7 +161,7 @@ func (d *Peer) handleSubPeersMsg(msg *subPeersMsg) error {
d.setDepth(msg.Depth) d.setDepth(msg.Depth)
var peers []*BzzAddr var peers []*BzzAddr
d.kad.EachConn(d.Over(), 255, func(p *Peer, po int, isproxbin bool) bool { d.kad.EachConn(d.Over(), 255, func(p *Peer, po int, isproxbin bool) bool {
if pob, _ := pof(d, d.kad.BaseAddr(), 0); pob > po { if pob, _ := Pof(d, d.kad.BaseAddr(), 0); pob > po {
return false return false
} }
if !d.seen(p.BzzAddr) { if !d.seen(p.BzzAddr) {

View file

@ -49,7 +49,7 @@ a guaranteed constant maximum limit on the number of hops needed to reach one
node from the other. node from the other.
*/ */
var pof = pot.DefaultPof(256) var Pof = pot.DefaultPof(256)
// KadParams holds the config params for Kademlia // KadParams holds the config params for Kademlia
type KadParams struct { type KadParams struct {
@ -62,7 +62,7 @@ type KadParams struct {
RetryExponent int // exponent to multiply retry intervals with RetryExponent int // exponent to multiply retry intervals with
MaxRetries int // maximum number of redial attempts MaxRetries int // maximum number of redial attempts
// function to sanction or prevent suggesting a peer // function to sanction or prevent suggesting a peer
Reachable func(*BzzAddr) bool Reachable func(*BzzAddr) bool `json:"-"`
} }
// NewKadParams returns a params struct with default values // NewKadParams returns a params struct with default values
@ -89,7 +89,6 @@ type Kademlia struct {
nDepth int // stores the last neighbourhood depth nDepth int // stores the last neighbourhood depth
nDepthC chan int // returned by DepthC function to signal neighbourhood depth change nDepthC chan int // returned by DepthC function to signal neighbourhood depth change
addrCountC chan int // returned by AddrCountC function to signal peer count change addrCountC chan int // returned by AddrCountC function to signal peer count change
Pof func(pot.Val, pot.Val, int) (int, bool) // function for calculating kademlia routing distance between two addresses
} }
// NewKademlia creates a Kademlia table for base address addr // NewKademlia creates a Kademlia table for base address addr
@ -104,7 +103,6 @@ func NewKademlia(addr []byte, params *KadParams) *Kademlia {
KadParams: params, KadParams: params,
addrs: pot.NewPot(nil, 0), addrs: pot.NewPot(nil, 0),
conns: pot.NewPot(nil, 0), conns: pot.NewPot(nil, 0),
Pof: pof,
} }
} }
@ -147,7 +145,7 @@ func (k *Kademlia) Register(peers ...*BzzAddr) error {
return fmt.Errorf("add peers: %x is self", k.base) return fmt.Errorf("add peers: %x is self", k.base)
} }
var found bool var found bool
k.addrs, _, found, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { k.addrs, _, found, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val {
// if not found // if not found
if v == nil { if v == nil {
// insert new offline peer into conns // insert new offline peer into conns
@ -181,7 +179,7 @@ func (k *Kademlia) SuggestPeer() (a *BzzAddr, o int, want bool) {
// if there is a callable neighbour within the current proxBin, connect // if there is a callable neighbour within the current proxBin, connect
// this makes sure nearest neighbour set is fully connected // this makes sure nearest neighbour set is fully connected
var ppo int var ppo int
k.addrs.EachNeighbour(k.base, pof, func(val pot.Val, po int) bool { k.addrs.EachNeighbour(k.base, Pof, func(val pot.Val, po int) bool {
if po < depth { if po < depth {
return false return false
} }
@ -200,7 +198,7 @@ func (k *Kademlia) SuggestPeer() (a *BzzAddr, o int, want bool) {
var bpo []int var bpo []int
prev := -1 prev := -1
k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
prev++ prev++
for ; prev < po; prev++ { for ; prev < po; prev++ {
bpo = append(bpo, prev) bpo = append(bpo, prev)
@ -221,7 +219,7 @@ func (k *Kademlia) SuggestPeer() (a *BzzAddr, o int, want bool) {
// try to select a candidate peer // try to select a candidate peer
// find the first callable peer // find the first callable peer
nxt := bpo[0] nxt := bpo[0]
k.addrs.EachBin(k.base, pof, nxt, func(po, _ int, f func(func(pot.Val, int) bool) bool) bool { k.addrs.EachBin(k.base, Pof, nxt, func(po, _ int, f func(func(pot.Val, int) bool) bool) bool {
// for each bin (up until depth) we find callable candidate peers // for each bin (up until depth) we find callable candidate peers
if po >= depth { if po >= depth {
return false return false
@ -253,7 +251,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) {
k.lock.Lock() k.lock.Lock()
defer k.lock.Unlock() defer k.lock.Unlock()
var ins bool var ins bool
k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(v pot.Val) pot.Val { k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(v pot.Val) pot.Val {
// if not found live // if not found live
if v == nil { if v == nil {
ins = true ins = true
@ -267,7 +265,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) {
a := newEntry(p.BzzAddr) a := newEntry(p.BzzAddr)
a.conn = p a.conn = p
// insert new online peer into addrs // insert new online peer into addrs
k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val {
return a return a
}) })
// send new address count value only if the peer is inserted // send new address count value only if the peer is inserted
@ -277,7 +275,7 @@ func (k *Kademlia) On(p *Peer) (uint8, bool) {
} }
log.Trace(k.string()) log.Trace(k.string())
// calculate if depth of saturation changed // calculate if depth of saturation changed
depth := uint8(k.saturation(k.MinBinSize)) depth := uint8(k.saturation())
var changed bool var changed bool
if depth != k.depth { if depth != k.depth {
changed = true changed = true
@ -333,7 +331,7 @@ func (k *Kademlia) Off(p *Peer) {
defer k.lock.Unlock() defer k.lock.Unlock()
var del bool var del bool
if !p.BzzPeer.LightNode { if !p.BzzPeer.LightNode {
k.addrs, _, _, _ = pot.Swap(k.addrs, p, pof, func(v pot.Val) pot.Val { k.addrs, _, _, _ = pot.Swap(k.addrs, p, Pof, func(v pot.Val) pot.Val {
// v cannot be nil, must check otherwise we overwrite entry // v cannot be nil, must check otherwise we overwrite entry
if v == nil { if v == nil {
panic(fmt.Sprintf("connected peer not found %v", p)) panic(fmt.Sprintf("connected peer not found %v", p))
@ -346,7 +344,7 @@ func (k *Kademlia) Off(p *Peer) {
} }
if del { if del {
k.conns, _, _, _ = pot.Swap(k.conns, p, pof, func(_ pot.Val) pot.Val { k.conns, _, _, _ = pot.Swap(k.conns, p, Pof, func(_ pot.Val) pot.Val {
// v cannot be nil, but no need to check // v cannot be nil, but no need to check
return nil return nil
}) })
@ -358,6 +356,10 @@ func (k *Kademlia) Off(p *Peer) {
} }
} }
// EachBin is a two level nested iterator
// The outer iterator returns all bins that have known peers, in order from shallowest to deepest
// The inner iterator returns all peers per bin returned by the outer iterator, in no defined order
// TODO the po returned by the inner iterator is not reliable. However, it is not being used in this method
func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn *Peer, po int) bool) { func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(conn *Peer, po int) bool) {
k.lock.RLock() k.lock.RLock()
defer k.lock.RUnlock() defer k.lock.RUnlock()
@ -366,7 +368,7 @@ func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(con
var endPo int var endPo int
kadDepth := depthForPot(k.conns, k.MinProxBinSize, k.base) kadDepth := depthForPot(k.conns, k.MinProxBinSize, k.base)
k.conns.EachBin(base, pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { k.conns.EachBin(base, Pof, o, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
if startPo > 0 && endPo != k.MaxProxDisplay { if startPo > 0 && endPo != k.MaxProxDisplay {
startPo = endPo + 1 startPo = endPo + 1
} }
@ -388,6 +390,7 @@ func (k *Kademlia) EachBin(base []byte, pof pot.Pof, o int, eachBinFunc func(con
// EachConn is an iterator with args (base, po, f) applies f to each live peer // EachConn is an iterator with args (base, po, f) applies f to each live peer
// that has proximity order po or less as measured from the base // that has proximity order po or less as measured from the base
// if base is nil, kademlia base address is used // if base is nil, kademlia base address is used
// It returns peers in order deepest to shallowest
func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int, bool) bool) { func (k *Kademlia) EachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
k.lock.RLock() k.lock.RLock()
defer k.lock.RUnlock() defer k.lock.RUnlock()
@ -399,7 +402,7 @@ func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
base = k.base base = k.base
} }
depth := depthForPot(k.conns, k.MinProxBinSize, k.base) depth := depthForPot(k.conns, k.MinProxBinSize, k.base)
k.conns.EachNeighbour(base, pof, func(val pot.Val, po int) bool { k.conns.EachNeighbour(base, Pof, func(val pot.Val, po int) bool {
if po > o { if po > o {
return true return true
} }
@ -408,8 +411,9 @@ func (k *Kademlia) eachConn(base []byte, o int, f func(*Peer, int, bool) bool) {
} }
// EachAddr called with (base, po, f) is an iterator applying f to each known peer // EachAddr called with (base, po, f) is an iterator applying f to each known peer
// that has proximity order po or less as measured from the base // that has proximity order o or less as measured from the base
// if base is nil, kademlia base address is used // if base is nil, kademlia base address is used
// It returns peers in order deepest to shallowest
func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) { func (k *Kademlia) EachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool) {
k.lock.RLock() k.lock.RLock()
defer k.lock.RUnlock() defer k.lock.RUnlock()
@ -421,7 +425,7 @@ func (k *Kademlia) eachAddr(base []byte, o int, f func(*BzzAddr, int, bool) bool
base = k.base base = k.base
} }
depth := depthForPot(k.conns, k.MinProxBinSize, k.base) depth := depthForPot(k.conns, k.MinProxBinSize, k.base)
k.addrs.EachNeighbour(base, pof, func(val pot.Val, po int) bool { k.addrs.EachNeighbour(base, Pof, func(val pot.Val, po int) bool {
if po > o { if po > o {
return true return true
} }
@ -447,11 +451,10 @@ func depthForPot(p *pot.Pot, minProxBinSize int, pivotAddr []byte) (depth int) {
// total number of peers in iteration // total number of peers in iteration
var size int var size int
// true if iteration has all prox peers // determining the depth is a two-step process
var b bool // first we find the proximity bin of the shallowest of the MinProxBinSize peers
// the numeric value of depth cannot be higher than this
// last po recorded in iteration var maxDepth int
var lastPo int
f := func(v pot.Val, i int) bool { f := func(v pot.Val, i int) bool {
// po == 256 means that addr is the pivot address(self) // po == 256 means that addr is the pivot address(self)
@ -463,38 +466,28 @@ func depthForPot(p *pot.Pot, minProxBinSize int, pivotAddr []byte) (depth int) {
// this means we have all nn-peers. // this means we have all nn-peers.
// depth is by default set to the bin of the farthest nn-peer // depth is by default set to the bin of the farthest nn-peer
if size == minProxBinSize { if size == minProxBinSize {
b = true maxDepth = i
depth = i
return true
}
// if there are empty bins between farthest nn and current node,
// the depth should recalculated to be
// the farthest of those empty bins
//
// 0 abac ccde
// 1 2a2a
// 2 589f <--- nearest non-nn
// ============ DEPTH 3 ===========
// 3 <--- don't count as empty bins
// 4 <--- don't count as empty bins
// 5 cbcb cdcd <---- furthest nn
// 6 a1a2 b3c4
if b && i < depth {
depth = i + 1
lastPo = i
return false return false
} }
lastPo = i
return true return true
} }
p.EachNeighbour(pivotAddr, pof, f) p.EachNeighbour(pivotAddr, Pof, f)
// cover edge case where more than one farthest nn // the second step is to test for empty bins in order from shallowest to deepest
// AND we only have nn-peers // if an empty bin is found, this will be the actual depth
if lastPo == depth { // we stop iterating if we hit the maxDepth determined in the first step
depth = 0 p.EachBin(pivotAddr, Pof, 0, func(po int, _ int, f func(func(pot.Val, int) bool) bool) bool {
if po == depth {
if maxDepth == depth {
return false
} }
depth++
return true
}
return false
})
return depth return depth
} }
@ -556,7 +549,7 @@ func (k *Kademlia) string() string {
depth := depthForPot(k.conns, k.MinProxBinSize, k.base) depth := depthForPot(k.conns, k.MinProxBinSize, k.base)
rest := k.conns.Size() rest := k.conns.Size()
k.conns.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { k.conns.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
var rowlen int var rowlen int
if po >= k.MaxProxDisplay { if po >= k.MaxProxDisplay {
po = k.MaxProxDisplay - 1 po = k.MaxProxDisplay - 1
@ -575,7 +568,7 @@ func (k *Kademlia) string() string {
return true return true
}) })
k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
var rowlen int var rowlen int
if po >= k.MaxProxDisplay { if po >= k.MaxProxDisplay {
po = k.MaxProxDisplay - 1 po = k.MaxProxDisplay - 1
@ -613,81 +606,74 @@ func (k *Kademlia) string() string {
return "\n" + strings.Join(rows, "\n") return "\n" + strings.Join(rows, "\n")
} }
// PeerPot keeps info about expected nearest neighbours and empty bins // PeerPot keeps info about expected nearest neighbours
// used for testing only // used for testing only
// TODO move to separate testing tools file
type PeerPot struct { type PeerPot struct {
NNSet [][]byte NNSet [][]byte
EmptyBins []int
} }
// NewPeerPotMap creates a map of pot record of *BzzAddr with keys // NewPeerPotMap creates a map of pot record of *BzzAddr with keys
// as hexadecimal representations of the address. // as hexadecimal representations of the address.
// the MinProxBinSize of the passed kademlia is used
// used for testing only // used for testing only
func NewPeerPotMap(kadMinProxSize int, addrs [][]byte) map[string]*PeerPot { // TODO move to separate testing tools file
func NewPeerPotMap(minProxBinSize int, addrs [][]byte) map[string]*PeerPot {
// create a table of all nodes for health check // create a table of all nodes for health check
np := pot.NewPot(nil, 0) np := pot.NewPot(nil, 0)
for _, addr := range addrs { for _, addr := range addrs {
np, _, _ = pot.Add(np, addr, pof) np, _, _ = pot.Add(np, addr, Pof)
} }
ppmap := make(map[string]*PeerPot) ppmap := make(map[string]*PeerPot)
// generate an allknowing source of truth for connections
// for every kademlia passed
for i, a := range addrs { for i, a := range addrs {
// actual kademlia depth // actual kademlia depth
depth := depthForPot(np, kadMinProxSize, a) depth := depthForPot(np, minProxBinSize, a)
// upon entering a new iteration
// this will hold the value the po should be
// if it's one higher than the po in the last iteration
prevPo := 256
// all empty bins which are outside neighbourhood depth
var emptyBins []int
// all nn-peers // all nn-peers
var nns [][]byte var nns [][]byte
np.EachNeighbour(a, pof, func(val pot.Val, po int) bool { // iterate through the neighbours, going from the deepest to the shallowest
np.EachNeighbour(a, Pof, func(val pot.Val, po int) bool {
addr := val.([]byte) addr := val.([]byte)
// po == 256 means that addr is the pivot address(self) // po == 256 means that addr is the pivot address(self)
// we do not include self in the map
if po == 256 { if po == 256 {
return true return true
} }
// append any neighbors found
// iterate through the neighbours, going from the closest to the farthest // a neighbor is any peer in or deeper than the depth
// we calculate the nearest neighbours that should be in the set
// depth in this case equates to:
// 1. Within all bins that are higher or equal than depth there are
// at least minProxBinSize peers connected
// 2. depth-1 bin is not empty
if po >= depth { if po >= depth {
nns = append(nns, addr) nns = append(nns, addr)
prevPo = depth - 1
return true return true
} }
for j := prevPo; j > po; j-- { return false
emptyBins = append(emptyBins, j)
}
prevPo = po - 1
return true
}) })
log.Trace(fmt.Sprintf("%x NNS: %s, emptyBins: %s", addrs[i][:4], LogAddrs(nns), logEmptyBins(emptyBins))) log.Trace(fmt.Sprintf("%x PeerPotMap NNS: %s", addrs[i][:4], LogAddrs(nns)))
ppmap[common.Bytes2Hex(a)] = &PeerPot{nns, emptyBins} ppmap[common.Bytes2Hex(a)] = &PeerPot{
NNSet: nns,
}
} }
return ppmap return ppmap
} }
// saturation returns the lowest proximity order that the bin for that order // saturation iterates through all peers and
// has less than n peers // returns the smallest po value in which the node has less than n peers
// It is used in Healthy function for testing only // if the iterator reaches depth, then value for depth is returned
func (k *Kademlia) saturation(n int) int { // TODO move to separate testing tools file
// TODO this function will stop at the first bin with less than MinBinSize peers, even if there are empty bins between that bin and the depth. This may not be correct behavior
func (k *Kademlia) saturation() int {
prev := -1 prev := -1
k.addrs.EachBin(k.base, pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool { k.addrs.EachBin(k.base, Pof, 0, func(po, size int, f func(func(val pot.Val, i int) bool) bool) bool {
prev++ prev++
return prev == po && size >= n return prev == po && size >= k.MinBinSize
}) })
// TODO evaluate whether this check cannot just as well be done within the eachbin
depth := depthForPot(k.conns, k.MinProxBinSize, k.base) depth := depthForPot(k.conns, k.MinProxBinSize, k.base)
if depth < prev { if depth < prev {
return depth return depth
@ -695,90 +681,74 @@ func (k *Kademlia) saturation(n int) int {
return prev return prev
} }
// full returns true if all required bins have connected peers. // knowNeighbours tests if all neighbours in the peerpot
// are found among the peers known to the kademlia
// It is used in Healthy function for testing only // It is used in Healthy function for testing only
func (k *Kademlia) full(emptyBins []int) (full bool) { // TODO move to separate testing tools file
prev := 0 func (k *Kademlia) knowNeighbours(addrs [][]byte) (got bool, n int, missing [][]byte) {
e := len(emptyBins)
ok := true
depth := depthForPot(k.conns, k.MinProxBinSize, k.base)
k.conns.EachBin(k.base, pof, 0, func(po, _ int, _ func(func(val pot.Val, i int) bool) bool) bool {
if po >= depth {
return false
}
if prev == depth+1 {
return true
}
for i := prev; i < po; i++ {
e--
if e < 0 {
ok = false
return false
}
if emptyBins[e] != i {
log.Trace(fmt.Sprintf("%08x po: %d, i: %d, e: %d, emptybins: %v", k.BaseAddr()[:4], po, i, e, logEmptyBins(emptyBins)))
if emptyBins[e] < i {
panic("incorrect peerpot")
}
ok = false
return false
}
}
prev = po + 1
return true
})
if !ok {
return false
}
return e == 0
}
// knowNearestNeighbours tests if all known nearest neighbours given as arguments
// are found in the addressbook
// It is used in Healthy function for testing only
func (k *Kademlia) knowNearestNeighbours(peers [][]byte) bool {
pm := make(map[string]bool) pm := make(map[string]bool)
// create a map with all peers at depth and deeper known in the kademlia
// in order deepest to shallowest compared to the kademlia base address
// all bins (except self) are included (0 <= bin <= 255)
depth := depthForPot(k.addrs, k.MinProxBinSize, k.base)
k.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool { k.eachAddr(nil, 255, func(p *BzzAddr, po int, nn bool) bool {
if !nn { if po < depth {
return false return false
} }
pk := fmt.Sprintf("%x", p.Address()) pk := common.Bytes2Hex(p.Address())
pm[pk] = true pm[pk] = true
return true return true
}) })
for _, p := range peers {
pk := fmt.Sprintf("%x", p)
if !pm[pk] {
log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.BaseAddr()[:4], pk[:8]))
return false
}
}
return true
}
// gotNearestNeighbours tests if all known nearest neighbours given as arguments // iterate through nearest neighbors in the peerpot map
// are connected peers // if we can't find the neighbor in the map we created above
// It is used in Healthy function for testing only // then we don't know all our neighbors
func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) { // (which sadly is all too common in modern society)
pm := make(map[string]bool)
k.eachConn(nil, 255, func(p *Peer, po int, nn bool) bool {
if !nn {
return false
}
pk := fmt.Sprintf("%x", p.Address())
pm[pk] = true
return true
})
var gots int var gots int
var culprits [][]byte var culprits [][]byte
for _, p := range peers { for _, p := range addrs {
pk := fmt.Sprintf("%x", p) pk := common.Bytes2Hex(p)
if pm[pk] { if pm[pk] {
gots++ gots++
} else { } else {
log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.BaseAddr()[:4], pk[:8])) log.Trace(fmt.Sprintf("%08x: known nearest neighbour %s not found", k.base, pk))
culprits = append(culprits, p)
}
}
return gots == len(addrs), gots, culprits
}
// connectedNeighbours tests if all neighbours in the peerpot
// are currently connected in the kademlia
// It is used in Healthy function for testing only
func (k *Kademlia) connectedNeighbours(peers [][]byte) (got bool, n int, missing [][]byte) {
pm := make(map[string]bool)
// create a map with all peers at depth and deeper that are connected in the kademlia
// in order deepest to shallowest compared to the kademlia base address
// all bins (except self) are included (0 <= bin <= 255)
depth := depthForPot(k.conns, k.MinProxBinSize, k.base)
k.eachConn(nil, 255, func(p *Peer, po int, nn bool) bool {
if po < depth {
return false
}
pk := common.Bytes2Hex(p.Address())
pm[pk] = true
return true
})
// iterate through nearest neighbors in the peerpot map
// if we can't find the neighbor in the map we created above
// then we don't know all our neighbors
var gots int
var culprits [][]byte
for _, p := range peers {
pk := common.Bytes2Hex(p)
if pm[pk] {
gots++
} else {
log.Trace(fmt.Sprintf("%08x: ExpNN: %s not found", k.base, pk))
culprits = append(culprits, p) culprits = append(culprits, p)
} }
} }
@ -788,31 +758,40 @@ func (k *Kademlia) gotNearestNeighbours(peers [][]byte) (got bool, n int, missin
// Health state of the Kademlia // Health state of the Kademlia
// used for testing only // used for testing only
type Health struct { type Health struct {
KnowNN bool // whether node knows all its nearest neighbours KnowNN bool // whether node knows all its neighbours
GotNN bool // whether node is connected to all its nearest neighbours CountKnowNN int // amount of neighbors known
CountNN int // amount of nearest neighbors connected to MissingKnowNN [][]byte // which neighbours we should have known but we don't
CulpritsNN [][]byte // which known NNs are missing ConnectNN bool // whether node is connected to all its neighbours
Full bool // whether node has a peer in each kademlia bin (where there is such a peer) CountConnectNN int // amount of neighbours connected to
MissingConnectNN [][]byte // which neighbours we should have been connected to but we're not
Saturated bool // whether we are connected to all the peers we would have liked to
Hive string Hive string
} }
// Healthy reports the health state of the kademlia connectivity // Healthy reports the health state of the kademlia connectivity
// returns a Health struct //
// The PeerPot argument provides an all-knowing view of the network
// The resulting Health object is a result of comparisons between
// what is the actual composition of the kademlia in question (the receiver), and
// what SHOULD it have been when we take all we know about the network into consideration.
//
// used for testing only // used for testing only
func (k *Kademlia) Healthy(pp *PeerPot) *Health { func (k *Kademlia) Healthy(pp *PeerPot) *Health {
k.lock.RLock() k.lock.RLock()
defer k.lock.RUnlock() defer k.lock.RUnlock()
gotnn, countnn, culpritsnn := k.gotNearestNeighbours(pp.NNSet) gotnn, countgotnn, culpritsgotnn := k.connectedNeighbours(pp.NNSet)
knownn := k.knowNearestNeighbours(pp.NNSet) knownn, countknownn, culpritsknownn := k.knowNeighbours(pp.NNSet)
full := k.full(pp.EmptyBins) depth := depthForPot(k.conns, k.MinProxBinSize, k.base)
log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, full: %v\n", k.BaseAddr()[:4], knownn, gotnn, full)) saturated := k.saturation() < depth
return &Health{knownn, gotnn, countnn, culpritsnn, full, k.string()} log.Trace(fmt.Sprintf("%08x: healthy: knowNNs: %v, gotNNs: %v, saturated: %v\n", k.base, knownn, gotnn, saturated))
} return &Health{
KnowNN: knownn,
func logEmptyBins(ebs []int) string { CountKnowNN: countknownn,
var ebss []string MissingKnowNN: culpritsknownn,
for _, eb := range ebs { ConnectNN: gotnn,
ebss = append(ebss, fmt.Sprintf("%d", eb)) CountConnectNN: countgotnn,
MissingConnectNN: culpritsgotnn,
Saturated: saturated,
Hive: k.string(),
} }
return strings.Join(ebss, ", ")
} }

View file

@ -41,12 +41,17 @@ func testKadPeerAddr(s string) *BzzAddr {
return &BzzAddr{OAddr: a, UAddr: a} return &BzzAddr{OAddr: a, UAddr: a}
} }
func newTestKademlia(b string) *Kademlia { func newTestKademliaParams() *KadParams {
params := NewKadParams() params := NewKadParams()
// TODO why is this 1?
params.MinBinSize = 1 params.MinBinSize = 1
params.MinProxBinSize = 2 params.MinProxBinSize = 2
return params
}
func newTestKademlia(b string) *Kademlia {
base := pot.NewAddressFromString(b) base := pot.NewAddressFromString(b)
return NewKademlia(base, params) return NewKademlia(base, newTestKademliaParams())
} }
func newTestKadPeer(k *Kademlia, s string, lightNode bool) *Peer { func newTestKadPeer(k *Kademlia, s string, lightNode bool) *Peer {
@ -89,65 +94,165 @@ func TestNeighbourhoodDepth(t *testing.T) {
baseAddress := pot.NewAddressFromBytes(baseAddressBytes) baseAddress := pot.NewAddressFromBytes(baseAddressBytes)
closerAddress := pot.RandomAddressAt(baseAddress, 7) // generate the peers
closerPeer := newTestDiscoveryPeer(closerAddress, kad) var peers []*Peer
kad.On(closerPeer) for i := 0; i < 7; i++ {
addr := pot.RandomAddressAt(baseAddress, i)
peers = append(peers, newTestDiscoveryPeer(addr, kad))
}
var sevenPeers []*Peer
for i := 0; i < 2; i++ {
addr := pot.RandomAddressAt(baseAddress, 7)
sevenPeers = append(sevenPeers, newTestDiscoveryPeer(addr, kad))
}
testNum := 0
// first try with empty kademlia
depth := kad.NeighbourhoodDepth() depth := kad.NeighbourhoodDepth()
if depth != 0 { if depth != 0 {
t.Fatalf("expected depth 0, was %d", depth) t.Fatalf("%d expected depth 0, was %d", testNum, depth)
} }
testNum++
sameAddress := pot.RandomAddressAt(baseAddress, 7) // add one peer on 7
samePeer := newTestDiscoveryPeer(sameAddress, kad) kad.On(sevenPeers[0])
kad.On(samePeer)
depth = kad.NeighbourhoodDepth() depth = kad.NeighbourhoodDepth()
if depth != 0 { if depth != 0 {
t.Fatalf("expected depth 0, was %d", depth) t.Fatalf("%d expected depth 0, was %d", testNum, depth)
} }
testNum++
midAddress := pot.RandomAddressAt(baseAddress, 4) // add a second on 7
midPeer := newTestDiscoveryPeer(midAddress, kad) kad.On(sevenPeers[1])
kad.On(midPeer)
depth = kad.NeighbourhoodDepth()
if depth != 5 {
t.Fatalf("expected depth 5, was %d", depth)
}
kad.Off(midPeer)
depth = kad.NeighbourhoodDepth() depth = kad.NeighbourhoodDepth()
if depth != 0 { if depth != 0 {
t.Fatalf("expected depth 0, was %d", depth) t.Fatalf("%d expected depth 0, was %d", testNum, depth)
} }
testNum++
fartherAddress := pot.RandomAddressAt(baseAddress, 1) // add from 0 to 6
fartherPeer := newTestDiscoveryPeer(fartherAddress, kad) for i, p := range peers {
kad.On(fartherPeer) kad.On(p)
depth = kad.NeighbourhoodDepth() depth = kad.NeighbourhoodDepth()
if depth != 2 { if depth != i+1 {
t.Fatalf("expected depth 2, was %d", depth) t.Fatalf("%d.%d expected depth %d, was %d", i+1, testNum, i, depth)
} }
midSameAddress := pot.RandomAddressAt(baseAddress, 4)
midSamePeer := newTestDiscoveryPeer(midSameAddress, kad)
kad.Off(closerPeer)
kad.On(midPeer)
kad.On(midSamePeer)
depth = kad.NeighbourhoodDepth()
if depth != 2 {
t.Fatalf("expected depth 2, was %d", depth)
} }
testNum++
kad.Off(fartherPeer) kad.Off(sevenPeers[1])
log.Trace(kad.string())
time.Sleep(time.Millisecond)
depth = kad.NeighbourhoodDepth() depth = kad.NeighbourhoodDepth()
if depth != 0 { if depth != 6 {
t.Fatalf("expected depth 0, was %d", depth) t.Fatalf("%d expected depth 6, was %d", testNum, depth)
}
testNum++
kad.Off(peers[4])
depth = kad.NeighbourhoodDepth()
if depth != 4 {
t.Fatalf("%d expected depth 4, was %d", testNum, depth)
}
testNum++
kad.Off(peers[3])
depth = kad.NeighbourhoodDepth()
if depth != 3 {
t.Fatalf("%d expected depth 3, was %d", testNum, depth)
}
testNum++
}
// TestHealthStrict tests the simplest definition of health
// Which means whether we are connected to all neighbors we know of
func TestHealthStrict(t *testing.T) {
// base address is all zeros
// no peers
// unhealthy (and lonely)
k := newTestKademlia("11111111")
assertHealth(t, k, false, false)
// know one peer but not connected
// unhealthy
Register(k, "11100000")
log.Trace(k.String())
assertHealth(t, k, false, false)
// know one peer and connected
// healthy
On(k, "11100000")
assertHealth(t, k, true, false)
// know two peers, only one connected
// unhealthy
Register(k, "11111100")
log.Trace(k.String())
assertHealth(t, k, false, false)
// know two peers and connected to both
// healthy
On(k, "11111100")
assertHealth(t, k, true, false)
// know three peers, connected to the two deepest
// healthy
Register(k, "00000000")
log.Trace(k.String())
assertHealth(t, k, true, false)
// know three peers, connected to all three
// healthy
On(k, "00000000")
assertHealth(t, k, true, false)
// add fourth peer deeper than current depth
// unhealthy
Register(k, "11110000")
log.Trace(k.String())
assertHealth(t, k, false, false)
// connected to three deepest peers
// healthy
On(k, "11110000")
assertHealth(t, k, true, false)
// add additional peer in same bin as deepest peer
// unhealthy
Register(k, "11111101")
log.Trace(k.String())
assertHealth(t, k, false, false)
// four deepest of five peers connected
// healthy
On(k, "11111101")
assertHealth(t, k, true, false)
}
func assertHealth(t *testing.T, k *Kademlia, expectHealthy bool, expectSaturation bool) {
t.Helper()
kid := common.Bytes2Hex(k.BaseAddr())
addrs := [][]byte{k.BaseAddr()}
k.EachAddr(nil, 255, func(addr *BzzAddr, po int, _ bool) bool {
addrs = append(addrs, addr.Address())
return true
})
pp := NewPeerPotMap(k.MinProxBinSize, addrs)
healthParams := k.Healthy(pp[kid])
// definition of health, all conditions but be true:
// - we at least know one peer
// - we know all neighbors
// - we are connected to all known neighbors
health := healthParams.KnowNN && healthParams.ConnectNN && healthParams.CountKnowNN > 0
if expectHealthy != health {
t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, k.String())
} }
} }
func testSuggestPeer(k *Kademlia, expAddr string, expPo int, expWant bool) error { func testSuggestPeer(k *Kademlia, expAddr string, expPo int, expWant bool) error {
addr, o, want := k.SuggestPeer() addr, o, want := k.SuggestPeer()
log.Trace("suggestpeer return", "a", addr, "o", o, "want", want)
if binStr(addr) != expAddr { if binStr(addr) != expAddr {
return fmt.Errorf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr)) return fmt.Errorf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr))
} }
@ -167,6 +272,7 @@ func binStr(a *BzzAddr) string {
return pot.ToBin(a.Address())[:8] return pot.ToBin(a.Address())[:8]
} }
// TODO explain why this bug occurred and how it should have been mitigated
func TestSuggestPeerBug(t *testing.T) { func TestSuggestPeerBug(t *testing.T) {
// 2 row gap, unsaturated proxbin, no callables -> want PO 0 // 2 row gap, unsaturated proxbin, no callables -> want PO 0
k := newTestKademlia("00000000") k := newTestKademlia("00000000")
@ -186,72 +292,98 @@ func TestSuggestPeerBug(t *testing.T) {
} }
func TestSuggestPeerFindPeers(t *testing.T) { func TestSuggestPeerFindPeers(t *testing.T) {
t.Skip("The SuggestPeers implementation seems to have weaknesses exposed by the change in the new depth calculation. The results are no longer predictable")
testnum := 0
// test 0
// 2 row gap, unsaturated proxbin, no callables -> want PO 0 // 2 row gap, unsaturated proxbin, no callables -> want PO 0
k := newTestKademlia("00000000") k := newTestKademlia("00000000")
On(k, "00100000") On(k, "00100000")
err := testSuggestPeer(k, "<nil>", 0, false) err := testSuggestPeer(k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 1
// 2 row gap, saturated proxbin, no callables -> want PO 0 // 2 row gap, saturated proxbin, no callables -> want PO 0
On(k, "00010000") On(k, "00010000")
err = testSuggestPeer(k, "<nil>", 0, false) err = testSuggestPeer(k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 2
// 1 row gap (1 less), saturated proxbin, no callables -> want PO 1 // 1 row gap (1 less), saturated proxbin, no callables -> want PO 1
On(k, "10000000") On(k, "10000000")
err = testSuggestPeer(k, "<nil>", 1, false) err = testSuggestPeer(k, "<nil>", 1, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 3
// no gap (1 less), saturated proxbin, no callables -> do not want more // no gap (1 less), saturated proxbin, no callables -> do not want more
On(k, "01000000", "00100001") On(k, "01000000", "00100001")
err = testSuggestPeer(k, "<nil>", 0, false) err = testSuggestPeer(k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 4
// oversaturated proxbin, > do not want more // oversaturated proxbin, > do not want more
On(k, "00100001") On(k, "00100001")
err = testSuggestPeer(k, "<nil>", 0, false) err = testSuggestPeer(k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 5
// reintroduce gap, disconnected peer callable // reintroduce gap, disconnected peer callable
Off(k, "01000000") Off(k, "01000000")
log.Trace(k.String())
err = testSuggestPeer(k, "01000000", 0, false) err = testSuggestPeer(k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 6
// second time disconnected peer not callable // second time disconnected peer not callable
// with reasonably set Interval // with reasonably set Interval
err = testSuggestPeer(k, "<nil>", 1, true) log.Trace("foo")
log.Trace(k.String())
err = testSuggestPeer(k, "<nil>", 1, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 6
// on and off again, peer callable again // on and off again, peer callable again
On(k, "01000000") On(k, "01000000")
Off(k, "01000000") Off(k, "01000000")
log.Trace(k.String())
err = testSuggestPeer(k, "01000000", 0, false) err = testSuggestPeer(k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
On(k, "01000000") // test 7
// new closer peer appears, it is immediately wanted // new closer peer appears, it is immediately wanted
On(k, "01000000")
Register(k, "00010001") Register(k, "00010001")
err = testSuggestPeer(k, "00010001", 0, false) err = testSuggestPeer(k, "00010001", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 8
// PO1 disconnects // PO1 disconnects
On(k, "00010001") On(k, "00010001")
log.Info(k.String()) log.Info(k.String())
@ -260,70 +392,94 @@ func TestSuggestPeerFindPeers(t *testing.T) {
// second time, gap filling // second time, gap filling
err = testSuggestPeer(k, "01000000", 0, false) err = testSuggestPeer(k, "01000000", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 9
On(k, "01000000") On(k, "01000000")
log.Info(k.String())
err = testSuggestPeer(k, "<nil>", 0, false) err = testSuggestPeer(k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 10
k.MinBinSize = 2 k.MinBinSize = 2
log.Info(k.String())
err = testSuggestPeer(k, "<nil>", 0, true) err = testSuggestPeer(k, "<nil>", 0, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 11
Register(k, "01000001") Register(k, "01000001")
log.Info(k.String())
err = testSuggestPeer(k, "01000001", 0, false) err = testSuggestPeer(k, "01000001", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 12
On(k, "10000001") On(k, "10000001")
log.Trace(fmt.Sprintf("Kad:\n%v", k.String())) log.Trace(fmt.Sprintf("Kad:\n%v", k.String()))
err = testSuggestPeer(k, "<nil>", 1, true) err = testSuggestPeer(k, "<nil>", 1, true)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 13
On(k, "01000001") On(k, "01000001")
err = testSuggestPeer(k, "<nil>", 0, false) err = testSuggestPeer(k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 14
k.MinBinSize = 3 k.MinBinSize = 3
Register(k, "10000010") Register(k, "10000010")
err = testSuggestPeer(k, "10000010", 0, false) err = testSuggestPeer(k, "10000010", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 15
On(k, "10000010") On(k, "10000010")
err = testSuggestPeer(k, "<nil>", 1, false) err = testSuggestPeer(k, "<nil>", 1, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 16
On(k, "01000010") On(k, "01000010")
err = testSuggestPeer(k, "<nil>", 2, false) err = testSuggestPeer(k, "<nil>", 2, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 17
On(k, "00100010") On(k, "00100010")
err = testSuggestPeer(k, "<nil>", 3, false) err = testSuggestPeer(k, "<nil>", 3, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
// test 18
On(k, "00010010") On(k, "00010010")
err = testSuggestPeer(k, "<nil>", 0, false) err = testSuggestPeer(k, "<nil>", 0, false)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatalf("%d %v", testnum, err.Error())
} }
testnum++
} }
@ -459,27 +615,28 @@ func TestKademliaHiveString(t *testing.T) {
// the SuggestPeer and Healthy methods for provided hex-encoded addresses. // the SuggestPeer and Healthy methods for provided hex-encoded addresses.
// Argument pivotAddr is the address of the kademlia. // Argument pivotAddr is the address of the kademlia.
func testKademliaCase(t *testing.T, pivotAddr string, addrs ...string) { func testKademliaCase(t *testing.T, pivotAddr string, addrs ...string) {
addr := common.FromHex(pivotAddr)
addrs = append(addrs, pivotAddr) t.Skip("this test relies on SuggestPeer which is now not reliable. See description in TestSuggestPeerFindPeers")
addr := common.Hex2Bytes(pivotAddr)
var byteAddrs [][]byte
for _, ahex := range addrs {
byteAddrs = append(byteAddrs, common.Hex2Bytes(ahex))
}
k := NewKademlia(addr, NewKadParams()) k := NewKademlia(addr, NewKadParams())
as := make([][]byte, len(addrs)) // our pivot kademlia is the last one in the array
for i, a := range addrs { for _, a := range byteAddrs {
as[i] = common.FromHex(a)
}
for _, a := range as {
if bytes.Equal(a, addr) { if bytes.Equal(a, addr) {
continue continue
} }
p := &BzzAddr{OAddr: a, UAddr: a} p := &BzzAddr{OAddr: a, UAddr: a}
if err := k.Register(p); err != nil { if err := k.Register(p); err != nil {
t.Fatal(err) t.Fatalf("a %x addr %x: %v", a, addr, err)
} }
} }
ppmap := NewPeerPotMap(2, as) ppmap := NewPeerPotMap(k.MinProxBinSize, byteAddrs)
pp := ppmap[pivotAddr] pp := ppmap[pivotAddr]
@ -492,7 +649,7 @@ func testKademliaCase(t *testing.T, pivotAddr string, addrs ...string) {
} }
h := k.Healthy(pp) h := k.Healthy(pp)
if !(h.GotNN && h.KnowNN && h.Full) { if !(h.ConnectNN && h.KnowNN && h.CountKnowNN > 0) {
t.Fatalf("not healthy: %#v\n%v", h, k.String()) t.Fatalf("not healthy: %#v\n%v", h, k.String())
} }
} }

View file

@ -35,8 +35,6 @@ import (
const ( const (
DefaultNetworkID = 3 DefaultNetworkID = 3
// ProtocolMaxMsgSize maximum allowed message size
ProtocolMaxMsgSize = 10 * 1024 * 1024
// timeout for waiting // timeout for waiting
bzzHandshakeTimeout = 3000 * time.Millisecond bzzHandshakeTimeout = 3000 * time.Millisecond
) )
@ -250,11 +248,6 @@ func NewBzzPeer(p *protocols.Peer) *BzzPeer {
return &BzzPeer{Peer: p, BzzAddr: NewAddr(p.Node())} return &BzzPeer{Peer: p, BzzAddr: NewAddr(p.Node())}
} }
// LastActive returns the time the peer was last active
func (p *BzzPeer) LastActive() time.Time {
return p.lastActive
}
// ID returns the peer's underlay node identifier. // ID returns the peer's underlay node identifier.
func (p *BzzPeer) ID() enode.ID { func (p *BzzPeer) ID() enode.ID {
// This is here to resolve a method tie: both protocols.Peer and BzzAddr are embedded // This is here to resolve a method tie: both protocols.Peer and BzzAddr are embedded

View file

@ -20,7 +20,6 @@ import (
"flag" "flag"
"fmt" "fmt"
"os" "os"
"sync"
"testing" "testing"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -44,31 +43,7 @@ func init() {
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
} }
type testStore struct {
sync.Mutex
values map[string][]byte
}
func (t *testStore) Load(key string) ([]byte, error) {
t.Lock()
defer t.Unlock()
v, ok := t.values[key]
if !ok {
return nil, fmt.Errorf("key not found: %s", key)
}
return v, nil
}
func (t *testStore) Save(key string, v []byte) error {
t.Lock()
defer t.Unlock()
t.values[key] = v
return nil
}
func HandshakeMsgExchange(lhs, rhs *HandshakeMsg, id enode.ID) []p2ptest.Exchange { func HandshakeMsgExchange(lhs, rhs *HandshakeMsg, id enode.ID) []p2ptest.Exchange {
return []p2ptest.Exchange{ return []p2ptest.Exchange{
{ {
Expects: []p2ptest.Expect{ Expects: []p2ptest.Expect{

View file

@ -21,7 +21,7 @@ import "github.com/ethereum/go-ethereum/p2p/enode"
// BucketKey is the type that should be used for keys in simulation buckets. // BucketKey is the type that should be used for keys in simulation buckets.
type BucketKey string type BucketKey string
// NodeItem returns an item set in ServiceFunc function for a particualar node. // NodeItem returns an item set in ServiceFunc function for a particular node.
func (s *Simulation) NodeItem(id enode.ID, key interface{}) (value interface{}, ok bool) { func (s *Simulation) NodeItem(id enode.ID, key interface{}) (value interface{}, ok bool) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()

View file

@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
) )
// TestServiceBucket tests all bucket functionalities using subtests. // TestServiceBucket tests all bucket functionality using subtests.
// It constructs a simulation of two nodes by adding items to their buckets // It constructs a simulation of two nodes by adding items to their buckets
// in ServiceFunc constructor, then by SetNodeItem. Testing UpNodesItems // in ServiceFunc constructor, then by SetNodeItem. Testing UpNodesItems
// is done by stopping one node and validating availability of its items. // is done by stopping one node and validating availability of its items.

View file

@ -25,7 +25,7 @@ import (
// Every node can have a Kademlia associated using the node bucket under // Every node can have a Kademlia associated using the node bucket under
// BucketKeyKademlia key. This allows to use WaitTillHealthy to block until // BucketKeyKademlia key. This allows to use WaitTillHealthy to block until
// all nodes have the their Kadmlias healthy. // all nodes have the their Kademlias healthy.
func ExampleSimulation_WaitTillHealthy() { func ExampleSimulation_WaitTillHealthy() {
log.Error("temporarily disabled as simulations.WaitTillHealthy cannot be trusted") log.Error("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")

View file

@ -28,7 +28,7 @@ import (
) )
// BucketKeyKademlia is the key to be used for storing the kademlia // BucketKeyKademlia is the key to be used for storing the kademlia
// instance for particuar node, usually inside the ServiceFunc function. // instance for particular node, usually inside the ServiceFunc function.
var BucketKeyKademlia BucketKey = "kademlia" var BucketKeyKademlia BucketKey = "kademlia"
// WaitTillHealthy is blocking until the health of all kademlias is true. // WaitTillHealthy is blocking until the health of all kademlias is true.
@ -39,6 +39,7 @@ func (s *Simulation) WaitTillHealthy(ctx context.Context, kadMinProxSize int) (i
var ppmap map[string]*network.PeerPot var ppmap map[string]*network.PeerPot
kademlias := s.kademlias() kademlias := s.kademlias()
addrs := make([][]byte, 0, len(kademlias)) addrs := make([][]byte, 0, len(kademlias))
// TODO verify that all kademlias have same params
for _, k := range kademlias { for _, k := range kademlias {
addrs = append(addrs, k.BaseAddr()) addrs = append(addrs, k.BaseAddr())
} }
@ -66,10 +67,10 @@ func (s *Simulation) WaitTillHealthy(ctx context.Context, kadMinProxSize int) (i
h := k.Healthy(pp) h := k.Healthy(pp)
//print info //print info
log.Debug(k.String()) log.Debug(k.String())
log.Debug("kademlia", "empty bins", pp.EmptyBins, "gotNN", h.GotNN, "knowNN", h.KnowNN, "full", h.Full) log.Debug("kademlia", "connectNN", h.ConnectNN, "knowNN", h.KnowNN)
log.Debug("kademlia", "health", h.GotNN && h.KnowNN && h.Full, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) log.Debug("kademlia", "health", h.ConnectNN && h.KnowNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id)
log.Debug("kademlia", "ill condition", !h.GotNN || !h.Full, "addr", hex.EncodeToString(k.BaseAddr()), "node", id) log.Debug("kademlia", "ill condition", !h.ConnectNN, "addr", hex.EncodeToString(k.BaseAddr()), "node", id)
if !h.GotNN || !h.Full { if !h.ConnectNN {
ill[id] = k ill[id] = k
} }
} }

View file

@ -195,9 +195,9 @@ func (s *Simulation) AddNodesAndConnectStar(count int, opts ...AddNodeOption) (i
return ids, nil return ids, nil
} }
//UploadSnapshot uploads a snapshot to the simulation // UploadSnapshot uploads a snapshot to the simulation
//This method tries to open the json file provided, applies the config to all nodes // This method tries to open the json file provided, applies the config to all nodes
//and then loads the snapshot into the Simulation network // and then loads the snapshot into the Simulation network
func (s *Simulation) UploadSnapshot(snapshotFile string, opts ...AddNodeOption) error { func (s *Simulation) UploadSnapshot(snapshotFile string, opts ...AddNodeOption) error {
f, err := os.Open(snapshotFile) f, err := os.Open(snapshotFile)
if err != nil { if err != nil {

View file

@ -65,8 +65,7 @@ type Simulation struct {
// after network shutdown. // after network shutdown.
type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error)
// New creates a new Simulation instance with new // New creates a new simulation instance
// simulations.Network initialized with provided services.
// Services map must have unique keys as service names and // Services map must have unique keys as service names and
// every ServiceFunc must return a node.Service of the unique type. // every ServiceFunc must return a node.Service of the unique type.
// This restriction is required by node.Node.Start() function // This restriction is required by node.Node.Start() function

View file

@ -26,10 +26,9 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/simulations"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/rpc" "github.com/mattn/go-colorable"
colorable "github.com/mattn/go-colorable"
) )
var ( var (
@ -178,43 +177,27 @@ var noopServiceFuncMap = map[string]ServiceFunc{
} }
// a helper function for most basic noop service // a helper function for most basic noop service
func noopServiceFunc(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { func noopServiceFunc(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) {
return newNoopService(), nil, nil return newNoopService(), nil, nil
} }
// noopService is the service that does not do anything
// but implements node.Service interface.
type noopService struct{}
func newNoopService() node.Service { func newNoopService() node.Service {
return &noopService{} return &noopService{}
} }
func (t *noopService) Protocols() []p2p.Protocol { // a helper function for most basic Noop service
return []p2p.Protocol{} // of a different type then NoopService to test
}
func (t *noopService) APIs() []rpc.API {
return []rpc.API{}
}
func (t *noopService) Start(server *p2p.Server) error {
return nil
}
func (t *noopService) Stop() error {
return nil
}
// a helper function for most basic noop service
// of a different type then noopService to test
// multiple services on one node. // multiple services on one node.
func noopService2Func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { func noopService2Func(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) {
return new(noopService2), nil, nil return new(noopService2), nil, nil
} }
// noopService2 is the service that does not do anything // NoopService2 is the service that does not do anything
// but implements node.Service interface. // but implements node.Service interface.
type noopService2 struct { type noopService2 struct {
noopService simulations.NoopService
}
type noopService struct {
simulations.NoopService
} }

View file

@ -31,6 +31,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
@ -156,6 +157,7 @@ func testDiscoverySimulationSimAdapter(t *testing.T, nodes, conns int) {
} }
func testDiscoverySimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) { func testDiscoverySimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) {
t.Skip("discovery tests depend on suggestpeer, which is unreliable after kademlia depth change.")
startedAt := time.Now() startedAt := time.Now()
result, err := discoverySimulation(nodes, conns, adapter) result, err := discoverySimulation(nodes, conns, adapter)
if err != nil { if err != nil {
@ -183,6 +185,7 @@ func testDiscoverySimulation(t *testing.T, nodes, conns int, adapter adapters.No
} }
func testDiscoveryPersistenceSimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) map[int][]byte { func testDiscoveryPersistenceSimulation(t *testing.T, nodes, conns int, adapter adapters.NodeAdapter) map[int][]byte {
t.Skip("discovery tests depend on suggestpeer, which is unreliable after kademlia depth change.")
persistenceEnabled = true persistenceEnabled = true
discoveryEnabled = true discoveryEnabled = true
@ -265,7 +268,7 @@ func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simul
wg.Wait() wg.Wait()
log.Debug(fmt.Sprintf("nodes: %v", len(addrs))) log.Debug(fmt.Sprintf("nodes: %v", len(addrs)))
// construct the peer pot, so that kademlia health can be checked // construct the peer pot, so that kademlia health can be checked
ppmap := network.NewPeerPotMap(testMinProxBinSize, addrs) ppmap := network.NewPeerPotMap(network.NewKadParams().MinProxBinSize, addrs)
check := func(ctx context.Context, id enode.ID) (bool, error) { check := func(ctx context.Context, id enode.ID) (bool, error) {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@ -281,12 +284,13 @@ func discoverySimulation(nodes, conns int, adapter adapters.NodeAdapter) (*simul
if err != nil { if err != nil {
return false, fmt.Errorf("error getting node client: %s", err) return false, fmt.Errorf("error getting node client: %s", err)
} }
healthy := &network.Health{} healthy := &network.Health{}
if err := client.Call(&healthy, "hive_healthy", ppmap[id.String()]); err != nil { if err := client.Call(&healthy, "hive_healthy", ppmap); err != nil {
return false, fmt.Errorf("error getting node health: %s", err) return false, fmt.Errorf("error getting node health: %s", err)
} }
log.Debug(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v, saturated: %v\n%v", id, healthy.GotNN, healthy.KnowNN, healthy.Full, healthy.Hive)) log.Info(fmt.Sprintf("node %4s healthy: connected nearest neighbours: %v, know nearest neighbours: %v,\n\n%v", id, healthy.ConnectNN, healthy.KnowNN, healthy.Hive))
return healthy.KnowNN && healthy.GotNN && healthy.Full, nil return healthy.KnowNN && healthy.ConnectNN, nil
} }
// 64 nodes ~ 1min // 64 nodes ~ 1min
@ -371,6 +375,7 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt
if err := triggerChecks(trigger, net, node.ID()); err != nil { if err := triggerChecks(trigger, net, node.ID()); err != nil {
return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err) return nil, fmt.Errorf("error triggering checks for node %s: %s", node.ID().TerminalString(), err)
} }
// TODO we shouldn't be equating underaddr and overaddr like this, as they are not the same in production
ids[i] = node.ID() ids[i] = node.ID()
a := ids[i].Bytes() a := ids[i].Bytes()
@ -379,7 +384,6 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt
// run a simulation which connects the 10 nodes in a ring and waits // run a simulation which connects the 10 nodes in a ring and waits
// for full peer discovery // for full peer discovery
ppmap := network.NewPeerPotMap(testMinProxBinSize, addrs)
var restartTime time.Time var restartTime time.Time
@ -400,12 +404,21 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt
} }
healthy := &network.Health{} healthy := &network.Health{}
addr := id.String() addr := id.String()
if err := client.Call(&healthy, "hive_healthy", ppmap[addr]); err != nil { ppmap := network.NewPeerPotMap(network.NewKadParams().MinProxBinSize, addrs)
if err := client.Call(&healthy, "hive_healthy", ppmap); err != nil {
return fmt.Errorf("error getting node health: %s", err) return fmt.Errorf("error getting node health: %s", err)
} }
log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.GotNN && healthy.KnowNN && healthy.Full)) log.Info(fmt.Sprintf("NODE: %s, IS HEALTHY: %t", addr, healthy.ConnectNN && healthy.KnowNN && healthy.CountKnowNN > 0))
if !healthy.GotNN || !healthy.Full { var nodeStr string
if err := client.Call(&nodeStr, "hive_string"); err != nil {
return fmt.Errorf("error getting node string %s", err)
}
log.Info(nodeStr)
for _, a := range addrs {
log.Info(common.Bytes2Hex(a))
}
if !healthy.ConnectNN || healthy.CountKnowNN == 0 {
isHealthy = false isHealthy = false
break break
} }
@ -479,12 +492,14 @@ func discoveryPersistenceSimulation(nodes, conns int, adapter adapters.NodeAdapt
return false, fmt.Errorf("error getting node client: %s", err) return false, fmt.Errorf("error getting node client: %s", err)
} }
healthy := &network.Health{} healthy := &network.Health{}
if err := client.Call(&healthy, "hive_healthy", ppmap[id.String()]); err != nil { ppmap := network.NewPeerPotMap(network.NewKadParams().MinProxBinSize, addrs)
if err := client.Call(&healthy, "hive_healthy", ppmap); err != nil {
return false, fmt.Errorf("error getting node health: %s", err) return false, fmt.Errorf("error getting node health: %s", err)
} }
log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v, saturated: %v", id, healthy.GotNN, healthy.KnowNN, healthy.Full)) log.Info(fmt.Sprintf("node %4s healthy: got nearest neighbours: %v, know nearest neighbours: %v", id, healthy.ConnectNN, healthy.KnowNN))
return healthy.KnowNN && healthy.GotNN && healthy.Full, nil return healthy.KnowNN && healthy.ConnectNN, nil
} }
// 64 nodes ~ 1min // 64 nodes ~ 1min

View file

@ -35,7 +35,6 @@ import (
p2ptest "github.com/ethereum/go-ethereum/p2p/testing" p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
"github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network"
"github.com/ethereum/go-ethereum/swarm/network/simulation" "github.com/ethereum/go-ethereum/swarm/network/simulation"
"github.com/ethereum/go-ethereum/swarm/pot"
"github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/state"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/testutil" "github.com/ethereum/go-ethereum/swarm/testutil"
@ -57,7 +56,7 @@ var (
bucketKeyRegistry = simulation.BucketKey("registry") bucketKeyRegistry = simulation.BucketKey("registry")
chunkSize = 4096 chunkSize = 4096
pof = pot.DefaultPof(256) pof = network.Pof
) )
func init() { func init() {

View file

@ -442,19 +442,17 @@ func TestStreamerDownstreamChunkDeliveryMsgExchange(t *testing.T) {
} }
func TestDeliveryFromNodes(t *testing.T) { func TestDeliveryFromNodes(t *testing.T) {
testDeliveryFromNodes(t, 2, 1, dataChunkCount, true) testDeliveryFromNodes(t, 2, dataChunkCount, true)
testDeliveryFromNodes(t, 2, 1, dataChunkCount, false) testDeliveryFromNodes(t, 2, dataChunkCount, false)
testDeliveryFromNodes(t, 4, 1, dataChunkCount, true) testDeliveryFromNodes(t, 4, dataChunkCount, true)
testDeliveryFromNodes(t, 4, 1, dataChunkCount, false) testDeliveryFromNodes(t, 4, dataChunkCount, false)
testDeliveryFromNodes(t, 8, 1, dataChunkCount, true) testDeliveryFromNodes(t, 8, dataChunkCount, true)
testDeliveryFromNodes(t, 8, 1, dataChunkCount, false) testDeliveryFromNodes(t, 8, dataChunkCount, false)
testDeliveryFromNodes(t, 16, 1, dataChunkCount, true) testDeliveryFromNodes(t, 16, dataChunkCount, true)
testDeliveryFromNodes(t, 16, 1, dataChunkCount, false) testDeliveryFromNodes(t, 16, dataChunkCount, false)
} }
func testDeliveryFromNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck bool) { func testDeliveryFromNodes(t *testing.T, nodes, chunkCount int, skipCheck bool) {
t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
sim := simulation.New(map[string]simulation.ServiceFunc{ sim := simulation.New(map[string]simulation.ServiceFunc{
"streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) {
node := ctx.Config.Node() node := ctx.Config.Node()
@ -543,6 +541,7 @@ func testDeliveryFromNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck
} }
log.Debug("Waiting for kademlia") log.Debug("Waiting for kademlia")
// TODO this does not seem to be correct usage of the function, as the simulation may have no kademlias
if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { if _, err := sim.WaitTillHealthy(ctx, 2); err != nil {
return err return err
} }
@ -610,7 +609,7 @@ func BenchmarkDeliveryFromNodesWithoutCheck(b *testing.B) {
b.Run( b.Run(
fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), fmt.Sprintf("nodes=%v,chunks=%v", i, chunks),
func(b *testing.B) { func(b *testing.B) {
benchmarkDeliveryFromNodes(b, i, 1, chunks, true) benchmarkDeliveryFromNodes(b, i, chunks, true)
}, },
) )
} }
@ -623,14 +622,14 @@ func BenchmarkDeliveryFromNodesWithCheck(b *testing.B) {
b.Run( b.Run(
fmt.Sprintf("nodes=%v,chunks=%v", i, chunks), fmt.Sprintf("nodes=%v,chunks=%v", i, chunks),
func(b *testing.B) { func(b *testing.B) {
benchmarkDeliveryFromNodes(b, i, 1, chunks, false) benchmarkDeliveryFromNodes(b, i, chunks, false)
}, },
) )
} }
} }
} }
func benchmarkDeliveryFromNodes(b *testing.B, nodes, conns, chunkCount int, skipCheck bool) { func benchmarkDeliveryFromNodes(b *testing.B, nodes, chunkCount int, skipCheck bool) {
sim := simulation.New(map[string]simulation.ServiceFunc{ sim := simulation.New(map[string]simulation.ServiceFunc{
"streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) {
node := ctx.Config.Node() node := ctx.Config.Node()

View file

@ -17,14 +17,11 @@
package intervals package intervals
import ( import (
"errors"
"testing" "testing"
"github.com/ethereum/go-ethereum/swarm/state" "github.com/ethereum/go-ethereum/swarm/state"
) )
var ErrNotFound = errors.New("not found")
// TestInmemoryStore tests basic functionality of InmemoryStore. // TestInmemoryStore tests basic functionality of InmemoryStore.
func TestInmemoryStore(t *testing.T) { func TestInmemoryStore(t *testing.T) {
testStore(t, state.NewInmemoryStore()) testStore(t, state.NewInmemoryStore())

View file

@ -53,7 +53,6 @@ func TestIntervalsLiveAndHistory(t *testing.T) {
func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) { func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) {
t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
nodes := 2 nodes := 2
chunkCount := dataChunkCount chunkCount := dataChunkCount
externalStreamName := "externalStream" externalStreamName := "externalStream"

View file

@ -246,7 +246,6 @@ simulation's `action` function.
The snapshot should have 'streamer' in its service list. The snapshot should have 'streamer' in its service list.
*/ */
func runRetrievalTest(chunkCount int, nodeCount int) error { func runRetrievalTest(chunkCount int, nodeCount int) error {
sim := simulation.New(retrievalSimServiceMap) sim := simulation.New(retrievalSimServiceMap)
defer sim.Close() defer sim.Close()

View file

@ -182,8 +182,6 @@ func streamerFunc(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Servic
} }
func testSyncingViaGlobalSync(t *testing.T, chunkCount int, nodeCount int) { func testSyncingViaGlobalSync(t *testing.T, chunkCount int, nodeCount int) {
t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
sim := simulation.New(simServiceMap) sim := simulation.New(simServiceMap)
defer sim.Close() defer sim.Close()
@ -332,7 +330,6 @@ kademlia network. The snapshot should have 'streamer' in its service list.
*/ */
func testSyncingViaDirectSubscribe(t *testing.T, chunkCount int, nodeCount int) error { func testSyncingViaDirectSubscribe(t *testing.T, chunkCount int, nodeCount int) error {
t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
sim := simulation.New(map[string]simulation.ServiceFunc{ sim := simulation.New(map[string]simulation.ServiceFunc{
"streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) {
n := ctx.Config.Node() n := ctx.Config.Node()
@ -555,9 +552,7 @@ func mapKeysToNodes(conf *synctestConfig) {
np, _, _ = pot.Add(np, a, pof) np, _, _ = pot.Add(np, a, pof)
} }
var kadMinProxSize = 2 ppmap := network.NewPeerPotMap(network.NewKadParams().MinProxBinSize, conf.addrs)
ppmap := network.NewPeerPotMap(kadMinProxSize, conf.addrs)
//for each address, run EachNeighbour on the chunk hashes pot to identify closest nodes //for each address, run EachNeighbour on the chunk hashes pot to identify closest nodes
log.Trace(fmt.Sprintf("Generated hash chunk(s): %v", conf.hashes)) log.Trace(fmt.Sprintf("Generated hash chunk(s): %v", conf.hashes))

View file

@ -388,14 +388,6 @@ func (r *Registry) Quit(peerId enode.ID, s Stream) error {
return peer.Send(context.TODO(), msg) return peer.Send(context.TODO(), msg)
} }
func (r *Registry) NodeInfo() interface{} {
return nil
}
func (r *Registry) PeerInfo(id enode.ID) interface{} {
return nil
}
func (r *Registry) Close() error { func (r *Registry) Close() error {
return r.intervalsStore.Close() return r.intervalsStore.Close()
} }

View file

@ -24,8 +24,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/crypto/sha3"
p2ptest "github.com/ethereum/go-ethereum/p2p/testing" p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
"golang.org/x/crypto/sha3"
) )
func TestStreamerSubscribe(t *testing.T) { func TestStreamerSubscribe(t *testing.T) {

View file

@ -127,17 +127,7 @@ func (s *SwarmSyncerServer) SetNextBatch(from, to uint64) ([]byte, uint64, uint6
// SwarmSyncerClient // SwarmSyncerClient
type SwarmSyncerClient struct { type SwarmSyncerClient struct {
sessionAt uint64
nextC chan struct{}
sessionRoot storage.Address
sessionReader storage.LazySectionReader
retrieveC chan *storage.Chunk
storeC chan *storage.Chunk
store storage.SyncChunkStore store storage.SyncChunkStore
// chunker storage.Chunker
currentRoot storage.Address
requestFunc func(chunk *storage.Chunk)
end, start uint64
peer *Peer peer *Peer
stream Stream stream Stream
} }
@ -209,46 +199,6 @@ func (s *SwarmSyncerClient) BatchDone(stream Stream, from uint64, hashes []byte,
return nil return nil
} }
func (s *SwarmSyncerClient) TakeoverProof(stream Stream, from uint64, hashes []byte, root storage.Address) (*TakeoverProof, error) {
// for provable syncer currentRoot is non-zero length
// TODO: reenable this with putter/getter
// if s.chunker != nil {
// if from > s.sessionAt { // for live syncing currentRoot is always updated
// //expRoot, err := s.chunker.Append(s.currentRoot, bytes.NewReader(hashes), s.retrieveC, s.storeC)
// expRoot, _, err := s.chunker.Append(s.currentRoot, bytes.NewReader(hashes), s.retrieveC)
// if err != nil {
// return nil, err
// }
// if !bytes.Equal(root, expRoot) {
// return nil, fmt.Errorf("HandoverProof mismatch")
// }
// s.currentRoot = root
// } else {
// expHashes := make([]byte, len(hashes))
// _, err := s.sessionReader.ReadAt(expHashes, int64(s.end*HashSize))
// if err != nil && err != io.EOF {
// return nil, err
// }
// if !bytes.Equal(expHashes, hashes) {
// return nil, errors.New("invalid proof")
// }
// }
// return nil, nil
// }
s.end += uint64(len(hashes)) / HashSize
takeover := &Takeover{
Stream: stream,
Start: s.start,
End: s.end,
Root: root,
}
// serialise and sign
return &TakeoverProof{
Takeover: takeover,
Sig: nil,
}, nil
}
func (s *SwarmSyncerClient) Close() {} func (s *SwarmSyncerClient) Close() {}
// base for parsing and formating sync bin key // base for parsing and formating sync bin key

View file

@ -43,10 +43,10 @@ import (
const dataChunkCount = 200 const dataChunkCount = 200
func TestSyncerSimulation(t *testing.T) { func TestSyncerSimulation(t *testing.T) {
testSyncBetweenNodes(t, 2, 1, dataChunkCount, true, 1) testSyncBetweenNodes(t, 2, dataChunkCount, true, 1)
testSyncBetweenNodes(t, 4, 1, dataChunkCount, true, 1) testSyncBetweenNodes(t, 4, dataChunkCount, true, 1)
testSyncBetweenNodes(t, 8, 1, dataChunkCount, true, 1) testSyncBetweenNodes(t, 8, dataChunkCount, true, 1)
testSyncBetweenNodes(t, 16, 1, dataChunkCount, true, 1) testSyncBetweenNodes(t, 16, dataChunkCount, true, 1)
} }
func createMockStore(globalStore mock.GlobalStorer, id enode.ID, addr *network.BzzAddr) (lstore storage.ChunkStore, datadir string, err error) { func createMockStore(globalStore mock.GlobalStorer, id enode.ID, addr *network.BzzAddr) (lstore storage.ChunkStore, datadir string, err error) {
@ -67,9 +67,8 @@ func createMockStore(globalStore mock.GlobalStorer, id enode.ID, addr *network.B
return lstore, datadir, nil return lstore, datadir, nil
} }
func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck bool, po uint8) { func testSyncBetweenNodes(t *testing.T, nodes, chunkCount int, skipCheck bool, po uint8) {
t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
sim := simulation.New(map[string]simulation.ServiceFunc{ sim := simulation.New(map[string]simulation.ServiceFunc{
"streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { "streamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) {
var store storage.ChunkStore var store storage.ChunkStore

View file

@ -96,7 +96,6 @@ func watchSim(sim *simulation.Simulation) (context.Context, context.CancelFunc)
//This test requests bogus hashes into the network //This test requests bogus hashes into the network
func TestNonExistingHashesWithServer(t *testing.T) { func TestNonExistingHashesWithServer(t *testing.T) {
t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
nodeCount, _, sim := setupSim(retrievalSimServiceMap) nodeCount, _, sim := setupSim(retrievalSimServiceMap)
defer sim.Close() defer sim.Close()
@ -211,6 +210,7 @@ func TestSnapshotSyncWithServer(t *testing.T) {
}, },
}).WithServer(":8888") //start with the HTTP server }).WithServer(":8888") //start with the HTTP server
nodeCount, chunkCount, sim := setupSim(simServiceMap)
defer sim.Close() defer sim.Close()
log.Info("Initializing test config") log.Info("Initializing test config")

View file

@ -260,7 +260,6 @@ type testSwarmNetworkOptions struct {
// - Checking if a file is retrievable from all nodes. // - Checking if a file is retrievable from all nodes.
func testSwarmNetwork(t *testing.T, o *testSwarmNetworkOptions, steps ...testSwarmNetworkStep) { func testSwarmNetwork(t *testing.T, o *testSwarmNetworkOptions, steps ...testSwarmNetworkStep) {
t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
if o == nil { if o == nil {
o = new(testSwarmNetworkOptions) o = new(testSwarmNetworkOptions)
} }

View file

@ -41,10 +41,6 @@ func NewAddressFromBytes(b []byte) Address {
return Address(h) return Address(h)
} }
func (a Address) IsZero() bool {
return a.Bin() == zerosBin
}
func (a Address) String() string { func (a Address) String() string {
return fmt.Sprintf("%x", a[:]) return fmt.Sprintf("%x", a[:])
} }

View file

@ -477,7 +477,7 @@ func (t *Pot) each(f func(Val, int) bool) bool {
return f(t.pin, t.po) return f(t.pin, t.po)
} }
// EachFrom called with (f, start) is a synchronous iterator over the elements of a Pot // eachFrom called with (f, start) is a synchronous iterator over the elements of a Pot
// within the inclusive range starting from proximity order start // within the inclusive range starting from proximity order start
// the function argument is passed the value and the proximity order wrt the root pin // the function argument is passed the value and the proximity order wrt the root pin
// it does NOT include the pinned item of the root // it does NOT include the pinned item of the root
@ -485,10 +485,6 @@ func (t *Pot) each(f func(Val, int) bool) bool {
// proximity > pinnedness // proximity > pinnedness
// the iteration ends if the function return false or there are no more elements // the iteration ends if the function return false or there are no more elements
// end of a po range can be implemented since po is passed to the function // end of a po range can be implemented since po is passed to the function
func (t *Pot) EachFrom(f func(Val, int) bool, po int) bool {
return t.eachFrom(f, po)
}
func (t *Pot) eachFrom(f func(Val, int) bool, po int) bool { func (t *Pot) eachFrom(f func(Val, int) bool, po int) bool {
var next bool var next bool
_, lim := t.getPos(po) _, lim := t.getPos(po)

View file

@ -0,0 +1,356 @@
package pss
import (
"fmt"
"math/rand"
"testing"
"time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/protocols"
"github.com/ethereum/go-ethereum/swarm/network"
"github.com/ethereum/go-ethereum/swarm/pot"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
)
type testCase struct {
name string
recipient []byte
peers []pot.Address
expected []int
exclusive bool
nFails int
success bool
errors string
}
var testCases []testCase
// the purpose of this test is to see that pss.forward() function correctly
// selects the peers for message forwarding, depending on the message address
// and kademlia constellation.
func TestForwardBasic(t *testing.T) {
baseAddrBytes := make([]byte, 32)
for i := 0; i < len(baseAddrBytes); i++ {
baseAddrBytes[i] = 0xFF
}
var c testCase
base := pot.NewAddressFromBytes(baseAddrBytes)
var peerAddresses []pot.Address
const depth = 10
for i := 0; i <= depth; i++ {
// add two peers for each proximity order
a := pot.RandomAddressAt(base, i)
peerAddresses = append(peerAddresses, a)
a = pot.RandomAddressAt(base, i)
peerAddresses = append(peerAddresses, a)
}
// skip one level, add one peer at one level deeper.
// as a result, we will have an edge case of three peers in nearest neighbours' bin.
peerAddresses = append(peerAddresses, pot.RandomAddressAt(base, depth+2))
kad := network.NewKademlia(base[:], network.NewKadParams())
ps := createPss(t, kad)
addPeers(kad, peerAddresses)
const firstNearest = depth * 2 // shallowest peer in the nearest neighbours' bin
nearestNeighbours := []int{firstNearest, firstNearest + 1, firstNearest + 2}
var all []int // indices of all the peers
for i := 0; i < len(peerAddresses); i++ {
all = append(all, i)
}
for i := 0; i < len(peerAddresses); i++ {
// send msg directly to the known peers (recipient address == peer address)
c = testCase{
name: fmt.Sprintf("Send direct to known, id: [%d]", i),
recipient: peerAddresses[i][:],
peers: peerAddresses,
expected: []int{i},
exclusive: false,
}
testCases = append(testCases, c)
}
for i := 0; i < firstNearest; i++ {
// send random messages with proximity orders, corresponding to PO of each bin,
// with one peer being closer to the recipient address
a := pot.RandomAddressAt(peerAddresses[i], 64)
c = testCase{
name: fmt.Sprintf("Send random to each PO, id: [%d]", i),
recipient: a[:],
peers: peerAddresses,
expected: []int{i},
exclusive: false,
}
testCases = append(testCases, c)
}
for i := 0; i < firstNearest; i++ {
// send random messages with proximity orders, corresponding to PO of each bin,
// with random proximity relative to the recipient address
po := i / 2
a := pot.RandomAddressAt(base, po)
c = testCase{
name: fmt.Sprintf("Send direct to known, id: [%d]", i),
recipient: a[:],
peers: peerAddresses,
expected: []int{po * 2, po*2 + 1},
exclusive: true,
}
testCases = append(testCases, c)
}
for i := firstNearest; i < len(peerAddresses); i++ {
// recipient address falls into the nearest neighbours' bin
a := pot.RandomAddressAt(base, i)
c = testCase{
name: fmt.Sprintf("recipient address falls into the nearest neighbours' bin, id: [%d]", i),
recipient: a[:],
peers: peerAddresses,
expected: nearestNeighbours,
exclusive: false,
}
testCases = append(testCases, c)
}
// send msg with proximity order much deeper than the deepest nearest neighbour
a2 := pot.RandomAddressAt(base, 77)
c = testCase{
name: "proximity order much deeper than the deepest nearest neighbour",
recipient: a2[:],
peers: peerAddresses,
expected: nearestNeighbours,
exclusive: false,
}
testCases = append(testCases, c)
// test with partial addresses
const part = 12
for i := 0; i < firstNearest; i++ {
// send messages with partial address falling into different proximity orders
po := i / 2
if i%8 != 0 {
c = testCase{
name: fmt.Sprintf("partial address falling into different proximity orders, id: [%d]", i),
recipient: peerAddresses[i][:i],
peers: peerAddresses,
expected: []int{po * 2, po*2 + 1},
exclusive: true,
}
testCases = append(testCases, c)
}
c = testCase{
name: fmt.Sprintf("extended partial address falling into different proximity orders, id: [%d]", i),
recipient: peerAddresses[i][:part],
peers: peerAddresses,
expected: []int{po * 2, po*2 + 1},
exclusive: true,
}
testCases = append(testCases, c)
}
for i := firstNearest; i < len(peerAddresses); i++ {
// partial address falls into the nearest neighbours' bin
c = testCase{
name: fmt.Sprintf("partial address falls into the nearest neighbours' bin, id: [%d]", i),
recipient: peerAddresses[i][:part],
peers: peerAddresses,
expected: nearestNeighbours,
exclusive: false,
}
testCases = append(testCases, c)
}
// partial address with proximity order deeper than any of the nearest neighbour
a3 := pot.RandomAddressAt(base, part)
c = testCase{
name: "partial address with proximity order deeper than any of the nearest neighbour",
recipient: a3[:part],
peers: peerAddresses,
expected: nearestNeighbours,
exclusive: false,
}
testCases = append(testCases, c)
// special cases where partial address matches a large group of peers
// zero bytes of address is given, msg should be delivered to all the peers
c = testCase{
name: "zero bytes of address is given",
recipient: []byte{},
peers: peerAddresses,
expected: all,
exclusive: false,
}
testCases = append(testCases, c)
// luminous radius of 8 bits, proximity order 8
indexAtPo8 := 16
c = testCase{
name: "luminous radius of 8 bits",
recipient: []byte{0xFF},
peers: peerAddresses,
expected: all[indexAtPo8:],
exclusive: false,
}
testCases = append(testCases, c)
// luminous radius of 256 bits, proximity order 8
a4 := pot.Address{}
a4[0] = 0xFF
c = testCase{
name: "luminous radius of 256 bits",
recipient: a4[:],
peers: peerAddresses,
expected: []int{indexAtPo8, indexAtPo8 + 1},
exclusive: true,
}
testCases = append(testCases, c)
// check correct behaviour in case send fails
for i := 2; i < firstNearest-3; i += 2 {
po := i / 2
// send random messages with proximity orders, corresponding to PO of each bin,
// with different numbers of failed attempts.
// msg should be received by only one of the deeper peers.
a := pot.RandomAddressAt(base, po)
c = testCase{
name: fmt.Sprintf("Send direct to known, id: [%d]", i),
recipient: a[:],
peers: peerAddresses,
expected: all[i+1:],
exclusive: true,
nFails: rand.Int()%3 + 2,
}
testCases = append(testCases, c)
}
for _, c := range testCases {
testForwardMsg(t, ps, &c)
}
}
// this function tests the forwarding of a single message. the recipient address is passed as param,
// along with addresses of all peers, and indices of those peers which are expected to receive the message.
func testForwardMsg(t *testing.T, ps *Pss, c *testCase) {
recipientAddr := c.recipient
peers := c.peers
expected := c.expected
exclusive := c.exclusive
nFails := c.nFails
tries := 0 // number of previous failed tries
resultMap := make(map[pot.Address]int)
defer func() { sendFunc = sendMsg }()
sendFunc = func(_ *Pss, sp *network.Peer, _ *PssMsg) bool {
if tries < nFails {
tries++
return false
}
a := pot.NewAddressFromBytes(sp.Address())
resultMap[a]++
return true
}
msg := newTestMsg(recipientAddr)
ps.forward(msg)
// check test results
var fail bool
precision := len(recipientAddr)
if precision > 4 {
precision = 4
}
s := fmt.Sprintf("test [%s]\nmsg address: %x..., radius: %d", c.name, recipientAddr[:precision], 8*len(recipientAddr))
// false negatives (expected message didn't reach peer)
if exclusive {
var cnt int
for _, i := range expected {
a := peers[i]
cnt += resultMap[a]
resultMap[a] = 0
}
if cnt != 1 {
s += fmt.Sprintf("\n%d messages received by %d peers with indices: [%v]", cnt, len(expected), expected)
fail = true
}
} else {
for _, i := range expected {
a := peers[i]
received := resultMap[a]
if received != 1 {
s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", i, a[:4], received)
fail = true
}
resultMap[a] = 0
}
}
// false positives (unexpected message reached peer)
for k, v := range resultMap {
if v != 0 {
// find the index of the false positive peer
var j int
for j = 0; j < len(peers); j++ {
if peers[j] == k {
break
}
}
s += fmt.Sprintf("\npeer number %d [%x...] received %d messages", j, k[:4], v)
fail = true
}
}
if fail {
t.Fatal(s)
}
}
func addPeers(kad *network.Kademlia, addresses []pot.Address) {
for _, a := range addresses {
p := newTestDiscoveryPeer(a, kad)
kad.On(p)
}
}
func createPss(t *testing.T, kad *network.Kademlia) *Pss {
privKey, err := crypto.GenerateKey()
pssp := NewPssParams().WithPrivateKey(privKey)
ps, err := NewPss(kad, pssp)
if err != nil {
t.Fatal(err.Error())
}
return ps
}
func newTestDiscoveryPeer(addr pot.Address, kad *network.Kademlia) *network.Peer {
rw := &p2p.MsgPipeRW{}
p := p2p.NewPeer(enode.ID{}, "test", []p2p.Cap{})
pp := protocols.NewPeer(p, rw, &protocols.Spec{})
bp := &network.BzzPeer{
Peer: pp,
BzzAddr: &network.BzzAddr{
OAddr: addr.Bytes(),
UAddr: []byte(fmt.Sprintf("%x", addr[:])),
},
}
return network.NewPeer(bp, kad)
}
func newTestMsg(addr []byte) *PssMsg {
msg := newPssMsg(&msgParams{})
msg.To = addr[:]
msg.Expire = uint32(time.Now().Add(time.Second * 60).Unix())
msg.Payload = &whisper.Envelope{
Topic: [4]byte{},
Data: []byte("i have nothing to hide"),
}
return msg
}

View file

@ -29,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
@ -40,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/swarm/pot" "github.com/ethereum/go-ethereum/swarm/pot"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -187,7 +187,7 @@ func NewPss(k *network.Kademlia, params *PssParams) (*Pss, error) {
hashPool: sync.Pool{ hashPool: sync.Pool{
New: func() interface{} { New: func() interface{} {
return sha3.NewKeccak256() return sha3.NewLegacyKeccak256()
}, },
}, },
} }
@ -513,7 +513,7 @@ func (p *Pss) isSelfPossibleRecipient(msg *PssMsg, prox bool) bool {
} }
depth := p.Kademlia.NeighbourhoodDepth() depth := p.Kademlia.NeighbourhoodDepth()
po, _ := p.Kademlia.Pof(p.Kademlia.BaseAddr(), msg.To, 0) po, _ := network.Pof(p.Kademlia.BaseAddr(), msg.To, 0)
log.Trace("selfpossible", "po", po, "depth", depth) log.Trace("selfpossible", "po", po, "depth", depth)
return depth <= po return depth <= po
@ -891,68 +891,97 @@ func (p *Pss) send(to []byte, topic Topic, msg []byte, asymmetric bool, key []by
return nil return nil
} }
// Forwards a pss message to the peer(s) closest to the to recipient address in the PssMsg struct // sendFunc is a helper function that tries to send a message and returns true on success.
// The recipient address can be of any length, and the byte slice will be matched to the MSB slice // It is set here for usage in production, and optionally overridden in tests.
// of the peer address of the equivalent length. var sendFunc func(p *Pss, sp *network.Peer, msg *PssMsg) bool = sendMsg
func (p *Pss) forward(msg *PssMsg) error {
metrics.GetOrRegisterCounter("pss.forward", nil).Inc(1)
to := make([]byte, addressLength) // tries to send a message, returns true if successful
copy(to[:len(msg.To)], msg.To) func sendMsg(p *Pss, sp *network.Peer, msg *PssMsg) bool {
var isPssEnabled bool
// send with kademlia
// find the closest peer to the recipient and attempt to send
sent := 0
p.Kademlia.EachConn(to, 256, func(sp *network.Peer, po int, isproxbin bool) bool {
info := sp.Info() info := sp.Info()
for _, capability := range info.Caps {
// check if the peer is running pss if capability == p.capstring {
var ispss bool isPssEnabled = true
for _, cap := range info.Caps {
if cap == p.capstring {
ispss = true
break break
} }
} }
if !ispss { if !isPssEnabled {
log.Trace("peer doesn't have matching pss capabilities, skipping", "peer", info.Name, "caps", info.Caps) log.Error("peer doesn't have matching pss capabilities, skipping", "peer", info.Name, "caps", info.Caps)
return true return false
} }
// get the protocol peer from the forwarding peer cache // get the protocol peer from the forwarding peer cache
sendMsg := fmt.Sprintf("MSG TO %x FROM %x VIA %x", to, p.BaseAddr(), sp.Address())
p.fwdPoolMu.RLock() p.fwdPoolMu.RLock()
pp := p.fwdPool[sp.Info().ID] pp := p.fwdPool[sp.Info().ID]
p.fwdPoolMu.RUnlock() p.fwdPoolMu.RUnlock()
// attempt to send the message
err := pp.Send(context.TODO(), msg) err := pp.Send(context.TODO(), msg)
if err != nil { if err != nil {
metrics.GetOrRegisterCounter("pss.pp.send.error", nil).Inc(1) metrics.GetOrRegisterCounter("pss.pp.send.error", nil).Inc(1)
log.Error(err.Error()) log.Error(err.Error())
return true
} }
sent++
log.Trace(fmt.Sprintf("%v: successfully forwarded", sendMsg))
// continue forwarding if: return err == nil
// - if the peer is end recipient but the full address has not been disclosed }
// - if the peer address matches the partial address fully
// - if the peer is in proxbin // Forwards a pss message to the peer(s) based on recipient address according to the algorithm
if len(msg.To) < addressLength && bytes.Equal(msg.To, sp.Address()[:len(msg.To)]) { // described below. The recipient address can be of any length, and the byte slice will be matched
log.Trace(fmt.Sprintf("Pss keep forwarding: Partial address + full partial match")) // to the MSB slice of the peer address of the equivalent length.
return true //
} else if isproxbin { // If the recipient address (or partial address) is within the neighbourhood depth of the forwarding
log.Trace(fmt.Sprintf("%x is in proxbin, keep forwarding", common.ToHex(sp.Address()))) // node, then it will be forwarded to all the nearest neighbours of the forwarding node. In case of
return true // partial address, it should be forwarded to all the peers matching the partial address, if there
// are any; otherwise only to one peer, closest to the recipient address. In any case, if the message
// forwarding fails, the node should try to forward it to the next best peer, until the message is
// successfully forwarded to at least one peer.
func (p *Pss) forward(msg *PssMsg) error {
metrics.GetOrRegisterCounter("pss.forward", nil).Inc(1)
sent := 0 // number of successful sends
to := make([]byte, addressLength)
copy(to[:len(msg.To)], msg.To)
neighbourhoodDepth := p.Kademlia.NeighbourhoodDepth()
// luminosity is the opposite of darkness. the more bytes are removed from the address, the higher is darkness,
// but the luminosity is less. here luminosity equals the number of bits given in the destination address.
luminosityRadius := len(msg.To) * 8
// proximity order function matching up to neighbourhoodDepth bits (po <= neighbourhoodDepth)
pof := pot.DefaultPof(neighbourhoodDepth)
// soft threshold for msg broadcast
broadcastThreshold, _ := pof(to, p.BaseAddr(), 0)
if broadcastThreshold > luminosityRadius {
broadcastThreshold = luminosityRadius
} }
// at this point we stop forwarding, and the state is as follows:
// - the peer is end recipient and we have full address var onlySendOnce bool // indicates if the message should only be sent to one peer with closest address
// - we are not in proxbin (directed routing)
// - partial addresses don't fully match // if measured from the recipient address as opposed to the base address (see Kademlia.EachConn
// call below), then peers that fall in the same proximity bin as recipient address will appear
// [at least] one bit closer, but only if these additional bits are given in the recipient address.
if broadcastThreshold < luminosityRadius && broadcastThreshold < neighbourhoodDepth {
broadcastThreshold++
onlySendOnce = true
}
p.Kademlia.EachConn(to, addressLength*8, func(sp *network.Peer, po int, _ bool) bool {
if po < broadcastThreshold && sent > 0 {
return false // stop iterating
}
if sendFunc(p, sp, msg) {
sent++
if onlySendOnce {
return false return false
}
if po == addressLength*8 {
// stop iterating if successfully sent to the exact recipient (perfect match of full address)
return false
}
}
return true
}) })
// if we failed to send to anyone, re-insert message in the send-queue
if sent == 0 { if sent == 0 {
log.Debug("unable to forward to any peers") log.Debug("unable to forward to any peers")
if err := p.enqueue(msg); err != nil { if err := p.enqueue(msg); err != nil {

View file

@ -1,28 +0,0 @@
// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package swarm
type Voidstore struct {
}
func (self Voidstore) Load(string) ([]byte, error) {
return nil, nil
}
func (self Voidstore) Save(string, []byte) error {
return nil
}

View file

@ -28,9 +28,6 @@ import (
// ErrNotFound is returned when no results are returned from the database // ErrNotFound is returned when no results are returned from the database
var ErrNotFound = errors.New("ErrorNotFound") var ErrNotFound = errors.New("ErrorNotFound")
// ErrInvalidArgument is returned when the argument type does not match the expected type
var ErrInvalidArgument = errors.New("ErrorInvalidArgument")
// Store defines methods required to get, set, delete values for different keys // Store defines methods required to get, set, delete values for different keys
// and close the underlying resources. // and close the underlying resources.
type Store interface { type Store interface {

View file

@ -65,10 +65,6 @@ If all is well it is possible to implement this by simply composing readers so t
The hashing itself does use extra copies and allocation though, since it does need it. The hashing itself does use extra copies and allocation though, since it does need it.
*/ */
var (
errAppendOppNotSuported = errors.New("Append operation not supported")
)
type ChunkerParams struct { type ChunkerParams struct {
chunkSize int64 chunkSize int64
hashSize int64 hashSize int64
@ -99,7 +95,6 @@ type TreeChunker struct {
ctx context.Context ctx context.Context
branches int64 branches int64
hashFunc SwarmHasher
dataSize int64 dataSize int64
data io.Reader data io.Reader
// calculated // calculated
@ -365,10 +360,6 @@ func (tc *TreeChunker) runWorker(ctx context.Context) {
}() }()
} }
func (tc *TreeChunker) Append() (Address, func(), error) {
return nil, nil, errAppendOppNotSuported
}
// LazyChunkReader implements LazySectionReader // LazyChunkReader implements LazySectionReader
type LazyChunkReader struct { type LazyChunkReader struct {
ctx context.Context ctx context.Context
@ -411,7 +402,6 @@ func (r *LazyChunkReader) Size(ctx context.Context, quitC chan bool) (n int64, e
log.Debug("lazychunkreader.size", "addr", r.addr) log.Debug("lazychunkreader.size", "addr", r.addr)
if r.chunkData == nil { if r.chunkData == nil {
startTime := time.Now() startTime := time.Now()
chunkData, err := r.getter.Get(cctx, Reference(r.addr)) chunkData, err := r.getter.Get(cctx, Reference(r.addr))
if err != nil { if err != nil {
@ -420,13 +410,8 @@ func (r *LazyChunkReader) Size(ctx context.Context, quitC chan bool) (n int64, e
} }
metrics.GetOrRegisterResettingTimer("lcr.getter.get", nil).UpdateSince(startTime) metrics.GetOrRegisterResettingTimer("lcr.getter.get", nil).UpdateSince(startTime)
r.chunkData = chunkData r.chunkData = chunkData
s := r.chunkData.Size()
log.Debug("lazychunkreader.size", "key", r.addr, "size", s)
if s < 0 {
return 0, errors.New("corrupt size")
}
return int64(s), nil
} }
s := r.chunkData.Size() s := r.chunkData.Size()
log.Debug("lazychunkreader.size", "key", r.addr, "size", s) log.Debug("lazychunkreader.size", "key", r.addr, "size", s)

View file

@ -24,8 +24,8 @@ import (
"io" "io"
"testing" "testing"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/swarm/testutil" "github.com/ethereum/go-ethereum/swarm/testutil"
"golang.org/x/crypto/sha3"
) )
/* /*
@ -142,7 +142,7 @@ func TestSha3ForCorrectness(t *testing.T) {
io.LimitReader(bytes.NewReader(input[8:]), int64(size)) io.LimitReader(bytes.NewReader(input[8:]), int64(size))
rawSha3 := sha3.NewKeccak256() rawSha3 := sha3.NewLegacyKeccak256()
rawSha3.Reset() rawSha3.Reset()
rawSha3.Write(input) rawSha3.Write(input)
rawSha3Output := rawSha3.Sum(nil) rawSha3Output := rawSha3.Sum(nil)

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