remove legacy staking code

pull/1674/head
Rongjian Lan 5 years ago
parent f91c013ed2
commit d659a1b952
  1. 8
      api/client/service/client.go
  2. 171
      api/client/service/proto/client.pb.go
  3. 18
      api/client/service/proto/client.proto
  4. 29
      api/client/service/server.go
  5. 59
      api/client/service/server_test.go
  6. 3
      api/service/clientsupport/service.go
  7. 9
      api/service/staking/readme.md
  8. 261
      api/service/staking/service.go
  9. 108
      node/contract.go
  10. 6
      node/node.go
  11. 3
      node/node_newblock.go
  12. 5
      node/service_setup.go
  13. 91
      node/staking.go
  14. 76
      node/staking_test.go

@ -52,11 +52,3 @@ func (client *Client) GetFreeToken(address common.Address) (*proto.GetFreeTokenR
request := &proto.GetFreeTokenRequest{Address: address.Bytes()}
return client.clientServiceClient.GetFreeToken(ctx, request)
}
// GetStakingContractInfo gets necessary info for staking.
func (client *Client) GetStakingContractInfo(address common.Address) (*proto.StakingContractInfoResponse, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
request := &proto.StakingContractInfoRequest{Address: address.Bytes()}
return client.clientServiceClient.GetStakingContractInfo(ctx, request)
}

@ -195,138 +195,32 @@ 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{
// 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,
// 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,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -343,7 +237,6 @@ 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 {
@ -372,20 +265,10 @@ 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) {
@ -428,24 +311,6 @@ 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),
@ -458,10 +323,6 @@ var _ClientService_serviceDesc = grpc.ServiceDesc{
MethodName: "GetFreeToken",
Handler: _ClientService_GetFreeToken_Handler,
},
{
MethodName: "GetStakingContractInfo",
Handler: _ClientService_GetStakingContractInfo_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "client.proto",

@ -6,7 +6,6 @@ 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.
@ -34,20 +33,3 @@ 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;
}

@ -8,7 +8,6 @@ import (
"github.com/ethereum/go-ethereum/common"
proto "github.com/harmony-one/harmony/api/client/service/proto"
"github.com/harmony-one/harmony/core/state"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/utils"
"google.golang.org/grpc"
@ -16,9 +15,8 @@ import (
// Server is the Server struct for client service package.
type Server struct {
stateReader func() (*state.DB, error)
callFaucetContract func(common.Address) common.Hash
getDeployedStakingContractAddress func() common.Address
stateReader func() (*state.DB, error)
callFaucetContract func(common.Address) common.Hash
}
// FetchAccountState implements the FetchAccountState interface to return account state.
@ -41,21 +39,6 @@ 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: common2.MustAddressToBech32(s.getDeployedStakingContractAddress()),
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.
@ -78,12 +61,10 @@ 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,
getDeployedStakingContractAddress func() common.Address) *Server {
callFaucetContract func(common.Address) common.Hash) *Server {
s := &Server{
stateReader: stateReader,
callFaucetContract: callFaucetContract,
getDeployedStakingContractAddress: getDeployedStakingContractAddress,
stateReader: stateReader,
callFaucetContract: callFaucetContract,
}
return s
}

@ -3,7 +3,6 @@ package client
import (
"bytes"
"math/big"
"strings"
"testing"
blockfactory "github.com/harmony-one/harmony/block/factory"
@ -11,13 +10,10 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
client "github.com/harmony-one/harmony/api/client/service/proto"
proto "github.com/harmony-one/harmony/api/client/service/proto"
"github.com/harmony-one/harmony/core/state"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/ethereum/go-ethereum/ethdb"
client "github.com/harmony-one/harmony/api/client/service/proto"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
)
@ -39,7 +35,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)
@ -74,7 +70,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()})
@ -90,50 +86,3 @@ func TestFetchAccountState(test *testing.T) {
test.Errorf("Wrong nonce is returned")
}
}
func TestGetStakingContractInfo(test *testing.T) {
var (
database = ethdb.NewMemDatabase()
gspec = core.Genesis{
Config: chainConfig,
Factory: blockFactory,
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
ShardID: 10,
}
)
genesis := gspec.MustCommit(database)
_ = genesis
chain, _ := core.NewBlockChain(database, nil, gspec.Config, chain.Engine, vm.Config{}, nil)
hash := common.Hash{}
hash.SetBytes([]byte("hello"))
deployedStakingContractAddress := common.Address{}
deployedStakingContractAddress.SetBytes([]byte("stakingContractAddress"))
server := NewServer(func() (*state.DB, error) {
return chain.State()
}, func(common.Address) common.Hash {
return hash
}, func() common.Address {
return deployedStakingContractAddress
})
response, err := server.GetStakingContractInfo(nil, &proto.StakingContractInfoRequest{Address: testBankAddress.Bytes()})
if err != nil {
test.Fatal("GetStakingContractInfo failed:", err)
}
if bytes.Compare(response.Balance, testBankFunds.Bytes()) != 0 {
test.Errorf("Wrong balance is returned")
}
if strings.Compare(response.ContractAddress, common2.MustAddressToBech32(deployedStakingContractAddress)) != 0 {
test.Errorf("Wrong ContractAddress is returned (expected %#v, got %#v)",
common2.MustAddressToBech32(deployedStakingContractAddress),
response.ContractAddress)
}
if response.Nonce != 0 {
test.Errorf("Wrong nonce is returned")
}
}

