commit
75d0463426
@ -0,0 +1,3 @@ |
||||
{ |
||||
"key": "CAASpgkwggSiAgEAAoIBAQDhLRM7P8O8U9x+iXoxU+XOv5ihLVe+83he8jVoXp64QHZJQViYj//Wer2qDPeW7hHSC9FU7jsTOBcx3s46Z/4fS+rcXUtGQptscJywjh8wkadSoM8WwnLYIcRIpzI0nbt7wFRUOtwsLhR6/wb2l0qXiygmQn0l+byRQs7Jl1ZwleVetDik/QFGGz8NHFCl2PWNSkkJBOsy2zDGhiInK83qVADlyCP7roLgUe55W625OJ34f9iD7H+/A8UXi7n7BpTmLLDLVS1yeap0Jrftl7fA6s3hDVcNrBBDxsZuntEuKe+5fq6jb4Lj/iHzDoW/mkVWsURR2dIghBCe79cTUjhBAgMBAAECggEAOmOX0wtL1C/iwyUe/F+G/b+M8m5xjGBR3DzuQGwYuCpvAbviH11nt9QIDmpiYU7GbDMISv+jbe5jhVkDHP4OVUs4UYAXntZyuwHQf6+6wrtiKfjs+jfd09GdtkE0sZQdI4/Rzi2dHg+s29/5jEPa4cUB2jnvfcNudDRgrsGBdpvLZCbDm99PAn0z4gV8TZ+JxgMYG3obHjxWbHoyVHXkisM+WDsXaqOsE4xx40P3CevKsbrYYC7la5N/gt4RhkkMF8QGFpiMYHsO8PYxTYpNdZNUgfxLMDqvlUzBhzYE90y+a4bL2rflA+3JI9bfHKFqW0T14QXr8P/s9SqYPd1rgQKBgQDwj+ry71L++Koppct0qnu/IW+sZpw9Oydcaw128fWnEuX/VJR1DR/pBMisCHJwGGBqGQqZntw4Ajg7ZoYx7nlpUv9m5l8GTwS2IrmDkY1gri4qRw2ipzDCah+6mNQeys4B7LbQqbSATdeOQDbbbjJHTreAjts2V+bMx/Tep0G76QKBgQDvoGLmZ39dO5KM7yTG2GM3mmOadOHBk3GY/gjCm43PVtC4RePCIKyRX4UzYZuvmvT++Y5XSH91pVdoNqWY2vOhfBjNufV5tGHkUdTPy5yB6t2B/RvbYOEzZdWU+sQYl+/0EAI8IjoI8j2jnKr4giVVbEhxRU1o2lyj9nDmwpFamQKBgEC+GveC3Y1tky5eRqGBeIh6EToO66G3F+LRlPAcMobimS/crY/LFnl6Jh/WriXpCZnEX4v0q0QPpN6nuxoZGmf0RHSHL6/c+GGketUkCS6p8hbCxLKv2HmaYiuwEfavkj4GXTVPVxro2Eiak6j+wV1bnBtnVywLADzA2/BIh3JxAoGAH95oyNPC8JdXqj6z2W4149M4o/YfgCsn1H0UlS0y8vxMzfUdkVffG4ZkpKy6k+Q76R0vfRQ7P145/bYm1+lmtXdXpSSyLPl8e20WrHwb2Htv8jXDWq3LxZYpjaK8KbkrRH5MjcrPhRkScYwIgPxuEqpQCCB7ZxKDd5ry8P23byECgYBTXNVyeGqn5gBR1zdHzyg8qrUr39oerWqc+ejeDJgXp4HSYmXz7g1KuuE2OgVcOo/gpL13Acjc7neHGHnI20Aa3v5vh3gPohY5lgGy3AIoe0doedhkIUtqWjYkq+bmrrYUf2NG6iNOmjbqjUNBuxuIxlUomvgH+5PqBwGh0yKRMQ==" |
||||
} |
@ -0,0 +1,39 @@ |
||||
[default] |
||||
bootnode = /ip4/100.26.90.187/tcp/9876/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9 |
||||
bootnode = /ip4/54.213.43.194/tcp/9876/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX |
||||
shards = 1 |
||||
|
||||
[default.shard0.rpc] |
||||
rpc = 34.217.179.222:14555 |
||||
rpc = 18.209.247.105:14555 |
||||
rpc = 100.25.248.42:14555 |
||||
rpc = 3.80.164.193:14555 |
||||
rpc = 54.87.237.93:14555 |
||||
|
||||
[local] |
||||
bootnode = /ip4/127.0.0.1/tcp/19876/p2p/Qmc1V6W7BwX8Ugb42Ti8RnXF1rY5PF7nnZ6bKBryCgi6cv |
||||
shards = 1 |
||||
|
||||
[local.shard0.rpc] |
||||
rpc = 127.0.0.1:14555 |
||||
rpc = 127.0.0.1:14556 |
||||
|
||||
[devnet] |
||||
bootnode = /ip4/100.26.90.187/tcp/9871/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv |
||||
bootnode = /ip4/54.213.43.194/tcp/9871/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj |
||||
shards = 3 |
||||
|
||||
[devnet.shard0.rpc] |
||||
rpc = 13.57.196.136:14555 |
||||
rpc = 35.175.103.144:14555 |
||||
rpc = 54.245.176.36:14555 |
||||
|
||||
[devnet.shard1.rpc] |
||||
rpc = 35.163.188.234:14555 |
||||
rpc = 54.215.251.123:14555 |
||||
rpc = 54.153.11.146:14555 |
||||
|
||||
[devnet.shard2.rpc] |
||||
rpc = 52.201.246.212:14555 |
||||
rpc = 3.81.26.139:14555 |
||||
rpc = 18.237.42.209:14555 |
@ -0,0 +1,124 @@ |
||||
// Package ctxerror provides a context-aware error facility.
|
||||
//
|
||||
// Inspired by log15-style (semi-)structured logging,
|
||||
// it also provides a log15 bridge.
|
||||
package ctxerror |
||||
|
||||
//go:generate mockgen -source ctxerror.go -destination mock/ctxerror.go
|
||||
|
||||
import ( |
||||
"fmt" |
||||
) |
||||
|
||||
// CtxError is a context-aware error container.
|
||||
type CtxError interface { |
||||
// Error returns a fully formatted message, with context info.
|
||||
Error() string |
||||
|
||||
// Message returns the bare error message, without context info.
|
||||
Message() string |
||||
|
||||
// Contexts returns message contexts.
|
||||
// Caller shall not modify the returned map.
|
||||
Contexts() map[string]interface{} |
||||
|
||||
// WithCause chains an error after the receiver.
|
||||
// It returns the merged/chained instance,
|
||||
// where the message is "<receiver.Message>: <c.Message>",
|
||||
// and with contexts merged (ones in c takes precedence).
|
||||
WithCause(c error) CtxError |
||||
} |
||||
|
||||
type ctxError struct { |
||||
msg string |
||||
ctx map[string]interface{} |
||||
} |
||||
|
||||
// New creates and returns a new context-aware error.
|
||||
func New(msg string, ctx ...interface{}) CtxError { |
||||
e := &ctxError{msg: msg, ctx: make(map[string]interface{})} |
||||
e.updateCtx(ctx...) |
||||
return e |
||||
} |
||||
|
||||
func (e *ctxError) updateCtx(ctx ...interface{}) { |
||||
var name string |
||||
if len(ctx)%2 == 1 { |
||||
ctx = append(ctx, nil) |
||||
} |
||||
for idx, value := range ctx { |
||||
if idx%2 == 0 { |
||||
name = value.(string) |
||||
} else { |
||||
e.ctx[name] = value |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Error returns a fully formatted message, with context info.
|
||||
func (e *ctxError) Error() string { |
||||
s := e.msg |
||||
for k, v := range e.ctx { |
||||
s += fmt.Sprintf(", %s=%#v", k, v) |
||||
} |
||||
return s |
||||
} |
||||
|
||||
// Message returns the bare error message, without context info.
|
||||
func (e *ctxError) Message() string { |
||||
return e.msg |
||||
} |
||||
|
||||
// Contexts returns message contexts.
|
||||
// Caller shall not modify the returned map.
|
||||
func (e *ctxError) Contexts() map[string]interface{} { |
||||
return e.ctx |
||||
} |
||||
|
||||
// WithCause chains an error after the receiver.
|
||||
// It returns the merged/chained instance,
|
||||
// where the message is “<receiver.Message>: <c.Message>”,
|
||||
// and with contexts merged (ones in c takes precedence).
|
||||
func (e *ctxError) WithCause(c error) CtxError { |
||||
r := &ctxError{msg: e.msg + ": ", ctx: make(map[string]interface{})} |
||||
for k, v := range e.ctx { |
||||
r.ctx[k] = v |
||||
} |
||||
switch c := c.(type) { |
||||
case *ctxError: |
||||
r.msg += c.msg |
||||
for k, v := range c.ctx { |
||||
r.ctx[k] = v |
||||
} |
||||
default: |
||||
r.msg += c.Error() |
||||
} |
||||
return r |
||||
} |
||||
|
||||
// Log15Func is a log15-compatible logging function.
|
||||
type Log15Func func(msg string, ctx ...interface{}) |
||||
|
||||
// Log15Logger logs something with a log15-style logging function.
|
||||
type Log15Logger interface { |
||||
Log15(f Log15Func) |
||||
} |
||||
|
||||
// Log15 logs the receiver with a log15-style logging function.
|
||||
func (e *ctxError) Log15(f Log15Func) { |
||||
var ctx []interface{} |
||||
for k, v := range e.ctx { |
||||
ctx = append(ctx, k, v) |
||||
} |
||||
f(e.msg, ctx...) |
||||
} |
||||
|
||||
// Log15 logs an error with a log15-style logging function.
|
||||
// It handles both regular errors and Log15Logger-compliant errors.
|
||||
func Log15(f Log15Func, e error) { |
||||
if e15, ok := e.(Log15Logger); ok { |
||||
e15.Log15(f) |
||||
} else { |
||||
f(e.Error()) |
||||
} |
||||
} |
@ -0,0 +1,363 @@ |
||||
package ctxerror |
||||
|
||||
import ( |
||||
"errors" |
||||
"reflect" |
||||
"testing" |
||||
) |
||||
|
||||
func TestNew(t *testing.T) { |
||||
type args struct { |
||||
msg string |
||||
ctx []interface{} |
||||
} |
||||
tests := []struct { |
||||
name string |
||||
args args |
||||
want CtxError |
||||
}{ |
||||
{ |
||||
name: "Empty", |
||||
args: args{msg: "", ctx: []interface{}{}}, |
||||
want: &ctxError{msg: "", ctx: map[string]interface{}{}}, |
||||
}, |
||||
{ |
||||
name: "Regular", |
||||
args: args{msg: "omg", ctx: []interface{}{"wtf", 1, "bbq", 2}}, |
||||
want: &ctxError{msg: "omg", ctx: map[string]interface{}{"wtf": 1, "bbq": 2}}, |
||||
}, |
||||
{ |
||||
name: "Truncated", |
||||
args: args{ |
||||
msg: "omg", |
||||
ctx: []interface{}{"wtf", 1, "bbq" /* missing value... */}, |
||||
}, |
||||
want: &ctxError{ |
||||
msg: "omg", |
||||
ctx: map[string]interface{}{"wtf": 1, "bbq": /* becomes */ nil}, |
||||
}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
if got := New(tt.args.msg, tt.args.ctx...); !reflect.DeepEqual(got, tt.want) { |
||||
t.Errorf("New() = %#v, want %#v", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func Test_ctxError_updateCtx(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
before, after map[string]interface{} |
||||
delta []interface{} |
||||
}{ |
||||
{ |
||||
name: "Empty", |
||||
before: map[string]interface{}{"omg": 1, "wtf": 2, "bbq": 3}, |
||||
delta: []interface{}{}, |
||||
after: map[string]interface{}{"omg": 1, "wtf": 2, "bbq": 3}, |
||||
}, |
||||
{ |
||||
name: "Regular", |
||||
before: map[string]interface{}{"omg": 1, "wtf": 2, "bbq": 3}, |
||||
delta: []interface{}{"omg", 10, "wtf", 20}, |
||||
after: map[string]interface{}{"omg": 10, "wtf": 20, "bbq": 3}, |
||||
}, |
||||
{ |
||||
name: "Truncated", |
||||
before: map[string]interface{}{"omg": 1, "wtf": 2, "bbq": 3}, |
||||
delta: []interface{}{"omg", 10, "wtf" /* missing value... */}, |
||||
after: map[string]interface{}{"omg": 10, "wtf": /* becomes */ nil, "bbq": 3}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
e := &ctxError{msg: tt.name, ctx: tt.before} |
||||
e.updateCtx(tt.delta...) |
||||
if !reflect.DeepEqual(e.ctx, tt.after) { |
||||
t.Errorf("expected ctx %#v != %#v seen", tt.after, e.ctx) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func Test_ctxError_Error(t *testing.T) { |
||||
type fields struct { |
||||
msg string |
||||
ctx map[string]interface{} |
||||
} |
||||
tests := []struct { |
||||
name string |
||||
fields fields |
||||
want string |
||||
}{ |
||||
{ |
||||
name: "AllEmpty", |
||||
fields: fields{msg: "", ctx: map[string]interface{}{}}, |
||||
want: "", |
||||
}, |
||||
{ |
||||
name: "CtxEmpty", |
||||
fields: fields{msg: "omg", ctx: map[string]interface{}{}}, |
||||
want: "omg", |
||||
}, |
||||
{ |
||||
name: "MsgEmpty", |
||||
fields: fields{msg: "", ctx: map[string]interface{}{"wtf": "bbq"}}, |
||||
want: ", wtf=\"bbq\"", |
||||
}, |
||||
{ |
||||
name: "Regular", |
||||
fields: fields{msg: "omg", ctx: map[string]interface{}{"wtf": "bbq"}}, |
||||
want: "omg, wtf=\"bbq\"", |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
e := &ctxError{ |
||||
msg: tt.fields.msg, |
||||
ctx: tt.fields.ctx, |
||||
} |
||||
if got := e.Error(); got != tt.want { |
||||
t.Errorf("Error() = %#v, want %#v", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func Test_ctxError_Message(t *testing.T) { |
||||
type fields struct { |
||||
msg string |
||||
ctx map[string]interface{} |
||||
} |
||||
tests := []struct { |
||||
name string |
||||
fields fields |
||||
want string |
||||
}{ |
||||
{ |
||||
name: "AllEmpty", |
||||
fields: fields{msg: "", ctx: map[string]interface{}{}}, |
||||
want: "", |
||||
}, |
||||
{ |
||||
name: "CtxEmpty", |
||||
fields: fields{msg: "omg", ctx: map[string]interface{}{}}, |
||||
want: "omg", |
||||
}, |
||||
{ |
||||
name: "MsgEmpty", |
||||
fields: fields{msg: "", ctx: map[string]interface{}{"wtf": "bbq"}}, |
||||
want: "", |
||||
}, |
||||
{ |
||||
name: "Regular", |
||||
fields: fields{msg: "omg", ctx: map[string]interface{}{"wtf": "bbq"}}, |
||||
want: "omg", |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
e := &ctxError{ |
||||
msg: tt.fields.msg, |
||||
ctx: tt.fields.ctx, |
||||
} |
||||
if got := e.Message(); got != tt.want { |
||||
t.Errorf("Message() = %#v, want %#v", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func Test_ctxError_Contexts(t *testing.T) { |
||||
type fields struct { |
||||
msg string |
||||
ctx map[string]interface{} |
||||
} |
||||
tests := []struct { |
||||
name string |
||||
fields fields |
||||
want map[string]interface{} |
||||
}{ |
||||
{ |
||||
name: "Empty", |
||||
fields: fields{msg: "", ctx: map[string]interface{}{}}, |
||||
want: map[string]interface{}{}, |
||||
}, |
||||
{ |
||||
name: "Regular", |
||||
fields: fields{ |
||||
msg: "", |
||||
ctx: map[string]interface{}{"omg": 1, "wtf": 2, "bbq": 3}, |
||||
}, |
||||
want: map[string]interface{}{"omg": 1, "wtf": 2, "bbq": 3}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
e := &ctxError{ |
||||
msg: tt.fields.msg, |
||||
ctx: tt.fields.ctx, |
||||
} |
||||
if got := e.Contexts(); !reflect.DeepEqual(got, tt.want) { |
||||
t.Errorf("Contexts() = %#v, want %#v", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func Test_ctxError_WithCause(t *testing.T) { |
||||
type fields struct { |
||||
msg string |
||||
ctx map[string]interface{} |
||||
} |
||||
type args struct { |
||||
c error |
||||
} |
||||
tests := []struct { |
||||
name string |
||||
fields fields |
||||
args args |
||||
want CtxError |
||||
}{ |
||||
{ |
||||
name: "CtxError", |
||||
fields: fields{ |
||||
msg: "hello", |
||||
ctx: map[string]interface{}{"omg": 1, "wtf": 2}, |
||||
}, |
||||
args: args{c: &ctxError{ |
||||
msg: "world", |
||||
ctx: map[string]interface{}{"wtf": 20, "bbq": 30}, |
||||
}}, |
||||
want: &ctxError{ |
||||
msg: "hello: world", |
||||
ctx: map[string]interface{}{"omg": 1, "wtf": 20, "bbq": 30}, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "RegularError", |
||||
fields: fields{ |
||||
msg: "hello", |
||||
ctx: map[string]interface{}{"omg": 1, "wtf": 2}, |
||||
}, |
||||
args: args{c: errors.New("world")}, |
||||
want: &ctxError{ |
||||
msg: "hello: world", |
||||
ctx: map[string]interface{}{"omg": 1, "wtf": 2}, |
||||
}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
e := &ctxError{ |
||||
msg: tt.fields.msg, |
||||
ctx: tt.fields.ctx, |
||||
} |
||||
if got := e.WithCause(tt.args.c); !reflect.DeepEqual(got, tt.want) { |
||||
t.Errorf("WithCause() = %#v, want %#v", got, tt.want) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func Test_ctxError_Log15(t *testing.T) { |
||||
type fields struct { |
||||
msg string |
||||
ctx map[string]interface{} |
||||
} |
||||
type want struct { |
||||
msg string |
||||
ctx []interface{} |
||||
} |
||||
tests := []struct { |
||||
name string |
||||
fields fields |
||||
want want |
||||
}{ |
||||
{ |
||||
name: "Empty", |
||||
fields: fields{msg: "", ctx: map[string]interface{}{}}, |
||||
want: want{msg: "", ctx: nil}, |
||||
}, |
||||
{ |
||||
name: "Regular", |
||||
fields: fields{msg: "hello", ctx: map[string]interface{}{"omg": 1}}, |
||||
want: want{msg: "hello", ctx: []interface{}{"omg", 1}}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
called := false |
||||
f := func(msg string, ctx ...interface{}) { |
||||
called = true |
||||
if msg != tt.want.msg { |
||||
t.Errorf("expected message %#v != %#v seen", |
||||
tt.want.msg, msg) |
||||
} |
||||
if !reflect.DeepEqual(ctx, tt.want.ctx) { |
||||
t.Errorf("expected ctx %#v != %#v seen", ctx, tt.want.ctx) |
||||
} |
||||
} |
||||
e := &ctxError{ |
||||
msg: tt.fields.msg, |
||||
ctx: tt.fields.ctx, |
||||
} |
||||
e.Log15(f) |
||||
if !called { |
||||
t.Error("logging func not called") |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
func TestLog15(t *testing.T) { |
||||
type args struct { |
||||
e error |
||||
} |
||||
type want struct { |
||||
msg string |
||||
ctx []interface{} |
||||
} |
||||
tests := []struct { |
||||
name string |
||||
args args |
||||
want want |
||||
}{ |
||||
{ |
||||
name: "Regular", |
||||
args: args{e: errors.New("hello")}, |
||||
want: want{msg: "hello", ctx: nil}, |
||||
}, |
||||
{ |
||||
name: "CtxError", |
||||
args: args{e: &ctxError{ |
||||
msg: "hello", |
||||
ctx: map[string]interface{}{"omg": 1}, |
||||
}}, |
||||
want: want{msg: "hello", ctx: []interface{}{"omg", 1}}, |
||||
}, |
||||
} |
||||
for _, tt := range tests { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
called := false |
||||
f := func(msg string, ctx ...interface{}) { |
||||
called = true |
||||
if msg != tt.want.msg { |
||||
t.Errorf("expected message %#v != %#v seen", |
||||
tt.want.msg, msg) |
||||
} |
||||
if !reflect.DeepEqual(ctx, tt.want.ctx) { |
||||
t.Errorf("expected ctx %#v != %#v seen", |
||||
tt.want.ctx, ctx) |
||||
} |
||||
} |
||||
Log15(f, tt.args.e) |
||||
if !called { |
||||
t.Errorf("logging func not called") |
||||
} |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,125 @@ |
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: ctxerror.go
|
||||
|
||||
// Package mock_ctxerror is a generated GoMock package.
|
||||
package mock_ctxerror |
||||
|
||||
import ( |
||||
gomock "github.com/golang/mock/gomock" |
||||
ctxerror "github.com/harmony-one/harmony/internal/ctxerror" |
||||
reflect "reflect" |
||||
) |
||||
|
||||
// MockCtxError is a mock of CtxError interface
|
||||
type MockCtxError struct { |
||||
ctrl *gomock.Controller |
||||
recorder *MockCtxErrorMockRecorder |
||||
} |
||||
|
||||
// MockCtxErrorMockRecorder is the mock recorder for MockCtxError
|
||||
type MockCtxErrorMockRecorder struct { |
||||
mock *MockCtxError |
||||
} |
||||
|
||||
// NewMockCtxError creates a new mock instance
|
||||
func NewMockCtxError(ctrl *gomock.Controller) *MockCtxError { |
||||
mock := &MockCtxError{ctrl: ctrl} |
||||
mock.recorder = &MockCtxErrorMockRecorder{mock} |
||||
return mock |
||||
} |
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockCtxError) EXPECT() *MockCtxErrorMockRecorder { |
||||
return m.recorder |
||||
} |
||||
|
||||
// Error mocks base method
|
||||
func (m *MockCtxError) Error() string { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Error") |
||||
ret0, _ := ret[0].(string) |
||||
return ret0 |
||||
} |
||||
|
||||
// Error indicates an expected call of Error
|
||||
func (mr *MockCtxErrorMockRecorder) Error() *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockCtxError)(nil).Error)) |
||||
} |
||||
|
||||
// Message mocks base method
|
||||
func (m *MockCtxError) Message() string { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Message") |
||||
ret0, _ := ret[0].(string) |
||||
return ret0 |
||||
} |
||||
|
||||
// Message indicates an expected call of Message
|
||||
func (mr *MockCtxErrorMockRecorder) Message() *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Message", reflect.TypeOf((*MockCtxError)(nil).Message)) |
||||
} |
||||
|
||||
// Contexts mocks base method
|
||||
func (m *MockCtxError) Contexts() map[string]interface{} { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "Contexts") |
||||
ret0, _ := ret[0].(map[string]interface{}) |
||||
return ret0 |
||||
} |
||||
|
||||
// Contexts indicates an expected call of Contexts
|
||||
func (mr *MockCtxErrorMockRecorder) Contexts() *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Contexts", reflect.TypeOf((*MockCtxError)(nil).Contexts)) |
||||
} |
||||
|
||||
// WithCause mocks base method
|
||||
func (m *MockCtxError) WithCause(c error) ctxerror.CtxError { |
||||
m.ctrl.T.Helper() |
||||
ret := m.ctrl.Call(m, "WithCause", c) |
||||
ret0, _ := ret[0].(ctxerror.CtxError) |
||||
return ret0 |
||||
} |
||||
|
||||
// WithCause indicates an expected call of WithCause
|
||||
func (mr *MockCtxErrorMockRecorder) WithCause(c interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithCause", reflect.TypeOf((*MockCtxError)(nil).WithCause), c) |
||||
} |
||||
|
||||
// MockLog15Logger is a mock of Log15Logger interface
|
||||
type MockLog15Logger struct { |
||||
ctrl *gomock.Controller |
||||
recorder *MockLog15LoggerMockRecorder |
||||
} |
||||
|
||||
// MockLog15LoggerMockRecorder is the mock recorder for MockLog15Logger
|
||||
type MockLog15LoggerMockRecorder struct { |
||||
mock *MockLog15Logger |
||||
} |
||||
|
||||
// NewMockLog15Logger creates a new mock instance
|
||||
func NewMockLog15Logger(ctrl *gomock.Controller) *MockLog15Logger { |
||||
mock := &MockLog15Logger{ctrl: ctrl} |
||||
mock.recorder = &MockLog15LoggerMockRecorder{mock} |
||||
return mock |
||||
} |
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockLog15Logger) EXPECT() *MockLog15LoggerMockRecorder { |
||||
return m.recorder |
||||
} |
||||
|
||||
// Log15 mocks base method
|
||||
func (m *MockLog15Logger) Log15(f ctxerror.Log15Func) { |
||||
m.ctrl.T.Helper() |
||||
m.ctrl.Call(m, "Log15", f) |
||||
} |
||||
|
||||
// Log15 indicates an expected call of Log15
|
||||
func (mr *MockLog15LoggerMockRecorder) Log15(f interface{}) *gomock.Call { |
||||
mr.mock.ctrl.T.Helper() |
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Log15", reflect.TypeOf((*MockLog15Logger)(nil).Log15), f) |
||||
} |
@ -0,0 +1,66 @@ |
||||
package utils |
||||
|
||||
// this module in utils handles the ini file read/write
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
|
||||
"github.com/harmony-one/harmony/p2p" |
||||
ini "gopkg.in/ini.v1" |
||||
) |
||||
|
||||
// WalletProfile contains a section and key value pair map
|
||||
type WalletProfile struct { |
||||
Profile string |
||||
Bootnodes []string |
||||
Shards int |
||||
RPCServer [][]p2p.Peer |
||||
} |
||||
|
||||
// ReadWalletProfile reads an ini file and return WalletProfile
|
||||
func ReadWalletProfile(fn string, profile string) (*WalletProfile, error) { |
||||
cfg, err := ini.ShadowLoad(fn) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
config := new(WalletProfile) |
||||
config.Profile = profile |
||||
|
||||
// get the profile section
|
||||
sec, err := cfg.GetSection(profile) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if sec.HasKey("bootnode") { |
||||
config.Bootnodes = sec.Key("bootnode").ValueWithShadows() |
||||
} else { |
||||
return nil, fmt.Errorf("can't find bootnode key") |
||||
} |
||||
|
||||
if sec.HasKey("shards") { |
||||
config.Shards = sec.Key("shards").MustInt() |
||||
config.RPCServer = make([][]p2p.Peer, config.Shards) |
||||
} else { |
||||
return nil, fmt.Errorf("can't find shards key") |
||||
} |
||||
|
||||
for i := 0; i < config.Shards; i++ { |
||||
rpcSec, err := cfg.GetSection(fmt.Sprintf("%s.shard%v.rpc", profile, i)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
rpcKey := rpcSec.Key("rpc").ValueWithShadows() |
||||
for _, key := range rpcKey { |
||||
v := strings.Split(key, ":") |
||||
rpc := p2p.Peer{ |
||||
IP: v[0], |
||||
Port: v[1], |
||||
} |
||||
config.RPCServer[i] = append(config.RPCServer[i], rpc) |
||||
} |
||||
} |
||||
|
||||
return config, nil |
||||
|
||||
} |
@ -0,0 +1,112 @@ |
||||
package utils |
||||
|
||||
import ( |
||||
"reflect" |
||||
"testing" |
||||
|
||||
"github.com/harmony-one/harmony/p2p" |
||||
) |
||||
|
||||
func TestReadWalletProfile(t *testing.T) { |
||||
config := []*WalletProfile{ |
||||
&WalletProfile{ |
||||
Profile: "default", |
||||
Bootnodes: []string{"127.0.0.1:9000/abcd", "127.0.0.1:9999/daeg"}, |
||||
Shards: 4, |
||||
RPCServer: [][]p2p.Peer{ |
||||
[]p2p.Peer{ |
||||
p2p.Peer{ |
||||
IP: "127.0.0.4", |
||||
Port: "8888", |
||||
}, |
||||
p2p.Peer{ |
||||
IP: "192.168.0.4", |
||||
Port: "9876", |
||||
}, |
||||
}, |
||||
[]p2p.Peer{ |
||||
p2p.Peer{ |
||||
IP: "127.0.0.1", |
||||
Port: "8888", |
||||
}, |
||||
p2p.Peer{ |
||||
IP: "192.168.0.1", |
||||
Port: "9876", |
||||
}, |
||||
}, |
||||
[]p2p.Peer{ |
||||
p2p.Peer{ |
||||
IP: "127.0.0.2", |
||||
Port: "8888", |
||||
}, |
||||
p2p.Peer{ |
||||
IP: "192.168.0.2", |
||||
Port: "9876", |
||||
}, |
||||
}, |
||||
[]p2p.Peer{ |
||||
p2p.Peer{ |
||||
IP: "127.0.0.3", |
||||
Port: "8888", |
||||
}, |
||||
p2p.Peer{ |
||||
IP: "192.168.0.3", |
||||
Port: "9876", |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
&WalletProfile{ |
||||
Profile: "testnet", |
||||
Bootnodes: []string{"192.168.0.1:9990/abcd", "127.0.0.1:8888/daeg"}, |
||||
Shards: 3, |
||||
RPCServer: [][]p2p.Peer{ |
||||
[]p2p.Peer{ |
||||
p2p.Peer{ |
||||
IP: "192.168.2.3", |
||||
Port: "8888", |
||||
}, |
||||
p2p.Peer{ |
||||
IP: "192.168.192.3", |
||||
Port: "9877", |
||||
}, |
||||
}, |
||||
[]p2p.Peer{ |
||||
p2p.Peer{ |
||||
IP: "192.168.2.1", |
||||
Port: "8888", |
||||
}, |
||||
p2p.Peer{ |
||||
IP: "192.168.192.1", |
||||
Port: "9877", |
||||
}, |
||||
}, |
||||
[]p2p.Peer{ |
||||
p2p.Peer{ |
||||
IP: "192.168.2.2", |
||||
Port: "8888", |
||||
}, |
||||
p2p.Peer{ |
||||
IP: "192.168.192.2", |
||||
Port: "9877", |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
config1, err := ReadWalletProfile("test.ini", "default") |
||||
if err != nil { |
||||
t.Fatalf("ReadWalletProfile Error: %v", err) |
||||
} |
||||
if !reflect.DeepEqual(config[0], config1) { |
||||
t.Errorf("Got: %v\nExpect: %v\n", config1, config[0]) |
||||
} |
||||
config2, err := ReadWalletProfile("test.ini", "testnet") |
||||
if err != nil { |
||||
t.Fatalf("ReadWalletProfile Error: %v", err) |
||||
} |
||||
if !reflect.DeepEqual(config[1], config2) { |
||||
t.Errorf("Got: %v\nExpect: %v\n", config2, config[1]) |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
[default] |
||||
bootnode = 127.0.0.1:9000/abcd |
||||
bootnode = 127.0.0.1:9999/daeg |
||||
shards = 4 |
||||
|
||||
[default.shard0.rpc] |
||||
rpc = 127.0.0.4:8888 |
||||
rpc = 192.168.0.4:9876 |
||||
|
||||
[default.shard1.rpc] |
||||
rpc = 127.0.0.1:8888 |
||||
rpc = 192.168.0.1:9876 |
||||
|
||||
[default.shard2.rpc] |
||||
rpc = 127.0.0.2:8888 |
||||
rpc = 192.168.0.2:9876 |
||||
|
||||
[default.shard3.rpc] |
||||
rpc = 127.0.0.3:8888 |
||||
rpc = 192.168.0.3:9876 |
||||
|
||||
[testnet] |
||||
bootnode = 192.168.0.1:9990/abcd |
||||
bootnode = 127.0.0.1:8888/daeg |
||||
shards = 3 |
||||
|
||||
[testnet.shard0.rpc] |
||||
rpc = 192.168.2.3:8888 |
||||
rpc = 192.168.192.3:9877 |
||||
|
||||
[testnet.shard1.rpc] |
||||
rpc = 192.168.2.1:8888 |
||||
rpc = 192.168.192.1:9877 |
||||
|
||||
[testnet.shard2.rpc] |
||||
rpc = 192.168.2.2:8888 |
||||
rpc = 192.168.192.2:9877 |
Loading…
Reference in new issue