pull/433/head
Rongjian Lan 6 years ago
commit dd6bf13b03
  1. 2
      README.md
  2. 12
      api/client/service/client.go
  3. 1
      api/client/service/gen.sh
  4. 171
      api/client/service/proto/client.pb.go
  5. 18
      api/client/service/proto/client.proto
  6. 35
      api/client/service/server.go
  7. 4
      api/client/service/server_test.go
  8. 10
      api/service/clientsupport/service.go
  9. 12
      api/service/randomness/service.go
  10. 13
      api/service/staking/service.go
  11. 11
      cmd/harmony.go
  12. 5
      consensus/consensus.go
  13. 12
      consensus/consensus_validator_test.go
  14. 140
      core/blockchain.go
  15. 3
      core/error.go
  16. 25
      core/rawdb/accessors_chain.go
  17. 6
      core/rawdb/schema.go
  18. 174
      core/resharding.go
  19. 12
      core/resharding.md
  20. 18
      core/resharding_test.go
  21. 14
      core/types/block.go
  22. 68
      core/types/shard_state.go
  23. 33
      core/types/shard_state_test.go
  24. 57
      internal/utils/connlogger.go
  25. 23
      node/contract.go
  26. 90
      node/node.go
  27. 12
      node/node_handler.go
  28. 33
      node/node_newblock.go
  29. 99
      node/node_test.go
  30. 2
      scripts/setup_bls_build_flags.sh

@ -19,7 +19,7 @@ export CGO_CFLAGS="-I$GOPATH/src/github.com/harmony-one/bls/include -I$GOPATH/sr
export CGO_LDFLAGS="-L$GOPATH/src/github.com/harmony-one/bls/lib -L/usr/local/opt/openssl/lib"
export LD_LIBRARY_PATH=$GOPATH/src/github.com/harmony-one/bls/lib:$GOPATH/src/github.com/harmony-one/mcl/lib:/usr/local/opt/openssl/lib
export LIBRARY_PATH=$LD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH
mkdir -p $HOME/<path_of_your_choice>/src/github.com/harmony-one

@ -62,3 +62,15 @@ func (client *Client) GetFreeToken(address common.Address) *proto.GetFreeTokenRe
}
return response
}
// GetStakingContractInfo gets necessary info for staking.
func (client *Client) GetStakingContractInfo(address common.Address) *proto.StakingContractInfoResponse {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
request := &proto.StakingContractInfoRequest{Address: address.Bytes()}
response, err := client.clientServiceClient.GetStakingContractInfo(ctx, request)
if err != nil {
log.Fatalf("Error getting free token: %s", err)
}
return response
}

@ -0,0 +1 @@
protoc -I proto/ proto/client.proto --go_out=plugins=grpc:proto

