Skip to content

Commit

Permalink
feat: change staking overlay (#4720)
Browse files Browse the repository at this point in the history
  • Loading branch information
nugaon authored Jul 10, 2024
1 parent 5adf59b commit 2b2036b
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 0 deletions.
17 changes: 17 additions & 0 deletions pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ func NewBee(
}
}

var changedOverlay bool
if targetNeighborhood != "" {
neighborhood, err := swarm.ParseBitStrAddress(targetNeighborhood)
if err != nil {
Expand Down Expand Up @@ -311,6 +312,7 @@ func NewBee(
if err != nil {
return nil, fmt.Errorf("statestore: save new overlay: %w", err)
}
changedOverlay = true
}
}

Expand Down Expand Up @@ -966,6 +968,21 @@ func NewBee(

stakingContract := staking.New(overlayEthAddress, stakingContractAddress, abiutil.MustParseABI(chainCfg.StakingABI), bzzTokenAddress, transactionService, common.BytesToHash(nonce))

if chainEnabled && changedOverlay {
stake, err := stakingContract.GetStake(ctx)
if err != nil {
return nil, errors.New("getting stake balance")
}
if stake.Cmp(big.NewInt(0)) > 0 {
logger.Debug("changing overlay address in staking contract")
tx, err := stakingContract.ChangeStakeOverlay(ctx, common.BytesToHash(nonce))
if err != nil {
return nil, fmt.Errorf("cannot change staking overlay address: %v", err.Error())
}
logger.Info("overlay address changed in staking contract", "transaction", tx)
}
}

var (
pullerService *puller.Puller
agent *storageincentives.Agent
Expand Down
12 changes: 12 additions & 0 deletions pkg/storageincentives/staking/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var (

type Contract interface {
DepositStake(ctx context.Context, stakedAmount *big.Int) (common.Hash, error)
ChangeStakeOverlay(ctx context.Context, nonce common.Hash) (common.Hash, error)
GetStake(ctx context.Context) (*big.Int, error)
WithdrawAllStake(ctx context.Context) (common.Hash, error)
RedistributionStatuser
Expand Down Expand Up @@ -223,6 +224,17 @@ func (c *contract) DepositStake(ctx context.Context, stakedAmount *big.Int) (com
return receipt.TxHash, nil
}

// ChangeStakeOverlay only changes the overlay address used in the redistribution game.
func (c *contract) ChangeStakeOverlay(ctx context.Context, nonce common.Hash) (common.Hash, error) {
c.overlayNonce = nonce
receipt, err := c.sendDepositStakeTransaction(ctx, new(big.Int), c.overlayNonce)
if err != nil {
return common.Hash{}, err
}

return receipt.TxHash, nil
}

func (c *contract) GetStake(ctx context.Context) (*big.Int, error) {
stakedAmount, err := c.getStake(ctx)
if err != nil {
Expand Down
196 changes: 196 additions & 0 deletions pkg/storageincentives/staking/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"math/big"
"strings"
"testing"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -485,6 +486,201 @@ func TestDepositStake(t *testing.T) {
})
}

func TestChangeStakeOverlay(t *testing.T) {
t.Parallel()

ctx := context.Background()
owner := common.HexToAddress("abcd")
stakingContractAddress := common.HexToAddress("ffff")
bzzTokenAddress := common.HexToAddress("eeee")
nonce := common.BytesToHash(make([]byte, 32))
txHashOverlayChanged := common.HexToHash("c3a7")
stakedAmount := big.NewInt(0)
txHashApprove := common.HexToHash("abb0")

t.Run("ok", func(t *testing.T) {
t.Parallel()

expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
if err != nil {
t.Fatal(err)
}

contract := staking.New(
owner,
stakingContractAddress,
stakingContractABI,
bzzTokenAddress,
transactionMock.New(
transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
if *request.To == stakingContractAddress {
if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
}
return txHashOverlayChanged, nil
}
return common.Hash{}, errors.New("sent to wrong contract")
}),
transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
if txHash == txHashOverlayChanged {
return &types.Receipt{
Status: 1,
}, nil
}
return nil, errors.New("unknown tx hash")
}),
),
nonce,
)

_, err = contract.ChangeStakeOverlay(ctx, nonce)
if err != nil {
t.Fatal(err)
}
})

t.Run("send tx failed", func(t *testing.T) {
t.Parallel()

contract := staking.New(
owner,
stakingContractAddress,
stakingContractABI,
bzzTokenAddress,
transactionMock.New(
transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
if *request.To == stakingContractAddress {
return common.Hash{}, errors.New("send transaction failed")
}
return common.Hash{}, errors.New("sent to wrong contract")
}),
),
nonce,
)

_, err := contract.ChangeStakeOverlay(ctx, nonce)
if err == nil || !strings.Contains(err.Error(), "send transaction failed") {
t.Fatal("expected different error")
}
})