@ -28,11 +28,10 @@ type Service struct {
// New returns new client support 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, getDeployedStakingContract),
server: clientService.NewServer(stateReader, callFaucetContract),
ip: ip,
port: strconv.Itoa(port + ClientServicePortDiff)}
}

@ -1,9 +0,0 @@
### Staking Service
Staking service is used to send a stake to beacon chain to get a ticket to join Harmony blockchain.
Staking service first gets beacon info which is a result of networkinfo service, then create a staking transaction and send it to beacon chain. As we are currently using ethereum account model, the staking transaction is an ethereum transaction. In ethereum, to create a transaction, a client needs to call to Ethereum network to get the current account nonce (required), suggested gas (optional), and chainID (optional).
For development purpose, after getting beacon info, the staking service of the new node should send a RPC request to beacon chain to get the account nonce as the beacon chain already has a client service which serves that request. In the long term, we should switch to send a gossip request to beancon chain instead of a RPC call.
**TODO**: Rework on this matter.

@ -1,261 +0,0 @@
package staking
import (
"math/big"
"strings"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
protobuf "github.com/golang/protobuf/proto"
"github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/accounts/abi"
proto "github.com/harmony-one/harmony/api/client/service/proto"
proto_common "github.com/harmony-one/harmony/api/proto"
"github.com/harmony-one/harmony/api/proto/message"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
"github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/genesis"
hmykey "github.com/harmony-one/harmony/internal/keystore"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
)
const (
// WaitTime is the delay time for resending staking transaction if the previous transaction did not get approved.
WaitTime = 5 * time.Second
// StakingContractAddress is the staking deployed contract address
StakingContractAddress = "TODO(minhdoan): Create a PR to generate staking contract address"
// StakingAmount is the amount of stake to put
StakingAmount = 10
)
// State is the state of staking service.
type State byte
// Service is the staking service.
// Service requires private key here which is not a right design.
// In stead in the right design, the end-user who runs mining needs to provide signed tx to this service.
type Service struct {
host p2p.Host
stopChan chan struct{}
stoppedChan chan struct{}
account accounts.Account
blsPublicKey *bls.PublicKey
stakingAmount int64
state State
beaconChain *core.BlockChain
messageChan chan *msg_pb.Message
}
// New returns staking service.
func New(host p2p.Host, account accounts.Account, beaconChain *core.BlockChain, blsPublicKey *bls.PublicKey) *Service {
return &Service{
host: host,
stopChan: make(chan struct{}),
stoppedChan: make(chan struct{}),
blsPublicKey: blsPublicKey,
stakingAmount: StakingAmount,
beaconChain: beaconChain,
}
}
// StartService starts staking service.
func (s *Service) StartService() {
utils.Logger().Info().Msg("Start Staking Service")
s.Run()
}
// Run runs staking.
func (s *Service) Run() {
tick := time.NewTicker(WaitTime)
go func() {
defer close(s.stoppedChan)
// Do service first time and after that doing it every 5 minutes.
// The reason we have to do it in every x minutes because of beacon chain syncing.
time.Sleep(WaitTime)
s.DoService()
for {
select {
case <-tick.C:
if s.IsStaked() {
return
}
//s.DoService()
return
case <-s.stopChan:
return
}
}
}()
}
// IsStaked checks if the txn gets accepted and approved in the beacon chain.
func (s *Service) IsStaked() bool {
return false
}
// DoService does staking.
func (s *Service) DoService() {
utils.Logger().Info().Msg("Trying to send a staking transaction.")
// TODO: no need to sync beacon chain to stake
//if s.beaconChain == nil {
// utils.Logger().Info().Msg("Can not send a staking transaction because of nil beacon chain.")
// return
//}
if msg := s.createStakingMessage(); msg == nil {
utils.Logger().Error().Msg("Can not create staking transaction")
} else if err := s.host.SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeacon}, host.ConstructP2pMessage(byte(17), msg)); err != nil {
utils.Logger().Warn().Err(err).Msg("cannot send staking message")
} else {
utils.Logger().Info().Msg("Sent staking transaction to the network.")
}
}
func (s *Service) getStakingInfo() *proto.StakingContractInfoResponse {
address := s.account.Address
state, err := s.beaconChain.State()
if err != nil {
utils.Logger().Error().Msg("error to get beacon chain state when getting staking info")
return nil
}
balance := state.GetBalance(address)
if balance == common.Big0 {
utils.Logger().Error().Msg("account balance empty when getting staking info")
return nil
}
nonce := state.GetNonce(address)
if nonce == 0 {
utils.Logger().Error().Msg("nonce zero when getting staking info")
return nil
}
return &proto.StakingContractInfoResponse{
ContractAddress: StakingContractAddress,
Balance: balance.Bytes(),
Nonce: nonce,
}
}
func (s *Service) getFakeStakingInfo() *proto.StakingContractInfoResponse {
balance := big.NewInt(denominations.One)
nonce := uint64(0) // TODO: make it a incrementing field
priKey := genesis.GenesisBeaconAccountPriKey
contractAddress := crypto.PubkeyToAddress(priKey.PublicKey)
stakingContractAddress := crypto.CreateAddress(contractAddress, uint64(nonce))
return &proto.StakingContractInfoResponse{
ContractAddress: common2.MustAddressToBech32(stakingContractAddress),
Balance: balance.Bytes(),
Nonce: nonce,
}
}
// Constructs the staking message
func constructStakingMessage(ts types.Transactions) []byte {
tsBytes, err := rlp.EncodeToBytes(ts)
if err == nil {
msg := &message.Message{
Type: message.MessageType_NEWNODE_BEACON_STAKING,
Request: &message.Message_Staking{
Staking: &message.StakingRequest{
Transaction: tsBytes,
NodeId: "",
},
},
}
if data, err := protobuf.Marshal(msg); err == nil {
return data
}
}
utils.Logger().Error().Err(err).Msg("Error when creating staking message")
return nil
}
func (s *Service) createRawStakingMessage() []byte {
// TODO(minhdoan): Enable getStakingInfo back after testing.
stakingInfo := s.getFakeStakingInfo()
toAddress := common2.ParseAddr(stakingInfo.ContractAddress)
abi, err := abi.JSON(strings.NewReader(contracts.StakeLockContractABI))
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to generate staking contract's ABI")
}
// TODO: the bls address should be signed by the bls private key
blsPubKeyBytes := s.blsPublicKey.Serialize()
if len(blsPubKeyBytes) != 96 {
utils.Logger().Error().Int("size", len(blsPubKeyBytes)).Msg("Wrong bls pubkey size")
return []byte{}
}
blsPubKeyPart1 := [32]byte{}
blsPubKeyPart2 := [32]byte{}
blsPubKeyPart3 := [32]byte{}
copy(blsPubKeyPart1[:], blsPubKeyBytes[:32])
copy(blsPubKeyPart2[:], blsPubKeyBytes[32:64])
copy(blsPubKeyPart3[:], blsPubKeyBytes[64:96])
bytesData, err := abi.Pack("lock", blsPubKeyPart1, blsPubKeyPart2, blsPubKeyPart3)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to generate ABI function bytes data")
}
tx := types.NewTransaction(
stakingInfo.Nonce,
toAddress,
0,
big.NewInt(s.stakingAmount),
params.TxGas*10,
nil,
bytesData,
)
// This is currently not called.
chainID := big.NewInt(1) // TODO: wire the correct chain ID after staking flow is revamped.
if signedTx, err := hmykey.SignTx(s.account, tx, chainID); err == nil {
ts := types.Transactions{signedTx}
return constructStakingMessage(ts)
}
return nil
}
func (s *Service) createStakingMessage() []byte {
if msg := s.createRawStakingMessage(); msg != nil {
return proto_common.ConstructStakingMessage(msg)
}
return nil
}
// StopService stops staking service.
func (s *Service) StopService() {
utils.Logger().Info().Msg("Stopping staking service.")
s.stopChan <- struct{}{}
<-s.stoppedChan
utils.Logger().Info().Msg("Role conversion stopped.")
}
// NotifyService notify service
func (s *Service) NotifyService(params map[string]interface{}) {
return
}
// SetMessageChan sets up message channel to service.
func (s *Service) SetMessageChan(messageChan chan *msg_pb.Message) {
s.messageChan = messageChan
}
// APIs for the services.
func (s *Service) APIs() []rpc.API {
return nil
}