@ -195,32 +195,138 @@ func (m *GetFreeTokenResponse) GetTxId() []byte {
return nil
}
// StakingContractInfoRequest is the request to necessary info for stkaing.
type StakingContractInfoRequest struct {
// The account address
Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *StakingContractInfoRequest) Reset() { *m = StakingContractInfoRequest{} }
func (m *StakingContractInfoRequest) String() string { return proto.CompactTextString(m) }
func (*StakingContractInfoRequest) ProtoMessage() {}
func (*StakingContractInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_014de31d7ac8c57c, []int{4}
}
func (m *StakingContractInfoRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StakingContractInfoRequest.Unmarshal(m, b)
}
func (m *StakingContractInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_StakingContractInfoRequest.Marshal(b, m, deterministic)
}
func (m *StakingContractInfoRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_StakingContractInfoRequest.Merge(m, src)
}
func (m *StakingContractInfoRequest) XXX_Size() int {
return xxx_messageInfo_StakingContractInfoRequest.Size(m)
}
func (m *StakingContractInfoRequest) XXX_DiscardUnknown() {
xxx_messageInfo_StakingContractInfoRequest.DiscardUnknown(m)
}
var xxx_messageInfo_StakingContractInfoRequest proto.InternalMessageInfo
func (m *StakingContractInfoRequest) GetAddress() []byte {
if m != nil {
return m.Address
}
return nil
}
// StakingContractInfoResponse is the response of GetStakingContractInfo.
type StakingContractInfoResponse struct {
// Contract address.
ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"`
// The balance of the staking account.
Balance []byte `protobuf:"bytes,2,opt,name=balance,proto3" json:"balance,omitempty"`
// The nonce of the staking account.
Nonce uint64 `protobuf:"varint,3,opt,name=nonce,proto3" json:"nonce,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *StakingContractInfoResponse) Reset() { *m = StakingContractInfoResponse{} }
func (m *StakingContractInfoResponse) String() string { return proto.CompactTextString(m) }
func (*StakingContractInfoResponse) ProtoMessage() {}
func (*StakingContractInfoResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_014de31d7ac8c57c, []int{5}
}
func (m *StakingContractInfoResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StakingContractInfoResponse.Unmarshal(m, b)
}
func (m *StakingContractInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_StakingContractInfoResponse.Marshal(b, m, deterministic)
}
func (m *StakingContractInfoResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_StakingContractInfoResponse.Merge(m, src)
}
func (m *StakingContractInfoResponse) XXX_Size() int {
return xxx_messageInfo_StakingContractInfoResponse.Size(m)
}
func (m *StakingContractInfoResponse) XXX_DiscardUnknown() {
xxx_messageInfo_StakingContractInfoResponse.DiscardUnknown(m)
}
var xxx_messageInfo_StakingContractInfoResponse proto.InternalMessageInfo
func (m *StakingContractInfoResponse) GetContractAddress() string {
if m != nil {
return m.ContractAddress
}
return ""
}
func (m *StakingContractInfoResponse) GetBalance() []byte {
if m != nil {
return m.Balance
}
return nil
}
func (m *StakingContractInfoResponse) GetNonce() uint64 {
if m != nil {
return m.Nonce
}
return 0
}
func init() {
proto.RegisterType((*FetchAccountStateRequest)(nil), "client.FetchAccountStateRequest")
proto.RegisterType((*FetchAccountStateResponse)(nil), "client.FetchAccountStateResponse")
proto.RegisterType((*GetFreeTokenRequest)(nil), "client.GetFreeTokenRequest")
proto.RegisterType((*GetFreeTokenResponse)(nil), "client.GetFreeTokenResponse")
proto.RegisterType((*StakingContractInfoRequest)(nil), "client.StakingContractInfoRequest")
proto.RegisterType((*StakingContractInfoResponse)(nil), "client.StakingContractInfoResponse")
}
func init() { proto.RegisterFile("client.proto", fileDescriptor_014de31d7ac8c57c) }
var fileDescriptor_014de31d7ac8c57c = []byte{
// 229 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0xce, 0xc9, 0x4c,
0xcd, 0x2b, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0xf0, 0x94, 0x4c, 0xb8, 0x24,
0xdc, 0x52, 0x4b, 0x92, 0x33, 0x1c, 0x93, 0x93, 0xf3, 0x4b, 0xf3, 0x4a, 0x82, 0x4b, 0x12, 0x4b,
0x52, 0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x24, 0xb8, 0xd8, 0x13, 0x53, 0x52, 0x8a,
0x52, 0x8b, 0x8b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x60, 0x5c, 0x25, 0x6f, 0x2e, 0x49,
0x2c, 0xba, 0x8a, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x41, 0xda, 0x92, 0x12, 0x73, 0x12, 0xf3, 0x92,
0x53, 0x61, 0xda, 0xa0, 0x5c, 0x21, 0x11, 0x2e, 0xd6, 0xbc, 0x7c, 0x90, 0x38, 0x93, 0x02, 0xa3,
0x06, 0x4b, 0x10, 0x84, 0xa3, 0xa4, 0xcf, 0x25, 0xec, 0x9e, 0x5a, 0xe2, 0x56, 0x94, 0x9a, 0x1a,
0x92, 0x9f, 0x9d, 0x9a, 0x47, 0xd8, 0x76, 0x2d, 0x2e, 0x11, 0x54, 0x0d, 0x50, 0x8b, 0x85, 0xb8,
0x58, 0x4a, 0x2a, 0x3c, 0x53, 0xa0, 0xca, 0xc1, 0x6c, 0xa3, 0x1d, 0x8c, 0x5c, 0xbc, 0xce, 0x60,
0xaf, 0x06, 0xa7, 0x16, 0x95, 0x65, 0x26, 0xa7, 0x0a, 0x45, 0x71, 0x09, 0x62, 0xb8, 0x5d, 0x48,
0x41, 0x0f, 0x1a, 0x3a, 0xb8, 0x02, 0x43, 0x4a, 0x11, 0x8f, 0x0a, 0x88, 0xfd, 0x4a, 0x0c, 0x42,
0xde, 0x5c, 0x3c, 0xc8, 0x2e, 0x13, 0x92, 0x86, 0x69, 0xc2, 0xe2, 0x41, 0x29, 0x19, 0xec, 0x92,
0x30, 0xc3, 0x92, 0xd8, 0xc0, 0x31, 0x65, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xc6, 0xd9, 0x35,
0x0c, 0xb9, 0x01, 0x00, 0x00,
// 302 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x52, 0x41, 0x4f, 0xf2, 0x40,
0x14, 0xfc, 0xda, 0x0f, 0x31, 0xbe, 0xd4, 0xa8, 0x2b, 0x31, 0xb5, 0x78, 0xa8, 0xeb, 0x05, 0x3d,
0x60, 0xa2, 0xc6, 0x3b, 0x21, 0x81, 0x10, 0x6e, 0xad, 0x27, 0x2f, 0x66, 0xd9, 0x3e, 0xb5, 0x81,
0xec, 0x62, 0xfb, 0x30, 0xfc, 0x19, 0xff, 0xab, 0xa1, 0xdd, 0x35, 0x35, 0xb6, 0x70, 0xdb, 0x99,
0x7d, 0xf3, 0x26, 0x3b, 0xb3, 0xe0, 0xc9, 0x45, 0x8a, 0x8a, 0xfa, 0xcb, 0x4c, 0x93, 0x66, 0xed,
0x12, 0xf1, 0x07, 0xf0, 0x47, 0x48, 0xf2, 0x7d, 0x20, 0xa5, 0x5e, 0x29, 0x8a, 0x49, 0x10, 0x46,
0xf8, 0xb1, 0xc2, 0x9c, 0x98, 0x0f, 0xfb, 0x22, 0x49, 0x32, 0xcc, 0x73, 0xdf, 0x09, 0x9d, 0x9e,
0x17, 0x59, 0xc8, 0xa7, 0x70, 0x5e, 0xa3, 0xca, 0x97, 0x5a, 0xe5, 0xb8, 0x91, 0xcd, 0xc4, 0x42,
0x28, 0x89, 0x56, 0x66, 0x20, 0xeb, 0xc0, 0x9e, 0xd2, 0x1b, 0xde, 0x0d, 0x9d, 0x5e, 0x2b, 0x2a,
0x01, 0xbf, 0x85, 0xd3, 0x31, 0xd2, 0x28, 0x43, 0x7c, 0xd2, 0x73, 0x54, 0xbb, 0xdd, 0x6f, 0xa0,
0xf3, 0x5b, 0x60, 0x8c, 0x19, 0xb4, 0x68, 0x3d, 0x49, 0xcc, 0x78, 0x71, 0xe6, 0x8f, 0x10, 0xc4,
0x24, 0xe6, 0xa9, 0x7a, 0x1b, 0x6a, 0x45, 0x99, 0x90, 0x34, 0x51, 0xaf, 0x7a, 0xb7, 0xc7, 0x1a,
0xba, 0xb5, 0x3a, 0x63, 0x75, 0x0d, 0xc7, 0xd2, 0xf0, 0x2f, 0xd5, 0x0d, 0x07, 0xd1, 0x91, 0xe5,
0x07, 0x25, 0x5d, 0x8d, 0xc3, 0x6d, 0x88, 0xe3, 0x7f, 0x25, 0x8e, 0xbb, 0x2f, 0x17, 0x0e, 0x87,
0x45, 0x39, 0x31, 0x66, 0x9f, 0xa9, 0x44, 0xf6, 0x0c, 0x27, 0x7f, 0xd2, 0x66, 0x61, 0xdf, 0xf4,
0xd9, 0x54, 0x5f, 0x70, 0xb9, 0x65, 0xa2, 0x7c, 0x06, 0xff, 0xc7, 0xa6, 0xe0, 0x55, 0xb3, 0x64,
0x5d, 0x2b, 0xaa, 0xa9, 0x24, 0xb8, 0xa8, 0xbf, 0xfc, 0x59, 0x26, 0xe1, 0x6c, 0x8c, 0x54, 0x93,
0x1b, 0xe3, 0x56, 0xd9, 0x5c, 0x46, 0x70, 0xb5, 0x75, 0xc6, 0x9a, 0xcc, 0xda, 0xc5, 0x07, 0xbe,
0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x3e, 0x0b, 0x3e, 0xd0, 0x02, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -237,6 +343,7 @@ const _ = grpc.SupportPackageIsVersion4
type ClientServiceClient interface {
FetchAccountState(ctx context.Context, in *FetchAccountStateRequest, opts ...grpc.CallOption) (*FetchAccountStateResponse, error)
GetFreeToken(ctx context.Context, in *GetFreeTokenRequest, opts ...grpc.CallOption) (*GetFreeTokenResponse, error)
GetStakingContractInfo(ctx context.Context, in *StakingContractInfoRequest, opts ...grpc.CallOption) (*StakingContractInfoResponse, error)
}
type clientServiceClient struct {
@ -265,10 +372,20 @@ func (c *clientServiceClient) GetFreeToken(ctx context.Context, in *GetFreeToken
return out, nil
}
func (c *clientServiceClient) GetStakingContractInfo(ctx context.Context, in *StakingContractInfoRequest, opts ...grpc.CallOption) (*StakingContractInfoResponse, error) {
out := new(StakingContractInfoResponse)
err := c.cc.Invoke(ctx, "/client.ClientService/GetStakingContractInfo", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ClientServiceServer is the server API for ClientService service.
type ClientServiceServer interface {
FetchAccountState(context.Context, *FetchAccountStateRequest) (*FetchAccountStateResponse, error)
GetFreeToken(context.Context, *GetFreeTokenRequest) (*GetFreeTokenResponse, error)
GetStakingContractInfo(context.Context, *StakingContractInfoRequest) (*StakingContractInfoResponse, error)
}
func RegisterClientServiceServer(s *grpc.Server, srv ClientServiceServer) {
@ -311,6 +428,24 @@ func _ClientService_GetFreeToken_Handler(srv interface{}, ctx context.Context, d
return interceptor(ctx, in, info, handler)
}
func _ClientService_GetStakingContractInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StakingContractInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ClientServiceServer).GetStakingContractInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/client.ClientService/GetStakingContractInfo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ClientServiceServer).GetStakingContractInfo(ctx, req.(*StakingContractInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
var _ClientService_serviceDesc = grpc.ServiceDesc{
ServiceName: "client.ClientService",
HandlerType: (*ClientServiceServer)(nil),
@ -323,6 +458,10 @@ var _ClientService_serviceDesc = grpc.ServiceDesc{
MethodName: "GetFreeToken",
Handler: _ClientService_GetFreeToken_Handler,
},
{
MethodName: "GetStakingContractInfo",
Handler: _ClientService_GetStakingContractInfo_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "client.proto",

@ -6,6 +6,7 @@ package client;
service ClientService {
rpc FetchAccountState(FetchAccountStateRequest) returns (FetchAccountStateResponse) {}
rpc GetFreeToken(GetFreeTokenRequest) returns (GetFreeTokenResponse) {}
rpc GetStakingContractInfo(StakingContractInfoRequest) returns (StakingContractInfoResponse) {}
}
// FetchAccountStateRequest is the request to fetch an account's balance and nonce.
@ -33,3 +34,20 @@ message GetFreeTokenResponse {
// The transaction Id that requests free token from the faucet.
bytes txId = 1;
}
// StakingContractInfoRequest is the request to necessary info for stkaing.
message StakingContractInfoRequest {
// The account address
bytes address = 1;
}
// StakingContractInfoResponse is the response of GetStakingContractInfo.
message StakingContractInfoResponse {
// Contract address.
string contract_address = 1;
// The balance of the staking account.
bytes balance = 2;
// The nonce of the staking account.
uint64 nonce = 3;
}

@ -6,17 +6,16 @@ import (
"net"
"github.com/ethereum/go-ethereum/common"
proto "github.com/harmony-one/harmony/api/client/service/proto"
"github.com/harmony-one/harmony/core/state"
"google.golang.org/grpc"
proto "github.com/harmony-one/harmony/api/client/service/proto"
)
// Server is the Server struct for client service package.
type Server struct {
stateReader func() (*state.DB, error)
callFaucetContract func(common.Address) common.Hash
stateReader func() (*state.DB, error)
callFaucetContract func(common.Address) common.Hash
getDeployedStakingContractAddress func() common.Address
}
// FetchAccountState implements the FetchAccountState interface to return account state.
@ -39,6 +38,21 @@ func (s *Server) GetFreeToken(ctx context.Context, request *proto.GetFreeTokenRe
return &proto.GetFreeTokenResponse{TxId: s.callFaucetContract(address).Bytes()}, nil
}
// GetStakingContractInfo implements the GetStakingContractInfo interface to return necessary info for staking.
func (s *Server) GetStakingContractInfo(ctx context.Context, request *proto.StakingContractInfoRequest) (*proto.StakingContractInfoResponse, error) {
var address common.Address
address.SetBytes(request.Address)
state, err := s.stateReader()
if err != nil {
return nil, err
}
return &proto.StakingContractInfoResponse{
ContractAddress: s.getDeployedStakingContractAddress().Hex(),
Balance: state.GetBalance(address).Bytes(),
Nonce: state.GetNonce(address),
}, nil
}
// Start starts the Server on given ip and port.
func (s *Server) Start(ip, port string) (*grpc.Server, error) {
// TODO(minhdoan): Currently not using ip. Fix it later.
@ -55,7 +69,14 @@ func (s *Server) Start(ip, port string) (*grpc.Server, error) {
}
// NewServer creates new Server which implements ClientServiceServer interface.
func NewServer(stateReader func() (*state.DB, error), callFaucetContract func(common.Address) common.Hash) *Server {
s := &Server{stateReader: stateReader, callFaucetContract: callFaucetContract}
func NewServer(
stateReader func() (*state.DB, error),
callFaucetContract func(common.Address) common.Hash,
getDeployedStakingContractAddress func() common.Address) *Server {
s := &Server{
stateReader: stateReader,
callFaucetContract: callFaucetContract,
getDeployedStakingContractAddress: getDeployedStakingContractAddress,
}
return s
}

@ -33,7 +33,7 @@ func TestGetFreeToken(test *testing.T) {
return nil, nil
}, func(common.Address) common.Hash {
return hash
})
}, nil)
testBankKey, _ := crypto.GenerateKey()
testBankAddress := crypto.PubkeyToAddress(testBankKey.PublicKey)
@ -67,7 +67,7 @@ func TestFetchAccountState(test *testing.T) {
return chain.State()
}, func(common.Address) common.Hash {
return hash
})
}, nil)
response, err := server.FetchAccountState(nil, &client.FetchAccountStateRequest{Address: testBankAddress.Bytes()})

@ -23,9 +23,15 @@ type Service struct {
}
// New returns new client support service.
func New(stateReader func() (*state.DB, error), callFaucetContract func(common.Address) common.Hash, ip, nodePort string) *Service {
func New(stateReader func() (*state.DB, error),
callFaucetContract func(common.Address) common.Hash,
getDeployedStakingContract func() common.Address,
ip, nodePort string) *Service {
port, _ := strconv.Atoi(nodePort)
return &Service{server: clientService.NewServer(stateReader, callFaucetContract), ip: ip, port: strconv.Itoa(port + ClientServicePortDiff)}
return &Service{
server: clientService.NewServer(stateReader, callFaucetContract, getDeployedStakingContract),
ip: ip,
port: strconv.Itoa(port + ClientServicePortDiff)}
}
// StartService starts client support service.

@ -28,22 +28,18 @@ func (s *Service) StartService() {
// Init initializes randomness generation.
func (s *Service) Init() {
for {
newBlock := <-s.DRand.ConfirmedBlockChannel
_ = newBlock
// TODO: process newBlock
}
}
// Run runs randomness generation.
func (s *Service) Run(stopChan chan struct{}, stoppedChan chan struct{}) {
utils.GetLogInstance().Info("Running random generation")
go func() {
defer close(stoppedChan)
for {
select {
default:
utils.GetLogInstance().Info("Running random generation")
// Write some logic here.
case newBlock := <-s.DRand.ConfirmedBlockChannel:
_ = newBlock
utils.GetLogInstance().Debug("[RAND] Received New Block")
s.DoRandomGeneration()
case <-stopChan:
return

@ -4,11 +4,10 @@ import (
"crypto/ecdsa"
"math/big"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
client "github.com/harmony-one/harmony/api/client/service"
proto "github.com/harmony-one/harmony/api/client/service/proto"
"github.com/harmony-one/harmony/api/proto/message"
@ -76,17 +75,17 @@ func (s *Service) DoService(peer p2p.Peer) {
// See below of how to create a staking message.
}
func (s *Service) getAccountState(beaconPeer p2p.Peer) *proto.FetchAccountStateResponse {
func (s *Service) getStakingInfo(beaconPeer p2p.Peer) *proto.StakingContractInfoResponse {
client := client.NewClient(beaconPeer.IP, beaconPeer.Port)
defer client.Close()
return client.GetBalance(crypto.PubkeyToAddress(s.accountKey.PublicKey))
return client.GetStakingContractInfo(crypto.PubkeyToAddress(s.accountKey.PublicKey))
}
func (s *Service) createStakingMessage(beaconPeer p2p.Peer) *message.Message {
accountState := s.getAccountState(beaconPeer)
toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
stakingInfo := s.getStakingInfo(beaconPeer)
toAddress := common.HexToAddress(stakingInfo.ContractAddress)
tx := types.NewTransaction(
accountState.Nonce,
stakingInfo.Nonce,
toAddress,
0, // beacon chain.
big.NewInt(s.stakingAmount),

@ -13,6 +13,9 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
peerstore "github.com/libp2p/go-libp2p-peerstore"
multiaddr "github.com/multiformats/go-multiaddr"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/internal/attack"
pkg_newnode "github.com/harmony-one/harmony/internal/newnode"
@ -21,8 +24,6 @@ import (
"github.com/harmony-one/harmony/node"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
peerstore "github.com/libp2p/go-libp2p-peerstore"
multiaddr "github.com/multiformats/go-multiaddr"
)
var (
@ -113,6 +114,9 @@ func main() {
// isLeader indicates this node is a beacon chain leader node during the bootstrap process
isLeader := flag.Bool("is_leader", false, "true means this node is a beacon chain leader node")
// logConn logs incoming/outgoing connections
logConn := flag.Bool("log_conn", false, "log incoming/outgoing connections")
flag.Parse()
if *versionFlag {
@ -213,6 +217,9 @@ func main() {
}
host, err := p2pimpl.NewHost(&selfPeer, nodePriKey)
if *logConn {
host.GetP2PHost().Network().Notify(utils.ConnLogger)
}
if err != nil {
panic("unable to new host in harmony")
}

@ -27,7 +27,6 @@ import (
"golang.org/x/crypto/sha3"
proto_discovery "github.com/harmony-one/harmony/api/proto/discovery"
proto_node "github.com/harmony-one/harmony/api/proto/node"
)
// Consensus is the main struct with all states and data related to consensus process.
@ -107,10 +106,6 @@ type Consensus struct {
// List of offline Peers
OfflinePeerList []p2p.Peer
//List of nodes related to beaconchain funcs
WaitingNodes []proto_node.Info
ActiveNodes []proto_node.Info
}
// BFTBlockInfo send the latest block that was in BFT consensus process as well as its consensusID to state syncing

@ -44,9 +44,9 @@ func TestProcessMessageValidatorAnnounce(test *testing.T) {
test.Fatalf("newhost failure: %v", err)
}
consensusLeader := New(host, "0", []p2p.Peer{validator1, validator2, validator3}, leader)
blockBytes, err := hex.DecodeString("f90242f9023da00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a02b418211410ee3e75b32abd925bbeba215172afa509d65c1953d4b4e505a4a2aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808080a000000000000000000000000000000000000000000000000000000000000000008800000000000000008400000001b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080c0c0")
blockBytes, err := hex.DecodeString("f90264f9025fa00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a02b418211410ee3e75b32abd925bbeba215172afa509d65c1953d4b4e505a4a2aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808080a000000000000000000000000000000000000000000000000000000000000000008800000000000000008400000001b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080a00000000000000000000000000000000000000000000000000000000000000000c0c0")
consensusLeader.block = blockBytes
hashBytes, err := hex.DecodeString("a0b3344bd84d41e59b8d84857196080dc8bf91df2787ed5e3e7d65bf8a8cea050b")
hashBytes, err := hex.DecodeString("26d7cdbbaf6cedcaf946ad1e8c0bc2567e17418ce63026db4160a7cc32d9e488")
copy(consensusLeader.blockHash[:], hashBytes[:])
@ -98,9 +98,9 @@ func TestProcessMessageValidatorPrepared(test *testing.T) {
test.Fatalf("newhost failure: %v", err)
}
consensusLeader := New(host, "0", []p2p.Peer{validator1, validator2, validator3}, leader)
blockBytes, err := hex.DecodeString("f90242f9023da00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a02b418211410ee3e75b32abd925bbeba215172afa509d65c1953d4b4e505a4a2aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808080a000000000000000000000000000000000000000000000000000000000000000008800000000000000008400000001b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080c0c0")
blockBytes, err := hex.DecodeString("f90264f9025fa00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a02b418211410ee3e75b32abd925bbeba215172afa509d65c1953d4b4e505a4a2aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808080a000000000000000000000000000000000000000000000000000000000000000008800000000000000008400000001b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080a00000000000000000000000000000000000000000000000000000000000000000c0c0")
consensusLeader.block = blockBytes
hashBytes, err := hex.DecodeString("a0b3344bd84d41e59b8d84857196080dc8bf91df2787ed5e3e7d65bf8a8cea050b")
hashBytes, err := hex.DecodeString("26d7cdbbaf6cedcaf946ad1e8c0bc2567e17418ce63026db4160a7cc32d9e488")
copy(consensusLeader.blockHash[:], hashBytes[:])
@ -158,9 +158,9 @@ func TestProcessMessageValidatorCommitted(test *testing.T) {
test.Fatalf("newhost failure: %v", err)
}
consensusLeader := New(host, "0", []p2p.Peer{validator1, validator2, validator3}, leader)
blockBytes, err := hex.DecodeString("f90242f9023da00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a02b418211410ee3e75b32abd925bbeba215172afa509d65c1953d4b4e505a4a2aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808080a000000000000000000000000000000000000000000000000000000000000000008800000000000000008400000001b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080c0c0")
blockBytes, err := hex.DecodeString("f90264f9025fa00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a02b418211410ee3e75b32abd925bbeba215172afa509d65c1953d4b4e505a4a2aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000808502540be400808080a000000000000000000000000000000000000000000000000000000000000000008800000000000000008400000001b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080a00000000000000000000000000000000000000000000000000000000000000000c0c0")
consensusLeader.block = blockBytes
hashBytes, err := hex.DecodeString("a0b3344bd84d41e59b8d84857196080dc8bf91df2787ed5e3e7d65bf8a8cea050b")
hashBytes, err := hex.DecodeString("26d7cdbbaf6cedcaf946ad1e8c0bc2567e17418ce63026db4160a7cc32d9e488")
copy(consensusLeader.blockHash[:], hashBytes[:])

@ -43,6 +43,7 @@ import (
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/utils"
lru "github.com/hashicorp/golang-lru"
)
@ -62,6 +63,12 @@ const (
maxTimeFutureBlocks = 30
badBlockLimit = 10
triesInMemory = 128
shardCacheLimit = 2
// BlocksPerEpoch is the number of blocks in one epoch
// currently set to small number for testing
// in future, this need to be adjusted dynamically instead of constant
BlocksPerEpoch = 5
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
BlockChainVersion = 3
@ -114,12 +121,13 @@ type BlockChain struct {
currentBlock atomic.Value // Current head of the block chain
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
receiptsCache *lru.Cache // Cache for the most recent receipts per block
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
receiptsCache *lru.Cache // Cache for the most recent receipts per block
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
shardStateCache *lru.Cache
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically
@ -152,23 +160,25 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
blockCache, _ := lru.New(blockCacheLimit)
futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit)
shardCache, _ := lru.New(shardCacheLimit)
bc := &BlockChain{
chainConfig: chainConfig,
cacheConfig: cacheConfig,
db: db,
triegc: prque.New(nil),
stateCache: state.NewDatabase(db),
quit: make(chan struct{}),
shouldPreserve: shouldPreserve,
bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache,
receiptsCache: receiptsCache,
blockCache: blockCache,
futureBlocks: futureBlocks,
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,
chainConfig: chainConfig,
cacheConfig: cacheConfig,
db: db,
triegc: prque.New(nil),
stateCache: state.NewDatabase(db),
quit: make(chan struct{}),
shouldPreserve: shouldPreserve,
bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache,
receiptsCache: receiptsCache,
blockCache: blockCache,
futureBlocks: futureBlocks,
shardStateCache: shardCache,
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,
}
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
@ -299,6 +309,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
bc.receiptsCache.Purge()
bc.blockCache.Purge()
bc.futureBlocks.Purge()
bc.shardStateCache.Purge()
// Rewind the block chain, ensuring we don't end up with a stateless head block
if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number.Uint64() < currentBlock.NumberU64() {
@ -1626,3 +1637,90 @@ func (bc *BlockChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.Su
func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return bc.scope.Track(bc.logsFeed.Subscribe(ch))
}
// GetShardState retrives sharding state given block hash and block number
func (bc *BlockChain) GetShardState(hash common.Hash, number uint64) types.ShardState {
if cached, ok := bc.shardStateCache.Get(hash); ok {
shardState := cached.(types.ShardState)
return shardState
}
shardState := rawdb.ReadShardState(bc.db, hash, number)
if shardState == nil {
return nil
}
bc.shardStateCache.Add(hash, shardState)
return shardState
}
// GetShardStateByNumber retrieves sharding state given the block number
func (bc *BlockChain) GetShardStateByNumber(number uint64) types.ShardState {
hash := rawdb.ReadCanonicalHash(bc.db, number)
if hash == (common.Hash{}) {
return nil
}
return bc.GetShardState(hash, number)
}
// GetShardStateByHash retrieves the shard state given the blockhash, return nil if not exist
func (bc *BlockChain) GetShardStateByHash(hash common.Hash) types.ShardState {
number := bc.hc.GetBlockNumber(hash)
if number == nil {
return nil
}
return bc.GetShardState(hash, *number)
}
// GetRandSeedByNumber retrieves the rand seed given the block number, return 0 if not exist
func (bc *BlockChain) GetRandSeedByNumber(number uint64) int64 {
header := bc.GetHeaderByNumber(number)
if header == nil {
return 0
}
return int64(header.RandSeed)
}
// GetNewShardState will calculate (if not exist) and get the new shard state for epoch block or nil if block is not epoch block
// epoch block is where the new shard state stored
func (bc *BlockChain) GetNewShardState(block *types.Block) types.ShardState {
hash := block.Hash()
number := block.NumberU64()
// just ignore non-epoch block
if !CheckEpochBlock(number) {
return nil
}
shardState := bc.GetShardState(hash, number)
if shardState == nil {
epoch := GetEpochFromBlockNumber(number)
shardState = CalculateNewShardState(bc, epoch)
bc.shardStateCache.Add(hash, shardState)
}
return shardState
}
// ValidateNewShardState validate whether the new shard state root matches
func (bc *BlockChain) ValidateNewShardState(block *types.Block) error {
shardState := bc.GetNewShardState(block)
if shardState == nil {
return nil
}
if shardState.Hash() != block.Header().ShardStateHash {
return ErrShardStateNotMatch
}
utils.GetLogInstance().Debug("[resharding] validate new shard state success", "shardStateHash", shardState.Hash())
return nil
}
// InsertNewShardState insert new shard state into epoch block
func (bc *BlockChain) InsertNewShardState(block *types.Block) {
shardState := bc.GetNewShardState(block)
if shardState == nil {
return
}
hash := block.Hash()
number := block.NumberU64()
rawdb.WriteShardState(bc.db, hash, number, shardState)
utils.GetLogInstance().Debug("[resharding] save new shard state success", "shardStateHash", shardState.Hash())
for _, c := range shardState {
utils.GetLogInstance().Debug("[resharding] new shard information", "shardID", c.ShardID, "NodeList", c.NodeList)
}
}

@ -32,4 +32,7 @@ var (
// ErrNonceTooHigh is returned if the nonce of a transaction is higher than the
// next one expected based on the local chain.
ErrNonceTooHigh = errors.New("nonce too high")
// ErrShardStateNotMatch is returned if the calculated shardState hash not equal that in the block header
ErrShardStateNotMatch = errors.New("shard state root hash not match")
)

@ -373,3 +373,28 @@ func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header {
}
return a
}
// ReadShardState retrieves sharding state
func ReadShardState(db DatabaseReader, hash common.Hash, number uint64) types.ShardState {
data, _ := db.Get(shardStateKey(number, hash))
if len(data) == 0 {
return nil
}
shardState := types.ShardState{}
if err := rlp.DecodeBytes(data, &shardState); err != nil {
log.Error("Fail to decode sharding state", "hash", hash, "number", number, "err", err)
return nil
}
return shardState
}
// WriteShardState stores sharding state into database
func WriteShardState(db DatabaseWriter, hash common.Hash, number uint64, shardState types.ShardState) {
data, err := rlp.EncodeToBytes(shardState)
if err != nil {
log.Crit("Failed to encode sharding state", "err", err)
}
if err := db.Put(shardStateKey(number, hash), data); err != nil {
log.Crit("Failed to store sharding state", "err", err)
}
}

@ -53,6 +53,8 @@ var (
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
shardStatePrefix = []byte("ss") // shardStatePrefix + num (uint64 big endian) + hash -> shardState
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
@ -132,3 +134,7 @@ func preimageKey(hash common.Hash) []byte {
func configKey(hash common.Hash) []byte {
return append(configPrefix, hash.Bytes()...)
}
func shardStateKey(number uint64, hash common.Hash) []byte {
return append(append(shardStatePrefix, encodeBlockNumber(number)...), hash.Bytes()...)
}

@ -0,0 +1,174 @@
package core
import (
"math/rand"
"sort"
"strconv"
"github.com/harmony-one/harmony/core/types"
)
const (
// InitialSeed is the initial random seed, a magic number to answer everything, remove later
InitialSeed int64 = 42
)
// ShardingState is data structure hold the sharding state
type ShardingState struct {
epoch uint64 // current epoch
rnd int64 // random seed for resharding
numShards int
shardState types.ShardState
}
// sortedCommitteeBySize will sort shards by size
// Suppose there are N shards, the first N/2 larger shards are called active committees
// the rest N/2 smaller committees are called inactive committees
// actually they are all just normal shards
// TODO: sort the committee weighted by total staking instead of shard size
func (ss *ShardingState) sortCommitteeBySize() {
sort.Slice(ss.shardState, func(i, j int) bool {
return len(ss.shardState[i].NodeList) > len(ss.shardState[j].NodeList)
})
}
// assignNewNodes add new nodes into the N/2 active committees evenly
func (ss *ShardingState) assignNewNodes(newNodeList []types.NodeID) {
ss.sortCommitteeBySize()
numActiveShards := ss.numShards / 2
Shuffle(newNodeList)
for i, nid := range newNodeList {
id := i % numActiveShards
ss.shardState[id].NodeList = append(ss.shardState[id].NodeList, nid)
}
}
// cuckooResharding uses cuckoo rule to reshard X% of active committee(shards) into inactive committee(shards)
func (ss *ShardingState) cuckooResharding(percent float64) {
ss.sortCommitteeBySize()
numActiveShards := ss.numShards / 2
kickedNodes := []types.NodeID{}
for i := range ss.shardState {
if i >= numActiveShards {
break
}
Shuffle(ss.shardState[i].NodeList)
numKicked := int(percent * float64(len(ss.shardState[i].NodeList)))
tmp := ss.shardState[i].NodeList[:numKicked]
kickedNodes = append(kickedNodes, tmp...)
ss.shardState[i].NodeList = ss.shardState[i].NodeList[numKicked:]
}
Shuffle(kickedNodes)
for i, nid := range kickedNodes {
id := numActiveShards + i%(ss.numShards-numActiveShards)
ss.shardState[id].NodeList = append(ss.shardState[id].NodeList, nid)
}
}
// UpdateShardState will first add new nodes into shards, then use cuckoo rule to reshard to get new shard state
func (ss *ShardingState) UpdateShardState(newNodeList []types.NodeID, percent float64) {
rand.Seed(ss.rnd)
ss.assignNewNodes(newNodeList)
ss.cuckooResharding(percent)
}
// Shuffle will shuffle the list with result uniquely determined by seed, assuming there is no repeat items in the list
func Shuffle(list []types.NodeID) {
sort.Slice(list, func(i, j int) bool {
return types.CompareNodeID(list[i], list[j]) == -1
})
rand.Shuffle(len(list), func(i, j int) {
list[i], list[j] = list[j], list[i]
})
}
// GetBlockNumberFromEpoch calculates the block number where epoch sharding information is stored
func GetBlockNumberFromEpoch(epoch uint64) uint64 {
number := epoch * uint64(BlocksPerEpoch) // currently we use the first block in each epoch
return number
}
// GetEpochFromBlockNumber calculates the epoch number the block belongs to
func GetEpochFromBlockNumber(blockNumber uint64) uint64 {
return blockNumber / uint64(BlocksPerEpoch)
}
// CheckEpochBlock check whethere a given block number is the one to store epoch information
func CheckEpochBlock(blockNumber uint64) bool {
return blockNumber%uint64(BlocksPerEpoch) == 0
}
// GetPreviousEpochBlockNumber gets the epoch block number of previous epoch
func GetPreviousEpochBlockNumber(blockNumber uint64) uint64 {
epoch := GetEpochFromBlockNumber(blockNumber)
if epoch == 1 {
// no previous epoch
return epoch
}
return GetBlockNumberFromEpoch(epoch - 1)
}
// GetShardingStateFromBlockChain will retrieve random seed and shard map from beacon chain for given a epoch
func GetShardingStateFromBlockChain(bc *BlockChain, epoch uint64) *ShardingState {
number := GetBlockNumberFromEpoch(epoch)
shardState := bc.GetShardStateByNumber(number)
rnd := bc.GetRandSeedByNumber(number)
return &ShardingState{epoch: epoch, rnd: rnd, shardState: shardState, numShards: len(shardState)}
}
// CalculateNewShardState get sharding state from previous epoch and calcualte sharding state for new epoch
// TODO: currently, we just mock everything
func CalculateNewShardState(bc *BlockChain, epoch uint64) types.ShardState {
if epoch == 1 {
return fakeGetInitShardState()
}
ss := GetShardingStateFromBlockChain(bc, epoch-1)
newNodeList := fakeNewNodeList(ss.rnd)
percent := ss.calculateKickoutRate(newNodeList)
ss.UpdateShardState(newNodeList, percent)
return ss.shardState
}
// calculateKickoutRate calculates the cuckoo rule kick out rate in order to make committee balanced
func (ss *ShardingState) calculateKickoutRate(newNodeList []types.NodeID) float64 {
numActiveCommittees := ss.numShards / 2
newNodesPerShard := len(newNodeList) / numActiveCommittees
ss.sortCommitteeBySize()
return float64(newNodesPerShard) / float64(len(ss.shardState[numActiveCommittees].NodeList))
}
// FakeGenRandSeed generate random seed based on previous rnd seed; remove later after VRF implemented
func FakeGenRandSeed(seed int64) int64 {
rand.Seed(seed)
return rand.Int63()
}
// remove later after bootstrap codes ready
func fakeGetInitShardState() types.ShardState {
rand.Seed(InitialSeed)
shardState := types.ShardState{}
for i := 0; i < 6; i++ {
sid := uint32(i)
com := types.Committee{ShardID: sid}
for j := 0; j < 10; j++ {
nid := strconv.Itoa(int(rand.Int63()))
com.NodeList = append(com.NodeList, types.NodeID(nid))
}
shardState = append(shardState, com)
}
return shardState
}
// remove later after new nodes list generation ready
func fakeNewNodeList(seed int64) []types.NodeID {
rand.Seed(seed)
numNewNodes := rand.Intn(10)
nodeList := []types.NodeID{}
for i := 0; i < numNewNodes; i++ {
nid := strconv.Itoa(int(rand.Int63()))
nodeList = append(nodeList, types.NodeID(nid))
}
return nodeList
}

@ -0,0 +1,12 @@
## Resharding
In current design, the epoch is defined to be fixed length, the epoch length is a constant parameter BlocksPerEpoch. In future, it will be dynamically adjustable according to security parameter. During the epoch transition, suppose there are N shards, we sort the shards according to the size of active nodes (that had staking for next epoch). The first N/2 larger shards will be called active committees, and the last N/2 smaller shards will be called inactive committees. Don't be confused by
the name, they are all normal shards with same function.
All the information about sharding will be stored in BeaconChain. A sharding state is defined as a map which maps each NodeID to the ShardID the node belongs to. Every node will have a unique NodeID and be mapped to one ShardID. At the beginning of a new epoch, the BeaconChain leader will propose a new block containing the new sharding state, the new sharding state is uniquely determined by the randomness generated by distributed randomness protocol. During the consensus process, all the validators will perform the same calculation and verify the proposed sharding state is valid. After consensus is reached, each node will write the new sharding state into the block. This block is called epoch block. In current code, it's the first block of each epoch in BeaconChain.
The main function of resharding is CalculcateNewShardState. It will take 3 inputs: newNodeList, oldShardState, randomSeed and output newShardState.
The newNodeList will be retrieved from BeaconChain staking transaction during the previous epoch. The randomSeed and oldShardState is stored in previous epoch block. It should be noticed that the randomSeed generation currently is mocked. After the distributed randomness protocol(drand) is ready, the drand service will generate the random seed for resharding.
The resharding process is as follows: we first get newNodeList from staking transactions from previous epoch and assign the new nodes evenly into the N/2 active committees. Then, we kick out X% of nodes from each active committees and put these kicked out nodes into inactive committees evenly. The percentage X roughly equals to the percentage of new nodes into active committee in order to balance the committee size.

@ -0,0 +1,18 @@
package core
import (
"fmt"
"testing"
)
func TestFakeGetInitShardState(t *testing.T) {
ss := fakeGetInitShardState()
for i := range ss {
fmt.Printf("ShardID: %v, NodeList: %v\n", ss[i].ShardID, ss[i].NodeList)
}
}
func TestFakeNewNodeList(t *testing.T) {
nodeList := fakeNewNodeList(42)
fmt.Println("newNodeList: ", nodeList)
}

@ -97,7 +97,9 @@ type Header struct {
PrepareBitmap []byte `json:"bitmap" gencodec:"required"` // Contains which validator signed
CommitSignature [48]byte `json:"signature" gencodec:"required"`
CommitBitmap []byte `json:"bitmap" gencodec:"required"` // Contains which validator signed
// TODO(RJ): add epoch info
RandSeed uint64 `json:"randomSeed"`
ShardStateHash common.Hash `json:"shardStateRoot"`
}
// field type overrides for gencodec
@ -448,3 +450,13 @@ func (s blockSorter) Less(i, j int) bool {
func Number(b1, b2 *Block) bool {
return b1.header.Number.Cmp(b2.header.Number) < 0
}
// AddRandSeed add random seed into block header
func (b *Block) AddRandSeed(randSeed int64) {
b.header.RandSeed = uint64(randSeed)
}
// AddShardStateHash add shardStateHash into block header
func (b *Block) AddShardStateHash(shardStateHash common.Hash) {
b.header.ShardStateHash = shardStateHash
}

@ -0,0 +1,68 @@
package types
import (
"sort"
"github.com/ethereum/go-ethereum/common"
"golang.org/x/crypto/sha3"
)
// NodeID is a unique ID represent a node
type NodeID string
// ShardState is the collection of all committees
type ShardState []Committee
// Committee contains the active nodes in one shard
type Committee struct {
ShardID uint32
NodeList []NodeID // a list of NodeID where NodeID is represented by a string
}
// GetHashFromNodeList will sort the list, then use Keccak256 to hash the list
// notice that the input nodeList will be modified (sorted)
func GetHashFromNodeList(nodeList []NodeID) []byte {
// in general, nodeList should not be empty
if nodeList == nil || len(nodeList) == 0 {
return []byte{}
}
sort.Slice(nodeList, func(i, j int) bool {
return CompareNodeID(nodeList[i], nodeList[j]) == -1
})
d := sha3.NewLegacyKeccak256()
for i := range nodeList {
d.Write(nodeList[i].Serialize())
}
return d.Sum(nil)
}
// Hash is the root hash of ShardState
func (ss ShardState) Hash() (h common.Hash) {
sort.Slice(ss, func(i, j int) bool {
return ss[i].ShardID < ss[j].ShardID
})
d := sha3.NewLegacyKeccak256()
for i := range ss {
hash := GetHashFromNodeList(ss[i].NodeList)
d.Write(hash)
}
d.Sum(h[:0])
return h
}
// CompareNodeID compares two nodes by their ID; used to sort node list
func CompareNodeID(n1 NodeID, n2 NodeID) int {
if n1 < n2 {
return -1
}
if n1 > n2 {
return 1
}
return 0
}
// Serialize serialize NodeID into bytes
func (n NodeID) Serialize() []byte {
return []byte(n)
}

@ -0,0 +1,33 @@
package types
import (
"bytes"
"testing"
)
func TestGetHashFromNodeList(t *testing.T) {
l1 := []NodeID{"node1", "node2", "node3"}
l2 := []NodeID{"node2", "node1", "node3"}
h1 := GetHashFromNodeList(l1)
h2 := GetHashFromNodeList(l2)
if bytes.Compare(h1, h2) != 0 {
t.Error("node list l1 and l2 should have equal hash")
}
}
func TestHash(t *testing.T) {
com1 := Committee{ShardID: 22, NodeList: []NodeID{"node11", "node22", "node1"}}
com2 := Committee{ShardID: 2, NodeList: []NodeID{"node4", "node5", "node6"}}
shardState1 := ShardState{com1, com2}
h1 := shardState1.Hash()
com3 := Committee{ShardID: 2, NodeList: []NodeID{"node6", "node5", "node4"}}
com4 := Committee{ShardID: 22, NodeList: []NodeID{"node1", "node11", "node22"}}
shardState2 := ShardState{com3, com4}
h2 := shardState2.Hash()
if bytes.Compare(h1[:], h2[:]) != 0 {
t.Error("shardState1 and shardState2 should have equal hash")
}
}

@ -0,0 +1,57 @@
package utils
import (
"github.com/ethereum/go-ethereum/log"
net "github.com/libp2p/go-libp2p-net"
ma "github.com/multiformats/go-multiaddr"
)
type connLogger struct{}
func (connLogger) Listen(net net.Network, ma ma.Multiaddr) {
log.Debug("[CONNECTIONS] Listener starting", "net", net, "addr", ma)
}
func (connLogger) ListenClose(net net.Network, ma ma.Multiaddr) {
log.Debug("[CONNECTIONS] Listener closing", "net", net, "addr", ma)
}
func (connLogger) Connected(net net.Network, conn net.Conn) {
log.Debug("[CONNECTIONS] Connected", "net", net,
"localPeer", conn.LocalPeer(), "localAddr", conn.LocalMultiaddr(),
"remotePeer", conn.RemotePeer(), "remoteAddr", conn.RemoteMultiaddr(),
)
}
func (connLogger) Disconnected(net net.Network, conn net.Conn) {
log.Debug("[CONNECTIONS] Disconnected", "net", net,
"localPeer", conn.LocalPeer(), "localAddr", conn.LocalMultiaddr(),
"remotePeer", conn.RemotePeer(), "remoteAddr", conn.RemoteMultiaddr(),
)
}
func (connLogger) OpenedStream(net net.Network, stream net.Stream) {
conn := stream.Conn()
log.Debug("[CONNECTIONS] Stream opened", "net", net,
"localPeer", conn.LocalPeer(), "localAddr", conn.LocalMultiaddr(),
"remotePeer", conn.RemotePeer(), "remoteAddr", conn.RemoteMultiaddr(),
"protocol", stream.Protocol(),
)
}
func (connLogger) ClosedStream(net net.Network, stream net.Stream) {
conn := stream.Conn()
log.Debug("[CONNECTIONS] Stream closed", "net", net,
"localPeer", conn.LocalPeer(), "localAddr", conn.LocalMultiaddr(),
"remotePeer", conn.RemotePeer(), "remoteAddr", conn.RemoteMultiaddr(),
"protocol", stream.Protocol(),
)
}
// ConnLogger is a LibP2P connection logger.
// Add on a LibP2P host by calling:
//
// host.Network().Notify(utils.ConnLogger)
//
// It logs all listener/connection/stream open/close activities at debug level.
var ConnLogger connLogger

@ -4,7 +4,6 @@ import (
"crypto/ecdsa"
"encoding/hex"
"math/big"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common"
@ -13,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils/contract"
"golang.org/x/crypto/sha3"
)
// Constants related to smart contract.
@ -36,12 +36,13 @@ func (node *Node) AddStakingContractToPendingTransactions() {
dataEnc := common.FromHex(StakingContractBinary)
// Unsigned transaction to avoid the case of transaction address.
mycontracttx, _ := types.SignTx(types.NewContractCreation(uint64(0), node.Consensus.ShardID, contractFunds, params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, priKey)
node.ContractAddresses = append(node.ContractAddresses, crypto.CreateAddress(contractAddress, uint64(0)))
//node.StakingContractAddress = crypto.CreateAddress(contractAddress, uint64(0))
node.StakingContractAddress = node.generateDeployedStakingContractAddress(mycontracttx, contractAddress)
node.addPendingTransactions(types.Transactions{mycontracttx})
}
//CreateStakingWithdrawTransaction creates a new withdraw stake transaction
func (node *Node) CreateStakingWithdrawTransaction(stake int) (*types.Transaction, error) {
func (node *Node) CreateStakingWithdrawTransaction(stake string) (*types.Transaction, error) {
//These should be read from somewhere.
DepositContractPriKey, _ := ecdsa.GenerateKey(crypto.S256(), strings.NewReader("Deposit Smart Contract Key")) //DepositContractPriKey is pk for contract
DepositContractAddress := crypto.PubkeyToAddress(DepositContractPriKey.PublicKey) //DepositContractAddress is the address for the contract
@ -50,9 +51,19 @@ func (node *Node) CreateStakingWithdrawTransaction(stake int) (*types.Transactio
log.Error("Failed to get chain state", "Error", err)
}
nonce := state.GetNonce(crypto.PubkeyToAddress(DepositContractPriKey.PublicKey))
callingFunction := "0x2e1a7d4d"
contractData := callingFunction + hex.EncodeToString([]byte(strconv.Itoa(stake)))
dataEnc := common.FromHex(contractData)
//Following: https://github.com/miguelmota/ethereum-development-with-go-book/blob/master/code/transfer_tokens.go
withdrawFnSignature := []byte("withdraw(uint)")
hash := sha3.NewLegacyKeccak256()
hash.Write(withdrawFnSignature)
methodID := hash.Sum(nil)[:4]
amount := new(big.Int)
amount.SetString(stake, 10)
paddedAmount := common.LeftPadBytes(amount.Bytes(), 32)
var dataEnc []byte
dataEnc = append(dataEnc, methodID...)
dataEnc = append(dataEnc, paddedAmount...)
tx, err := types.SignTx(types.NewTransaction(nonce, DepositContractAddress, node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.AccountKey)
return tx, err
}

@ -165,6 +165,11 @@ type Node struct {
// Service manager.
serviceManager *service_manager.Manager
//Staked Accounts and Contract
CurrentStakes map[common.Address]int64 //This will save the latest information about staked nodes.
StakingContractAddress common.Address
WithdrawStakeFunc []byte
//Node Account
AccountKey *ecdsa.PrivateKey
Address common.Address
@ -272,9 +277,12 @@ func New(host p2p.Host, consensus *bft.Consensus, db ethdb.Database) *Node {
node.Worker = worker.New(params.TestChainConfig, chain, node.Consensus, pki.GetAddressFromPublicKey(node.SelfPeer.PubKey), node.Consensus.ShardID)
node.AddFaucetContractToPendingTransactions()
if node.Role == BeaconLeader {
node.AddStakingContractToPendingTransactions()
node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked
node.DepositToFakeAccounts()
}
if node.Role == BeaconLeader || node.Role == BeaconValidator {
node.CurrentStakes = make(map[common.Address]int64)
}
node.Consensus.ConsensusBlock = make(chan *bft.BFTBlockInfo)
node.Consensus.VerifiedNewBlock = make(chan *types.Block)
}
@ -298,6 +306,30 @@ func New(host p2p.Host, consensus *bft.Consensus, db ethdb.Database) *Node {
return &node
}
func (node *Node) getDeployedStakingContract() common.Address {
return node.StakingContractAddress
}
//In order to get the deployed contract address of a contract, we need to find the nonce of the address that created it.
//(Refer: https://solidity.readthedocs.io/en/v0.5.3/introduction-to-smart-contracts.html#index-8)
// Then we can (re)create the deployed address. Trivially, this is 0 for us.
// The deployed contract address can also be obtained via the receipt of the contract creating transaction.
func (node *Node) generateDeployedStakingContractAddress(mycontracttx *types.Transaction, contractAddress common.Address) common.Address {
//Ideally we send the transaction to
//Correct Way 1:
//node.SendTx(mycontracttx)
//receipts := node.worker.GetCurrentReceipts()
//deployedcontractaddress = recepits[len(receipts)-1].ContractAddress //get the address from the receipt
//Correct Way 2:
//nonce := GetNonce(contractAddress)
//deployedAddress := crypto.CreateAddress(contractAddress, uint64(nonce))
//deployedcontractaddress = recepits[len(receipts)-1].ContractAddress //get the address from the receipt
nonce := 0
return crypto.CreateAddress(contractAddress, uint64(nonce))
}
// IsOutOfSync checks whether the node is out of sync by comparing latest block with consensus block
func (node *Node) IsOutOfSync(consensusBlockInfo *bft.BFTBlockInfo) bool {
consensusBlock := consensusBlockInfo.Block
@ -332,14 +364,14 @@ func (node *Node) DoSyncing() {
continue
case consensusBlockInfo := <-node.Consensus.ConsensusBlock:
if !node.IsOutOfSync(consensusBlockInfo) {
startHash := node.blockchain.CurrentBlock().Hash()
node.stateSync.StartStateSync(startHash[:], node.blockchain, node.Worker)
if node.State == NodeNotInSync {
utils.GetLogInstance().Info("[SYNC] Node is now IN SYNC!")
}
node.stateMutex.Lock()
node.State = NodeReadyForConsensus
node.stateMutex.Unlock()
// wait for last mile block finish; think a better way
time.Sleep(200 * time.Millisecond)
node.stateSync.CloseConnections()
node.stateSync = nil
continue
@ -591,6 +623,53 @@ func (node *Node) RemovePeersHandler() {
}
}
//UpdateStakingList updates the stakes of every node.
func (node *Node) UpdateStakingList(block *types.Block) error {
signerType := types.HomesteadSigner{}
txns := block.Transactions()
for i := range txns {
txn := txns[i]
value := txn.Value().Int64()
currentSender, _ := types.Sender(signerType, txn)
_, isPresent := node.CurrentStakes[currentSender]
toAddress := txn.To()
if *toAddress != node.StakingContractAddress { //Not a address aimed at the staking contract.
continue
}
//This should be based on a switch case on function signature.
//TODO (ak) https://github.com/harmony-one/harmony/issues/430
if value > int64(0) { //If value >0 means its a staking deposit transaction
if isPresent {
//This means this node has increaserd its stake
node.CurrentStakes[currentSender] += value
} else {
node.CurrentStakes[currentSender] = value
}
} else { //This means node has withdrawn stake.
getData := txn.Data()
value := decodeStakeCall(getData) //Value being withdrawn
if isPresent {
//This means this node has increaserd its stake
if node.CurrentStakes[currentSender] > value {
node.CurrentStakes[currentSender] -= value
} else if node.CurrentStakes[currentSender] == value {
delete(node.CurrentStakes, currentSender)
} else {
continue //Overdraft protection.
}
} else {
node.CurrentStakes[currentSender] = value
}
}
}
return nil
}
func decodeStakeCall(getData []byte) int64 {
value := new(big.Int)
value.SetBytes(getData[4:]) //Escape the method call.
return value.Int64()
}
func (node *Node) setupForShardLeader() {
// Register explorer service.
node.serviceManager.RegisterService(service_manager.SupportExplorer, explorer.New(&node.SelfPeer))
@ -599,7 +678,7 @@ func (node *Node) setupForShardLeader() {
// Register new block service.
node.serviceManager.RegisterService(service_manager.BlockProposal, blockproposal.New(node.Consensus.ReadySignal, node.WaitForConsensusReady))
// Register client support service.
node.serviceManager.RegisterService(service_manager.ClientSupport, clientsupport.New(node.blockchain.State, node.CallFaucetContract, node.SelfPeer.IP, node.SelfPeer.Port))
node.serviceManager.RegisterService(service_manager.ClientSupport, clientsupport.New(node.blockchain.State, node.CallFaucetContract, node.getDeployedStakingContract, node.SelfPeer.IP, node.SelfPeer.Port))
}
func (node *Node) setupForShardValidator() {
@ -625,9 +704,10 @@ func (node *Node) setupForBeaconLeader() {
// Register new block service.
node.serviceManager.RegisterService(service_manager.BlockProposal, blockproposal.New(node.Consensus.ReadySignal, node.WaitForConsensusReady))
// Register client support service.
node.serviceManager.RegisterService(service_manager.ClientSupport, clientsupport.New(node.blockchain.State, node.CallFaucetContract, node.SelfPeer.IP, node.SelfPeer.Port))
node.serviceManager.RegisterService(service_manager.ClientSupport, clientsupport.New(node.blockchain.State, node.CallFaucetContract, node.getDeployedStakingContract, node.SelfPeer.IP, node.SelfPeer.Port))
// Register randomness service
node.serviceManager.RegisterService(service_manager.Randomness, randomness_service.New(node.DRand))
}
func (node *Node) setupForBeaconValidator() {

@ -229,6 +229,11 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) bool {
utils.GetLogInstance().Debug("Failed verifying new block", "Error", err, "tx", newBlock.Transactions()[0])
return false
}
err = node.blockchain.ValidateNewShardState(newBlock)
if err != nil {
utils.GetLogInstance().Debug("Failed to verify new sharding state", "err", err)
}
return true
}
@ -236,10 +241,12 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) bool {
// 1. add the new block to blockchain
// 2. [leader] send new block to the client
func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
if node.Role == BeaconLeader || node.Role == BeaconValidator {
node.UpdateStakingList(newBlock)
}
if node.Consensus.IsLeader {
node.BroadcastNewBlock(newBlock)
}
node.AddNewBlock(newBlock)
if node.Role == BeaconLeader && node.DRand != nil {
@ -252,11 +259,14 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
// AddNewBlock is usedd to add new block into the blockchain.
func (node *Node) AddNewBlock(newBlock *types.Block) {
blockNum, err := node.blockchain.InsertChain([]*types.Block{newBlock})
if err != nil {
utils.GetLogInstance().Debug("Error adding new block to blockchain", "blockNum", blockNum, "Error", err)
} else {
utils.GetLogInstance().Info("adding new block to blockchain", "blockNum", blockNum)
}
// only insert new shardstate when newBlock is epoch block
node.blockchain.InsertNewShardState(newBlock)
}
func (node *Node) pingMessageHandler(msgPayload []byte) int {

@ -3,6 +3,7 @@ package node
import (
"time"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils"
)
@ -49,6 +50,8 @@ func (node *Node) WaitForConsensusReady(readySignal chan struct{}, stopChan chan
if err != nil {
utils.GetLogInstance().Debug("Failed commiting new block", "Error", err)
} else {
// add new shard state if it's epoch block
node.addNewShardState(block)
newBlock = block
break
}
@ -65,3 +68,33 @@ func (node *Node) WaitForConsensusReady(readySignal chan struct{}, stopChan chan
}
}()
}
func (node *Node) addNewShardState(block *types.Block) {
shardState := node.blockchain.GetNewShardState(block)
if shardState != nil {
shardHash := shardState.Hash()
utils.GetLogInstance().Debug("[resharding] adding new shard state", "shardHash", shardHash)
for _, c := range shardState {
utils.GetLogInstance().Debug("new shard information", "shardID", c.ShardID, "NodeList", c.NodeList)
}
block.AddShardStateHash(shardHash)
}
}
func (node *Node) addNewRandSeed(block *types.Block) {
blockNumber := block.NumberU64()
if !core.CheckEpochBlock(blockNumber) {
return
}
var rnd int64
epoch := core.GetEpochFromBlockNumber(blockNumber)
if epoch == 1 {
rnd = core.InitialSeed
} else {
number := core.GetPreviousEpochBlockNumber(blockNumber)
oldrnd := node.blockchain.GetRandSeedByNumber(number)
rnd = core.FakeGenRandSeed(oldrnd)
}
block.AddRandSeed(rnd)
}

@ -2,16 +2,22 @@ package node
import (
"fmt"
"math/big"
"os"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
proto_discovery "github.com/harmony-one/harmony/api/proto/discovery"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"golang.org/x/crypto/sha3"
)
func TestNewNode(t *testing.T) {
@ -171,3 +177,96 @@ func TestPingPongHandler(t *testing.T) {
go exitServer()
node.StartServer()
}
func TestUpdateStakingDeposit(t *testing.T) {
_, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "127.0.0.1", Port: "8882", PubKey: pubKey}
validator := p2p.Peer{IP: "127.0.0.1", Port: "8885"}
priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "9902")
host, err := p2pimpl.NewHost(&leader, priKey)
if err != nil {
t.Fatalf("newhost failure: %v", err)
}
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(host, consensus, nil)
node.CurrentStakes = make(map[common.Address]int64)
DepositContractPriKey, _ := crypto.GenerateKey() //DepositContractPriKey is pk for contract
DepositContractAddress := crypto.PubkeyToAddress(DepositContractPriKey.PublicKey) //DepositContractAddress is the address for the contract
node.StakingContractAddress = DepositContractAddress
node.AccountKey, _ = crypto.GenerateKey()
Address := crypto.PubkeyToAddress(node.AccountKey.PublicKey)
callingFunction := "0xd0e30db0"
amount := new(big.Int)
amount.SetString("10", 10)
dataEnc := common.FromHex(callingFunction) //Deposit Does not take a argument, stake is transferred via amount.
tx1, err := types.SignTx(types.NewTransaction(0, DepositContractAddress, node.Consensus.ShardID, amount, params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.AccountKey)
var txs []*types.Transaction
txs = append(txs, tx1)
header := &types.Header{Extra: []byte("hello")}
block := types.NewBlock(header, txs, nil)
node.UpdateStakingList(block)
if len(node.CurrentStakes) == 0 {
t.Error("New node's stake was not added")
}
value, ok := node.CurrentStakes[Address]
if !ok {
t.Error("The correct address was not added")
}
if value != 10 {
t.Error("The correct stake value was not added")
}
}
func TestUpdateStakingWithdrawal(t *testing.T) {
_, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "127.0.0.1", Port: "8882", PubKey: pubKey}
validator := p2p.Peer{IP: "127.0.0.1", Port: "8885"}
priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "9902")
host, err := p2pimpl.NewHost(&leader, priKey)
if err != nil {
t.Fatalf("newhost failure: %v", err)
}
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(host, consensus, nil)
node.CurrentStakes = make(map[common.Address]int64)
DepositContractPriKey, _ := crypto.GenerateKey() //DepositContractPriKey is pk for contract
DepositContractAddress := crypto.PubkeyToAddress(DepositContractPriKey.PublicKey) //DepositContractAddress is the address for the contract
node.StakingContractAddress = DepositContractAddress
node.AccountKey, _ = crypto.GenerateKey()
Address := crypto.PubkeyToAddress(node.AccountKey.PublicKey)
node.CurrentStakes[Address] = int64(1010)
withdrawFnSignature := []byte("withdraw(uint)")
hash := sha3.NewLegacyKeccak256()
hash.Write(withdrawFnSignature)
methodID := hash.Sum(nil)[:4]
stake := "1000"
amount := new(big.Int)
amount.SetString(stake, 10)
paddedAmount := common.LeftPadBytes(amount.Bytes(), 32)
var dataEnc []byte
dataEnc = append(dataEnc, methodID...)
dataEnc = append(dataEnc, paddedAmount...)
tx, err := types.SignTx(types.NewTransaction(0, DepositContractAddress, node.Consensus.ShardID, big.NewInt(0), params.TxGasContractCreation*10, nil, dataEnc), types.HomesteadSigner{}, node.AccountKey)
var txs []*types.Transaction
txs = append(txs, tx)
header := &types.Header{Extra: []byte("hello")}
block := types.NewBlock(header, txs, nil)
node.UpdateStakingList(block)
value, ok := node.CurrentStakes[Address]
if !ok {
t.Error("The correct address was not present")
}
if value != 10 {
t.Error("The correct stake value was not subtracted")
}
}

@ -16,6 +16,6 @@ case $OS in
export CGO_CFLAGS="-I${BLS_DIR}/include -I${MCL_DIR}/include -I${OPENSSL_DIR}/include"
export CGO_LDFLAGS="-L${BLS_DIR}/lib -L${OPENSSL_DIR}/lib"
export LD_LIBRARY_PATH=${BLS_DIR}/lib:${MCL_DIR}/lib:${OPENSSL_DIR}/lib
export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH
;;
esac

Loading…
Cancel
Save