t.Run("invalid call data", func(t *testing.T) {
t.Parallel()

expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
if err != nil {
t.Fatal(err)
}

contract := staking.New(
owner,
stakingContractAddress,
stakingContractABI,
bzzTokenAddress,
transactionMock.New(
transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
if *request.To == stakingContractAddress {
if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
}
return txHashApprove, nil
}
return common.Hash{}, errors.New("sent to wrong contract")
}),
),
nonce,
)

newNonce := make([]byte, 32)
copy(newNonce, nonce[:])
newNonce[0]++
_, err = contract.ChangeStakeOverlay(ctx, common.BytesToHash(newNonce))
if err == nil || !strings.Contains(err.Error(), "got wrong call data. wanted") {
t.Fatal("expected different error")
}
})

t.Run("transaction reverted", func(t *testing.T) {
t.Parallel()

expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
if err != nil {
t.Fatal(err)
}

contract := staking.New(
owner,
stakingContractAddress,
stakingContractABI,
bzzTokenAddress,
transactionMock.New(
transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
if *request.To == stakingContractAddress {
if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
}
return txHashOverlayChanged, nil
}
return txHashOverlayChanged, errors.New("sent to wrong contract")
}),
transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
if txHash == txHashOverlayChanged {
return &types.Receipt{
Status: 0,
}, nil
}
return nil, errors.New("unknown tx hash")
}),
),
nonce,
)

_, err = contract.ChangeStakeOverlay(ctx, nonce)
if !errors.Is(err, transaction.ErrTransactionReverted) {
t.Fatalf("expeted %v, got %v", transaction.ErrTransactionReverted, err)
}
})

t.Run("transaction error", func(t *testing.T) {
t.Parallel()

expectedCallData, err := stakingContractABI.Pack("manageStake", nonce, stakedAmount)
if err != nil {
t.Fatal(err)
}

contract := staking.New(
owner,
stakingContractAddress,
stakingContractABI,
bzzTokenAddress,
transactionMock.New(
transactionMock.WithSendFunc(func(ctx context.Context, request *transaction.TxRequest, boost int) (txHash common.Hash, err error) {
if *request.To == stakingContractAddress {
if !bytes.Equal(expectedCallData[:80], request.Data[:80]) {
return common.Hash{}, fmt.Errorf("got wrong call data. wanted %x, got %x", expectedCallData, request.Data)
}
return txHashOverlayChanged, nil
}
return common.Hash{}, errors.New("sent to wrong contract")
}),
transactionMock.WithWaitForReceiptFunc(func(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
if txHash == txHashOverlayChanged {
return nil, fmt.Errorf("unknown error")
}
return nil, errors.New("unknown tx hash")
}),
),
nonce,
)

_, err = contract.ChangeStakeOverlay(ctx, nonce)
if err == nil || !strings.Contains(err.Error(), "unknown error") {
t.Fatal("expected different error")
}
})
}

func TestGetStake(t *testing.T) {
t.Parallel()

Expand Down
4 changes: 4 additions & 0 deletions pkg/storageincentives/staking/mock/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ func (s *stakingContractMock) DepositStake(ctx context.Context, stakedAmount *bi
return s.depositStake(ctx, stakedAmount)
}

func (s *stakingContractMock) ChangeStakeOverlay(_ context.Context, h common.Hash) (common.Hash, error) {
return h, nil
}

func (s *stakingContractMock) GetStake(ctx context.Context) (*big.Int, error) {
return s.getStake(ctx)
}
Expand Down

0 comments on commit 2b2036b

Please sign in to comment.