@ -8,17 +8,14 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/core/types"
common2 "github.com/harmony-one/harmony/internal/common"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/genesis"
"github.com/harmony-one/harmony/internal/utils"
)
@ -33,106 +30,8 @@ type builtInSC uint
// List of smart contract type built-in
const (
scFaucet builtInSC = iota
scStaking
)
// AddStakingContractToPendingTransactions adds the deposit smart contract the genesis block.
func (node *Node) AddStakingContractToPendingTransactions() {
// Add a contract deployment transaction
//Generate contract key and associate funds with the smart contract
priKey := genesis.GenesisBeaconAccountPriKey
contractAddress := crypto.PubkeyToAddress(priKey.PublicKey)
//Initially the smart contract should have minimal funds.
contractFunds := big.NewInt(0)
contractFunds = contractFunds.Mul(contractFunds, big.NewInt(denominations.One))
dataEnc := common.FromHex(contracts.StakeLockContractBin)
// Unsigned transaction to avoid the case of transaction address.
mycontracttx, _ := types.SignTx(types.NewContractCreation(uint64(0), node.Consensus.ShardID, contractFunds, params.TxGasContractCreation*100, nil, dataEnc), types.HomesteadSigner{}, priKey)
//node.StakingContractAddress = crypto.CreateAddress(contractAddress, uint64(0))
node.StakingContractAddress = node.generateDeployedStakingContractAddress(contractAddress)
node.addPendingTransactions(types.Transactions{mycontracttx})
}
// 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(contractAddress common.Address) common.Address {
//Correct Way 1:
//node.SendTx(mycontracttx)
//receipts := node.worker.GetCurrentReceipts()
//deployedcontractaddress = receipts[len(receipts)-1].ContractAddress //get the address from the receipt
//Correct Way 2:
//nonce := GetNonce(contractAddress)
//deployedAddress := crypto.CreateAddress(contractAddress, uint64(nonce))
nonce := 0
return crypto.CreateAddress(contractAddress, uint64(nonce))
}
// QueryStakeInfo queries the stake info from the stake contract.
func (node *Node) QueryStakeInfo() *structs.StakeInfoReturnValue {
abi, err := abi.JSON(strings.NewReader(contracts.StakeLockContractABI))
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to generate staking contract's ABI")
return nil
}
bytesData, err := abi.Pack("listLockedAddresses")
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to generate ABI function bytes data")
return nil
}
priKey := genesis.GenesisBeaconAccountPriKey
deployerAddress := crypto.PubkeyToAddress(priKey.PublicKey)
state, err := node.Blockchain().State()
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to get blockchain state")
return nil
}
stakingContractAddress := crypto.CreateAddress(deployerAddress, uint64(0))
tx := types.NewTransaction(
state.GetNonce(deployerAddress),
stakingContractAddress,
node.NodeConfig.ShardID,
nil,
math.MaxUint64,
nil,
bytesData,
)
signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, priKey)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to sign contract call tx")
return nil
}
output, err := node.ContractCaller.CallContract(signedTx)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to call staking contract")
return nil
}
ret := &structs.StakeInfoReturnValue{}
err = abi.Unpack(ret, "listLockedAddresses", output)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to unpack stake info")
return nil
}
return ret
}
func (node *Node) getDeployedStakingContract() common.Address {
if node.NodeConfig.GetNetworkType() == nodeconfig.Mainnet {
return common.Address{}
}
return node.StakingContractAddress
}
// GetNonceOfAddress returns nonce of an address.
func (node *Node) GetNonceOfAddress(address common.Address) uint64 {
state, err := node.Blockchain().State()
@ -224,11 +123,6 @@ func (node *Node) AddContractKeyAndAddress(t builtInSC) {
contractDeployerKey, _ := ecdsa.GenerateKey(crypto.S256(), strings.NewReader("Test contract key string stream that is fixed so that generated test key are deterministic every time"))
node.ContractDeployerKey = contractDeployerKey
node.ContractAddresses = append(node.ContractAddresses, crypto.CreateAddress(crypto.PubkeyToAddress(contractDeployerKey.PublicKey), uint64(0)))
case scStaking:
// staking contract
node.CurrentStakes = make(map[common.Address]*structs.StakeInfo)
stakingPrivKey := genesis.GenesisBeaconAccountPriKey
node.StakingContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(stakingPrivKey.PublicKey), uint64(0))
default:
utils.Logger().Error().Interface("unknown SC", t).Msg("AddContractKeyAndAddress")
}

