205 lines
5.6 KiB
Go
205 lines
5.6 KiB
Go
package incentivisation
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
|
gethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
var (
|
|
nodeOne = []byte{0x01}
|
|
nodeTwo = []byte{0x02}
|
|
)
|
|
|
|
type MockContract struct {
|
|
currentSession *big.Int
|
|
activeNodes [][]byte
|
|
inactiveNodes [][]byte
|
|
votes []Vote
|
|
}
|
|
|
|
type Vote struct {
|
|
joinNodes []gethcommon.Address
|
|
removeNodes []gethcommon.Address
|
|
}
|
|
|
|
type MockWhisper struct {
|
|
sentMessages []types.NewMessage
|
|
filterMessages []*types.Message
|
|
}
|
|
|
|
func BuildMockContract() *MockContract {
|
|
contract := &MockContract{
|
|
currentSession: big.NewInt(0),
|
|
}
|
|
|
|
contract.activeNodes = append(contract.activeNodes, nodeOne)
|
|
contract.inactiveNodes = append(contract.activeNodes, nodeTwo)
|
|
return contract
|
|
}
|
|
|
|
func (c *MockContract) Vote(opts *bind.TransactOpts, joinNodes []gethcommon.Address, removeNodes []gethcommon.Address) (*gethtypes.Transaction, error) {
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *MockContract) VoteSync(opts *bind.TransactOpts, joinNodes []gethcommon.Address, removeNodes []gethcommon.Address) (*gethtypes.Transaction, error) {
|
|
c.votes = append(c.votes, Vote{
|
|
joinNodes: joinNodes,
|
|
removeNodes: removeNodes,
|
|
})
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *MockContract) GetCurrentSession(opts *bind.CallOpts) (*big.Int, error) {
|
|
return c.currentSession, nil
|
|
}
|
|
func (c *MockContract) Registered(opts *bind.CallOpts, publicKey []byte) (bool, error) {
|
|
|
|
for _, e := range c.activeNodes {
|
|
if bytes.Equal(publicKey, e) {
|
|
return true, nil
|
|
}
|
|
}
|
|
|
|
for _, e := range c.inactiveNodes {
|
|
if bytes.Equal(publicKey, e) {
|
|
return true, nil
|
|
}
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
func (c *MockContract) RegisterNode(opts *bind.TransactOpts, publicKey []byte, ip uint32, port uint16) (*gethtypes.Transaction, error) {
|
|
c.inactiveNodes = append(c.inactiveNodes, publicKey)
|
|
return nil, nil
|
|
}
|
|
func (c *MockContract) ActiveNodeCount(opts *bind.CallOpts) (*big.Int, error) {
|
|
return big.NewInt(int64(len(c.activeNodes))), nil
|
|
}
|
|
func (c *MockContract) InactiveNodeCount(opts *bind.CallOpts) (*big.Int, error) {
|
|
return big.NewInt(int64(len(c.inactiveNodes))), nil
|
|
}
|
|
|
|
func (c *MockContract) GetNode(opts *bind.CallOpts, index *big.Int) ([]byte, uint32, uint16, uint32, uint32, error) {
|
|
return c.activeNodes[index.Int64()], 0, 0, 0, 0, nil
|
|
}
|
|
func (c *MockContract) GetInactiveNode(opts *bind.CallOpts, index *big.Int) ([]byte, uint32, uint16, uint32, uint32, error) {
|
|
return c.inactiveNodes[index.Int64()], 0, 0, 0, 0, nil
|
|
}
|
|
|
|
func (w *MockWhisper) Post(ctx context.Context, req types.NewMessage) ([]byte, error) {
|
|
w.sentMessages = append(w.sentMessages, req)
|
|
return nil, nil
|
|
}
|
|
func (w *MockWhisper) NewMessageFilter(req types.Criteria) (string, error) {
|
|
return "", nil
|
|
}
|
|
func (w *MockWhisper) AddPrivateKey(ctx context.Context, privateKey types.HexBytes) (string, error) {
|
|
return "", nil
|
|
}
|
|
func (w *MockWhisper) DeleteKeyPair(ctx context.Context, key string) (bool, error) {
|
|
return true, nil
|
|
}
|
|
func (w *MockWhisper) GenerateSymKeyFromPassword(ctx context.Context, passwd string) (string, error) {
|
|
return "", nil
|
|
}
|
|
func (w *MockWhisper) GetFilterMessages(id string) ([]*types.Message, error) {
|
|
return w.filterMessages, nil
|
|
}
|
|
|
|
func TestIncentivisationSuite(t *testing.T) {
|
|
suite.Run(t, new(IncentivisationSuite))
|
|
}
|
|
|
|
type IncentivisationSuite struct {
|
|
suite.Suite
|
|
service *Service
|
|
mockWhisper *MockWhisper
|
|
mockContract *MockContract
|
|
}
|
|
|
|
func (s *IncentivisationSuite) SetupTest() {
|
|
privateKey, err := crypto.GenerateKey()
|
|
config := &ServiceConfig{
|
|
IP: "192.168.1.1",
|
|
}
|
|
contract := BuildMockContract()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
w := &MockWhisper{}
|
|
s.service = New(privateKey, w, config, contract)
|
|
s.mockWhisper = w
|
|
s.mockContract = contract
|
|
}
|
|
|
|
func (s *IncentivisationSuite) TestStart() {
|
|
err := s.service.Start(nil)
|
|
s.Require().NoError(err)
|
|
}
|
|
|
|
func (s *IncentivisationSuite) TestPerform() {
|
|
err := s.service.Start(nil)
|
|
s.Require().NoError(err)
|
|
|
|
err = s.service.perform()
|
|
s.Require().NoError(err)
|
|
|
|
// It registers with the contract if not registered
|
|
registered, err := s.service.registered()
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(true, registered)
|
|
|
|
now := time.Now().Unix()
|
|
// Add some envelopes
|
|
s.mockWhisper.filterMessages = []*types.Message{
|
|
{
|
|
// We strip the first byte when processing
|
|
Sig: append(nodeOne, nodeOne[0]),
|
|
Timestamp: uint32(now - pingIntervalAllowance),
|
|
},
|
|
{
|
|
Sig: append(nodeOne, nodeOne[0]),
|
|
Timestamp: uint32(now - (pingIntervalAllowance * 2)),
|
|
},
|
|
{
|
|
Sig: append(nodeTwo, nodeTwo[0]),
|
|
Timestamp: uint32(now - (pingIntervalAllowance * 2)),
|
|
},
|
|
}
|
|
|
|
// It publishes a ping on whisper
|
|
s.Require().Equal(1, len(s.mockWhisper.sentMessages))
|
|
|
|
// It should not vote
|
|
s.Require().Equal(0, len(s.mockContract.votes))
|
|
|
|
// We increase the session
|
|
s.mockContract.currentSession = s.mockContract.currentSession.Add(s.mockContract.currentSession, big.NewInt(1))
|
|
|
|
// We perform again
|
|
err = s.service.perform()
|
|
s.Require().NoError(err)
|
|
|
|
// it should now vote
|
|
s.Require().Equal(1, len(s.mockContract.votes))
|
|
// Node one should have been voted up
|
|
s.Require().Equal(1, len(s.mockContract.votes[0].joinNodes))
|
|
s.Require().Equal(publicKeyBytesToAddress(nodeOne), s.mockContract.votes[0].joinNodes[0])
|
|
// Node two should have been voted down
|
|
s.Require().Equal(1, len(s.mockContract.votes[0].removeNodes))
|
|
s.Require().Equal(publicKeyBytesToAddress(nodeTwo), s.mockContract.votes[0].removeNodes[0])
|
|
|
|
}
|