@ -22,7 +22,6 @@ import (
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/contracts"
"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/drand"
@ -151,11 +150,6 @@ type Node struct {
// Service manager.
serviceManager *service.Manager
//Staked Accounts and Contract
CurrentStakes map[common.Address]*structs.StakeInfo //This will save the latest information about staked nodes.
StakingContractAddress common.Address
WithdrawStakeFunc []byte
// Demo account.
DemoContractAddress common.Address
LotteryManagerPrivateKey *ecdsa.PrivateKey

@ -151,8 +151,9 @@ func (node *Node) proposeBeaconShardState(block *types.Block) error {
return nil
}
nextEpoch := new(big.Int).Add(block.Header().Epoch(), common.Big1)
// TODO: add logic for EPoS
shardState, err := core.CalculateNewShardState(
node.Blockchain(), nextEpoch, &node.CurrentStakes)
node.Blockchain(), nextEpoch, nil)
if err != nil {
return err
}

@ -12,7 +12,6 @@ import (
"github.com/harmony-one/harmony/api/service/explorer"
"github.com/harmony-one/harmony/api/service/metrics"
"github.com/harmony-one/harmony/api/service/networkinfo"
"github.com/harmony-one/harmony/api/service/staking"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
@ -30,7 +29,7 @@ func (node *Node) setupForValidator() {
// Register new block service.
node.serviceManager.RegisterService(service.BlockProposal, blockproposal.New(node.Consensus.ReadySignal, node.WaitForConsensusReadyV2))
// Register client support service.
node.serviceManager.RegisterService(service.ClientSupport, clientsupport.New(node.Blockchain().State, node.CallFaucetContract, node.getDeployedStakingContract, node.SelfPeer.IP, node.SelfPeer.Port))
node.serviceManager.RegisterService(service.ClientSupport, clientsupport.New(node.Blockchain().State, node.CallFaucetContract, node.SelfPeer.IP, node.SelfPeer.Port))
// Register new metrics service
if node.NodeConfig.GetMetricsFlag() {
node.serviceManager.RegisterService(service.Metrics, metrics.New(&node.SelfPeer, node.NodeConfig.ConsensusPubKey.SerializeToHexStr(), node.NodeConfig.GetPushgatewayIP(), node.NodeConfig.GetPushgatewayPort()))
@ -48,8 +47,6 @@ func (node *Node) setupForNewNode() {
// TODO determine the role of new node, currently assume it is beacon node
nodeConfig, chanPeer := node.initNodeConfiguration()
// Register staking service.
node.serviceManager.RegisterService(service.Staking, staking.New(node.host, node.StakingAccount, node.Beaconchain(), node.NodeConfig.ConsensusPubKey))
// Register peer discovery service. "0" is the beacon shard ID
node.serviceManager.RegisterService(service.PeerDiscovery, discovery.New(node.host, nodeConfig, chanPeer, node.AddBeaconPeer))
// Register networkinfo service. "0" is the beacon shard ID

@ -1,91 +0,0 @@
package node
import (
"encoding/hex"
"math/big"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/core"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/internal/utils"
"github.com/ethereum/go-ethereum/common/hexutil"
)
//constants related to staking
//The first four bytes of the call data for a function call specifies the function to be called.
//It is the first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3)
//Refer: https://solidity.readthedocs.io/en/develop/abi-spec.html
const (
funcSingatureBytes = 4
lockPeriodInEpochs = 3 // This should be in sync with contracts/StakeLockContract.sol
)
// UpdateStakingList updates staking list from the given StakeInfo query result.
func (node *Node) UpdateStakingList(stakeInfoReturnValue *structs.StakeInfoReturnValue) {
utils.Logger().Info().Interface("contractState", stakeInfoReturnValue).Msg("Updating staking list")
if stakeInfoReturnValue == nil {
return
}
node.CurrentStakes = make(map[common.Address]*structs.StakeInfo)
for i, addr := range stakeInfoReturnValue.LockedAddresses {
blockNum := stakeInfoReturnValue.BlockNums[i]
lockPeriodCount := stakeInfoReturnValue.LockPeriodCounts[i]
startEpoch := core.GetEpochFromBlockNumber(blockNum.Uint64())
curEpoch := core.GetEpochFromBlockNumber(node.Blockchain().CurrentBlock().NumberU64())
if startEpoch == curEpoch {
continue // The token are counted into stakes at the beginning of next epoch.
}
// True if the token is still staked within the locking period.
if curEpoch-startEpoch <= lockPeriodCount.Uint64()*lockPeriodInEpochs {
blsPubKey := shard.BlsPublicKey{}
copy(blsPubKey[:32], stakeInfoReturnValue.BlsPubicKeys1[i][:])
copy(blsPubKey[32:48], stakeInfoReturnValue.BlsPubicKeys2[i][:16])
node.CurrentStakes[addr] = &structs.StakeInfo{
Account: addr,
BlsPublicKey: blsPubKey,
BlockNum: blockNum,
LockPeriodCount: lockPeriodCount,
Amount: stakeInfoReturnValue.Amounts[i],
}
}
}
}
func (node *Node) printStakingList() {
for addr, stakeInfo := range node.CurrentStakes {
utils.Logger().Info().
Str("Address", addr.String()).
Str("BlsPubKey", hex.EncodeToString(stakeInfo.BlsPublicKey[:])).
Interface("BlockNum", stakeInfo.BlockNum).
Interface("lockPeriodCount", stakeInfo.LockPeriodCount).
Interface("amount", stakeInfo.Amount).
Msg("")
}
}
//The first four bytes of the call data for a function call specifies the function to be called.
//It is the first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3)
//Refer: https://solidity.readthedocs.io/en/develop/abi-spec.html
func decodeStakeCall(getData []byte) int64 {
value := new(big.Int)
value.SetBytes(getData[funcSingatureBytes:]) //Escape the method call.
return value.Int64()
}
//The first four bytes of the call data for a function call specifies the function to be called.
//It is the first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3)
//Refer: https://solidity.readthedocs.io/en/develop/abi-spec.html
//gets the function signature from data.
func decodeFuncSign(data []byte) string {
funcSign := hexutil.Encode(data[:funcSingatureBytes]) //The function signature is first 4 bytes of data in ethereum
return funcSign
}

@ -1,76 +0,0 @@
package node
import (
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/contracts/structs"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
)
var (
amount = big.NewInt(10)
blockNum = big.NewInt(15000)
lockPeriodCount = big.NewInt(1)
testAddress = common.Address{123}
testBlsPubKey1 = [32]byte{}
testBlsPubKey2 = [32]byte{}
testBlsPubKey3 = [32]byte{}
)
func TestUpdateStakingList(t *testing.T) {
blsKey := bls.RandPrivateKey()
pubKey := blsKey.GetPublicKey()
leader := p2p.Peer{IP: "127.0.0.1", Port: "9882", ConsensusPubKey: pubKey}
priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "9902")
host, err := p2pimpl.NewHost(&leader, priKey)
if err != nil {
t.Fatalf("newhost failure: %v", err)
}
consensus, err := consensus.New(host, 0, leader, blsKey)
if err != nil {
t.Fatalf("Cannot craeate consensus: %v", err)
}
node := New(host, consensus, testDBFactory, false)
node.BlockPeriod = 8 * time.Second
for i := 0; i < 1; i++ {
selectedTxs, selectedStakingTxs := node.getTransactionsForNewBlock(common.Address{})
node.Worker.CommitTransactions(selectedTxs, selectedStakingTxs, common.Address{})
block, err := node.Worker.FinalizeNewBlock([]byte{}, []byte{}, 0, common.Address{}, nil, nil)
// The block must first be finalized before being added to the blockchain.
if err != nil {
t.Errorf("Error when finalizing block: %v", err)
}
block.Header()
err = node.AddNewBlock(block)
if err != nil {
t.Errorf("Error when adding new block: %v", err)
}
}
stakeInfo := &structs.StakeInfoReturnValue{
LockedAddresses: []common.Address{testAddress},
BlsPubicKeys1: [][32]byte{testBlsPubKey1},
BlsPubicKeys2: [][32]byte{testBlsPubKey2},
BlsPubicKeys3: [][32]byte{testBlsPubKey3},
BlockNums: []*big.Int{blockNum},
LockPeriodCounts: []*big.Int{lockPeriodCount},
Amounts: []*big.Int{amount},
}
node.UpdateStakingList(stakeInfo)
/*
if node.CurrentStakes[testAddress].Amount.Cmp(amount) != 0 {
t.Error("Stake Info is not updated correctly")
}
*/
}
Loading…
Cancel
Save