diff --git a/.github/workflows/full_test.yml b/.github/workflows/full_test.yml index add285e1b..8bb987af7 100644 --- a/.github/workflows/full_test.yml +++ b/.github/workflows/full_test.yml @@ -59,11 +59,14 @@ jobs: if: github.event_name != 'push' || github.ref_name != 'master' || github.ref_type != 'branch' run: go test -timeout 999s -v ./... - - name: Integration Tests - run: | - if [ -d "tests" ]; then - cd tests - ./run_tests.sh - else - echo "The 'tests' folder does not exist." - fi + - name: Integration Tests - brick + run: cd tests && ./run_tests.sh brick + + - name: Integration Tests - sbp + run: cd tests && ./run_tests.sh sbp + + - name: Integration Tests - dpos + run: cd tests && ./run_tests.sh dpos + + - name: Integration Tests - raft + run: cd tests && ./run_tests.sh raft diff --git a/chain/chainhandle.go b/chain/chainhandle.go index 2f4a49acd..70024bffe 100644 --- a/chain/chainhandle.go +++ b/chain/chainhandle.go @@ -603,7 +603,7 @@ func newBlockExecutor(cs *ChainService, bState *state.BlockState, block *types.B // executed by the block factory. commitOnly = true } - bState.SetGasPrice(system.GetGasPriceFromState(bState)) + bState.SetGasPrice(system.GetGasPrice()) bState.Receipts().SetHardFork(cs.cfg.Hardfork, block.BlockNo()) return &blockExecutor{ diff --git a/chain/chainhandle_test.go b/chain/chainhandle_test.go index de0b98b35..a71e1c1bc 100644 --- a/chain/chainhandle_test.go +++ b/chain/chainhandle_test.go @@ -13,7 +13,6 @@ import ( "github.com/aergoio/aergo-lib/db" "github.com/aergoio/aergo/v2/account/key" "github.com/aergoio/aergo/v2/contract" - "github.com/aergoio/aergo/v2/contract/system" "github.com/aergoio/aergo/v2/internal/common" "github.com/aergoio/aergo/v2/state" "github.com/aergoio/aergo/v2/types" @@ -37,7 +36,6 @@ func initTest(t *testing.T, testmode bool) { t.Fatalf("failed init : %s", err.Error()) } types.InitGovernance("dpos", true) - system.InitGovernance("dpos") } diff --git a/chain/chainservice.go b/chain/chainservice.go index 93a328415..e29eec028 100644 --- a/chain/chainservice.go +++ b/chain/chainservice.go @@ -291,7 +291,6 @@ func NewChainService(cfg *cfg.Config) *ChainService { // For a strict governance transaction validation. types.InitGovernance(cs.ConsensusType(), cs.IsPublic()) - system.InitGovernance(cs.ConsensusType()) //reset parameter of aergo.system systemState, err := cs.SDB().GetSystemAccountState() diff --git a/consensus/consensus.go b/consensus/consensus.go index 656c446cc..8d77a4b12 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -69,6 +69,8 @@ type Consensus interface { ChainConsensus ConsensusAccessor Ticker() *time.Ticker + // QueueJob queues block generation job. + // It waits until next block generation time is reached in raft consensus and sbp. QueueJob(now time.Time, jq chan<- interface{}) BlockFactory() BlockFactory QuitChan() chan interface{} diff --git a/consensus/impl/dpos/blockfactory.go b/consensus/impl/dpos/blockfactory.go index b3e291f8a..f8ee9ca7b 100644 --- a/consensus/impl/dpos/blockfactory.go +++ b/consensus/impl/dpos/blockfactory.go @@ -239,7 +239,7 @@ func (bf *BlockFactory) generateBlock(execCtx context.Context, bpi *bpInfo, lpbN bpi.bestBlock.GetHeader().GetBlocksRootHash(), state.SetPrevBlockHash(bpi.bestBlock.BlockHash()), ) - bs.SetGasPrice(system.GetGasPriceFromState(bs)) + bs.SetGasPrice(system.GetGasPrice()) bs.Receipts().SetHardFork(bf.bv, bi.No) bGen := chain.NewBlockGenerator( diff --git a/consensus/impl/dpos/status.go b/consensus/impl/dpos/status.go index 8fa303a02..b6e8f739c 100644 --- a/consensus/impl/dpos/status.go +++ b/consensus/impl/dpos/status.go @@ -6,6 +6,7 @@ import ( "github.com/aergoio/aergo/v2/consensus" "github.com/aergoio/aergo/v2/consensus/impl/dpos/bp" + "github.com/aergoio/aergo/v2/contract/system" "github.com/aergoio/aergo/v2/state" "github.com/aergoio/aergo/v2/types" ) @@ -83,6 +84,10 @@ func (s *Status) Update(block *types.Block) { } bps, _ = s.bps.AddSnapshot(block.BlockNo()) + + // if a system param was changed, apply its new value + system.CommitParams(true) + } else { // Rollback resulting from a reorganization: The code below assumes // that there is no block-by-block rollback; it assumes that the @@ -109,6 +114,11 @@ func (s *Status) Update(block *types.Block) { } else { logger.Debug().Uint64("from block no", block.BlockNo()).Msg("VPR reloaded") } + + // if a system param was changed, discard its new value + // this is mainly for block revert case + // the params are reloaded from db on block reorganization + system.CommitParams(false) } s.libState.gc(bps) diff --git a/consensus/impl/raftv2/blockfactory.go b/consensus/impl/raftv2/blockfactory.go index 960d7f61f..55b0baf67 100644 --- a/consensus/impl/raftv2/blockfactory.go +++ b/consensus/impl/raftv2/blockfactory.go @@ -237,7 +237,7 @@ func (bf *BlockFactory) Ticker() *time.Ticker { return time.NewTicker(BlockFactoryTickMs) } -// QueueJob send a block triggering information to jq. +// QueueJob send a block triggering information to jq, and hold to wait func (bf *BlockFactory) QueueJob(now time.Time, jq chan<- interface{}) { bf.jobLock.Lock() defer bf.jobLock.Unlock() @@ -279,6 +279,7 @@ func (bf *BlockFactory) QueueJob(now time.Time, jq chan<- interface{}) { logger.Debug().Str("work", work.ToString()).Str("prev", prevToString(prev)).Msg("new work generated") jq <- work + time.Sleep(BlockIntervalMs) } } @@ -522,7 +523,7 @@ func (bf *BlockFactory) generateBlock(work *Work) (*types.Block, *state.BlockSta bestBlock.GetHeader().GetBlocksRootHash(), state.SetPrevBlockHash(bestBlock.BlockHash()), ) - blockState.SetGasPrice(system.GetGasPriceFromState(blockState)) + blockState.SetGasPrice(system.GetGasPrice()) blockState.Receipts().SetHardFork(bf.bv, bi.No) block, err := chain.NewBlockGenerator(bf, work.execCtx, bi, blockState, txOp, RaftSkipEmptyBlock).GenerateBlock() diff --git a/consensus/impl/sbp/sbp.go b/consensus/impl/sbp/sbp.go index cd6e4528e..a8ef44cc0 100644 --- a/consensus/impl/sbp/sbp.go +++ b/consensus/impl/sbp/sbp.go @@ -45,7 +45,7 @@ func (te *txExec) Apply(bState *state.BlockState, tx types.Transaction) error { return err } -// SimpleBlockFactory implments a simple block factory which generate block each cfg.Consensus.BlockInterval. +// SimpleBlockFactory implements a simple block factory which generate block each cfg.Consensus.BlockInterval. // // This can be used for testing purpose. type SimpleBlockFactory struct { @@ -118,6 +118,7 @@ func (s *SimpleBlockFactory) QueueJob(now time.Time, jq chan<- interface{}) { } s.prevBlock = b jq <- b + time.Sleep(s.blockInterval) } } @@ -189,7 +190,7 @@ func (s *SimpleBlockFactory) Start() { prevBlock.GetHeader().GetBlocksRootHash(), state.SetPrevBlockHash(prevBlock.BlockHash()), ) - blockState.SetGasPrice(system.GetGasPriceFromState(blockState)) + blockState.SetGasPrice(system.GetGasPrice()) blockState.Receipts().SetHardFork(s.bv, bi.No) txOp := chain.NewCompTxOp(s.txOp, newTxExec(s.ChainDB, bi)) diff --git a/contract/name/execute.go b/contract/name/execute.go index 68739e853..6dc00e739 100644 --- a/contract/name/execute.go +++ b/contract/name/execute.go @@ -14,23 +14,18 @@ import ( func ExecuteNameTx(bs *state.BlockState, scs *state.ContractState, txBody *types.TxBody, sender, receiver *state.V, blockInfo *types.BlockHeaderInfo) ([]*types.Event, error) { - systemContractState, err := bs.StateDB.GetSystemAccountState() - - ci, err := ValidateNameTx(txBody, sender, scs, systemContractState) + ci, err := ValidateNameTx(txBody, sender, scs) if err != nil { return nil, err } - var events []*types.Event - var nameState *state.V owner := getOwner(scs, []byte(types.AergoName), false) if owner != nil { if bytes.Equal(sender.ID(), owner) { nameState = sender } else { - nameState, err = bs.GetAccountStateV(owner) - if err != nil { + if nameState, err = bs.GetAccountStateV(owner); err != nil { return nil, err } } @@ -38,17 +33,18 @@ func ExecuteNameTx(bs *state.BlockState, scs *state.ContractState, txBody *types nameState = receiver } + var events []*types.Event switch ci.Name { case types.NameCreate: - if err = CreateName(scs, txBody, sender, nameState, - ci.Args[0].(string)); err != nil { + nameArg := ci.Args[0].(string) + if err = CreateName(scs, txBody, sender, nameState, nameArg); err != nil { return nil, err } jsonArgs := "" if blockInfo.ForkVersion < 2 { - jsonArgs = `{"name":"` + ci.Args[0].(string) + `"}` + jsonArgs = `{"name":"` + nameArg + `"}` } else { - jsonArgs = `["` + ci.Args[0].(string) + `"]` + jsonArgs = `["` + nameArg + `"]` } events = append(events, &types.Event{ ContractAddress: receiver.ID(), @@ -57,16 +53,16 @@ func ExecuteNameTx(bs *state.BlockState, scs *state.ContractState, txBody *types JsonArgs: jsonArgs, }) case types.NameUpdate: - if err = UpdateName(bs, scs, txBody, sender, nameState, - ci.Args[0].(string), ci.Args[1].(string)); err != nil { + nameArg := ci.Args[0].(string) + toArg := ci.Args[1].(string) + if err = UpdateName(bs, scs, txBody, sender, nameState, nameArg, toArg); err != nil { return nil, err } jsonArgs := "" if blockInfo.ForkVersion < 2 { - jsonArgs = `{"name":"` + ci.Args[0].(string) + - `","to":"` + ci.Args[1].(string) + `"}` + jsonArgs = `{"name":"` + nameArg + `","to":"` + toArg + `"}` } else { - jsonArgs = `["` + ci.Args[0].(string) + `","` + ci.Args[1].(string) + `"]` + jsonArgs = `["` + nameArg + `","` + toArg + `"]` } events = append(events, &types.Event{ ContractAddress: receiver.ID(), @@ -75,7 +71,8 @@ func ExecuteNameTx(bs *state.BlockState, scs *state.ContractState, txBody *types JsonArgs: jsonArgs, }) case types.SetContractOwner: - ownerState, err := SetContractOwner(bs, scs, ci.Args[0].(string), nameState) + ownerArg := ci.Args[0].(string) + ownerState, err := SetContractOwner(bs, scs, ownerArg, nameState) if err != nil { return nil, err } @@ -87,9 +84,7 @@ func ExecuteNameTx(bs *state.BlockState, scs *state.ContractState, txBody *types return events, nil } -func ValidateNameTx(tx *types.TxBody, sender *state.V, - scs, systemcs *state.ContractState) (*types.CallInfo, error) { - +func ValidateNameTx(tx *types.TxBody, sender *state.V, scs *state.ContractState) (*types.CallInfo, error) { if sender != nil && sender.Balance().Cmp(tx.GetAmountBigInt()) < 0 { return nil, types.ErrInsufficientBalance } @@ -99,30 +94,25 @@ func ValidateNameTx(tx *types.TxBody, sender *state.V, return nil, err } - name := ci.Args[0].(string) - + nameArg := ci.Args[0].(string) switch ci.Name { case types.NameCreate: - namePrice := system.GetNamePriceFromState(systemcs) - if namePrice.Cmp(tx.GetAmountBigInt()) > 0 { + if system.GetNamePrice().Cmp(tx.GetAmountBigInt()) > 0 { return nil, types.ErrTooSmallAmount } - owner := getOwner(scs, []byte(name), false) - if owner != nil { - return nil, fmt.Errorf("aleady occupied %s", string(name)) + if owner := getOwner(scs, []byte(nameArg), false); owner != nil { + return nil, fmt.Errorf("aleady occupied %s", string(nameArg)) } case types.NameUpdate: - namePrice := system.GetNamePriceFromState(systemcs) - if namePrice.Cmp(tx.GetAmountBigInt()) > 0 { + if system.GetNamePrice().Cmp(tx.GetAmountBigInt()) > 0 { return nil, types.ErrTooSmallAmount } - if (!bytes.Equal(tx.Account, []byte(name))) && - (!bytes.Equal(tx.Account, getOwner(scs, []byte(name), false))) { - return nil, fmt.Errorf("owner not matched : %s", name) + if (!bytes.Equal(tx.Account, []byte(nameArg))) && + (!bytes.Equal(tx.Account, getOwner(scs, []byte(nameArg), false))) { + return nil, fmt.Errorf("owner not matched : %s", nameArg) } case types.SetContractOwner: - owner := getOwner(scs, []byte(types.AergoName), false) - if owner != nil { + if owner := getOwner(scs, []byte(types.AergoName), false); owner != nil { return nil, fmt.Errorf("owner aleady set to %s", types.EncodeAddress(owner)) } default: @@ -135,8 +125,6 @@ func ValidateNameTx(tx *types.TxBody, sender *state.V, func SetContractOwner(bs *state.BlockState, scs *state.ContractState, address string, nameState *state.V) (*state.V, error) { - name := []byte(types.AergoName) - rawaddr, err := types.DecodeAddress(address) if err != nil { return nil, err @@ -150,6 +138,7 @@ func SetContractOwner(bs *state.BlockState, scs *state.ContractState, ownerState.AddBalance(nameState.Balance()) nameState.SubBalance(nameState.Balance()) + name := []byte(types.AergoName) if err = registerOwner(scs, name, rawaddr, name); err != nil { return nil, err } diff --git a/contract/name/name.go b/contract/name/name.go index 39e7efebb..9fc8335cf 100644 --- a/contract/name/name.go +++ b/contract/name/name.go @@ -37,12 +37,13 @@ func createName(scs *state.ContractState, name []byte, owner []byte) error { // UpdateName is avaliable after bid implement func UpdateName(bs *state.BlockState, scs *state.ContractState, tx *types.TxBody, sender, receiver *state.V, name, to string) error { - amount := tx.GetAmountBigInt() if len(getAddress(scs, []byte(name))) <= types.NameLength { return fmt.Errorf("%s is not created yet", string(name)) } destination, _ := types.DecodeAddress(to) destination = GetAddress(scs, destination) + + amount := tx.GetAmountBigInt() sender.SubBalance(amount) receiver.AddBalance(amount) contract, err := bs.StateDB.OpenContractStateAccount(types.ToAccountID(destination)) @@ -88,7 +89,7 @@ func Resolve(bs *state.BlockState, name []byte, legacy bool) ([]byte, error) { } func openContract(bs *state.BlockState) (*state.ContractState, error) { - v, err := bs.GetAccountStateV([]byte("aergo.name")) + v, err := bs.GetAccountStateV([]byte(types.AergoName)) if err != nil { return nil, err } @@ -101,8 +102,7 @@ func openContract(bs *state.BlockState) (*state.ContractState, error) { // GetAddress is resolve name for mempool func GetAddress(scs *state.ContractState, name []byte) []byte { - if len(name) == types.AddressLength || - types.IsSpecialAccount(name) { + if len(name) == types.AddressLength || types.IsSpecialAccount(name) { return name } return getAddress(scs, name) @@ -110,8 +110,7 @@ func GetAddress(scs *state.ContractState, name []byte) []byte { // GetAddressLegacy is resolve name for mempool by buggy logic, leaved for backward compatibility func GetAddressLegacy(scs *state.ContractState, name []byte) []byte { - if len(name) == types.AddressLength || - strings.Contains(string(name), ".") { + if len(name) == types.AddressLength || strings.Contains(string(name), ".") { return name } return getAddress(scs, name) diff --git a/contract/name/name_test.go b/contract/name/name_test.go index 2748dcdeb..4c6a5d274 100644 --- a/contract/name/name_test.go +++ b/contract/name/name_test.go @@ -45,13 +45,12 @@ func TestName(t *testing.T) { receiver, _ := sdb.GetStateDB().GetAccountStateV(tx.Recipient) bs := sdb.NewBlockState(sdb.GetRoot()) scs := openContractState(t, bs) - systemcs := openSystemContractState(t, bs) err := CreateName(scs, tx, sender, receiver, name) assert.NoError(t, err, "create name") scs = nextBlockContractState(t, bs, scs) - _, err = ValidateNameTx(tx, sender, scs, systemcs) + _, err = ValidateNameTx(tx, sender, scs) assert.Error(t, err, "same name") ret := getAddress(scs, []byte(name)) diff --git a/contract/system/execute_test.go b/contract/system/execute_test.go index 4d3fe2907..6f1f8acff 100644 --- a/contract/system/execute_test.go +++ b/contract/system/execute_test.go @@ -720,6 +720,8 @@ func TestProposalExecute2(t *testing.T) { blockInfo.No++ blockInfo.ForkVersion = config.AllEnabledHardforkConfig.Version(blockInfo.No) + // BP Count + votingTx := &types.Tx{ Body: &types.TxBody{ Account: sender.ID(), @@ -747,6 +749,8 @@ func TestProposalExecute2(t *testing.T) { internalVoteResult, err := loadVoteResult(scs, GenProposalKey(bpCount.ID())) assert.Equal(t, new(big.Int).Mul(balance2, big.NewInt(3)), internalVoteResult.GetTotal(), "check result total") + // Staking Min + votingTx = &types.Tx{ Body: &types.TxBody{ Account: sender.ID(), @@ -765,6 +769,10 @@ func TestProposalExecute2(t *testing.T) { _, err = ExecuteSystemTx(scs, votingTx.GetBody(), sender3, receiver, blockInfo) assert.NoError(t, err, "could not execute system tx") + // Gas Price + + origGasPrice := GetGasPrice() + votingTx = &types.Tx{ Body: &types.TxBody{ Account: sender.ID(), @@ -782,8 +790,15 @@ func TestProposalExecute2(t *testing.T) { votingTx.Body.Payload = []byte(`{"Name":"v1voteDAO", "Args":["GASPRICE", "1004"]}`) _, err = ExecuteSystemTx(scs, votingTx.GetBody(), sender3, receiver, blockInfo) assert.NoError(t, err, "could not execute system tx") - gasPrice := GetGasPrice() - assert.Equal(t, balance0_5, gasPrice, "result of gas price voting") + + // check the value for the current block + assert.Equal(t, origGasPrice, GetGasPrice(), "result of gas price voting") + // check the value for the next block + assert.Equal(t, balance0_5, GetNextBlockParam("GASPRICE"), "result of gas price voting") + // commit the new value + CommitParams(true) + // check the value for the current block + assert.Equal(t, balance0_5, GetGasPrice(), "result of gas price voting") blockInfo.No += StakingDelay unstakingTx := &types.Tx{ @@ -815,6 +830,8 @@ func TestProposalExecute2(t *testing.T) { _, err = ExecuteSystemTx(scs, unstakingTx.GetBody(), sender, receiver, blockInfo) assert.NoError(t, err, "could not execute system tx") + oldNamePrice := GetNamePrice() + votingTx.Body.Account = sender2.ID() votingTx.Body.Payload = []byte(`{"Name":"v1voteDAO", "Args":["NAMEPRICE", "1004"]}`) _, err = ExecuteSystemTx(scs, votingTx.GetBody(), sender2, receiver, blockInfo) @@ -830,8 +847,15 @@ func TestProposalExecute2(t *testing.T) { internalVoteResult, err = loadVoteResult(scs, GenProposalKey(namePrice.ID())) assert.Equal(t, new(big.Int).Mul(balance2, big.NewInt(2)), internalVoteResult.GetTotal(), "check result total") assert.Equal(t, "1004", string(voteResult.Votes[0].Candidate), "1st place") - currentNamePrice := GetNamePrice() - assert.Equal(t, "1004", currentNamePrice.String(), "current name price") + + // check the value for the current block + assert.Equal(t, oldNamePrice, GetNamePrice(), "check name price") + // check the value for the next block + assert.Equal(t, big.NewInt(1004), GetNextBlockParam("NAMEPRICE"), "check name price") + // commit the new value + CommitParams(true) + // check the value for the current block + assert.Equal(t, big.NewInt(1004), GetNamePrice(), "check name price") /* blockInfo += StakingDelay diff --git a/contract/system/param.go b/contract/system/param.go index a4fe2ba1a..b9375640b 100644 --- a/contract/system/param.go +++ b/contract/system/param.go @@ -3,12 +3,56 @@ package system import ( "math/big" "strings" + "sync" "github.com/aergoio/aergo/v2/state" "github.com/aergoio/aergo/v2/types" ) -type parameters map[string]*big.Int +type parameters struct { + mutex sync.RWMutex + params map[string]*big.Int +} + +func (p *parameters) setParam(proposalID string, value *big.Int) { + p.mutex.Lock() + defer p.mutex.Unlock() + + p.params[proposalID] = value +} + +// save the new value for the param, to be active on the next block +func (p *parameters) setNextBlockParam(proposalID string, value *big.Int) { + p.mutex.Lock() + defer p.mutex.Unlock() + + p.params[nextBlockParamKey(proposalID)] = value +} + +func (p *parameters) delNextBlockParam(proposalID string) { + p.mutex.Lock() + defer p.mutex.Unlock() + + delete(p.params, nextBlockParamKey(proposalID)) +} + +func (p *parameters) getNextBlockParam(proposalID string) *big.Int { + p.mutex.Lock() + defer p.mutex.Unlock() + + return p.params[nextBlockParamKey(proposalID)] +} + +func (p *parameters) getParam(proposalID string) *big.Int { + p.mutex.Lock() + defer p.mutex.Unlock() + + return p.params[proposalID] +} + +func nextBlockParamKey(id string) string { + return id + "next" +} const ( RESET = -1 @@ -26,7 +70,10 @@ const ( ) var ( - systemParams parameters + systemParams *parameters = ¶meters{ + mutex: sync.RWMutex{}, + params: map[string]*big.Int{}, + } //DefaultParams is for aergo v1 compatibility DefaultParams = map[string]*big.Int{ @@ -36,16 +83,30 @@ var ( } ) +func genParamKey(id string) []byte { + return []byte("param\\" + strings.ToUpper(id)) +} + +// This is also called on chain reorganization func InitSystemParams(g dataGetter, bpCount int) { + // discard any new params computed for the next block + CommitParams(false) + // (re)load param values from database initDefaultBpCount(bpCount) - systemParams = loadParam(g) + systemParams = loadParams(g) } -func genParamKey(id string) []byte { - return []byte("param\\" + strings.ToUpper(id)) +// This function must be called before all the aergosvr +// services start. +func initDefaultBpCount(count int) { + // Ensure that it is not modified after it is initialized. + if DefaultParams[bpCount.ID()] == nil { + DefaultParams[bpCount.ID()] = big.NewInt(int64(count)) + } } -func loadParam(g dataGetter) parameters { +// load the params from the database or use the default values +func loadParams(g dataGetter) *parameters { ret := map[string]*big.Int{} for i := sysParamIndex(0); i < sysParamMax; i++ { id := i.ID() @@ -53,35 +114,68 @@ func loadParam(g dataGetter) parameters { if err != nil { panic("could not load blockchain parameter") } - if data == nil { + if data != nil { + ret[id] = new(big.Int).SetBytes(data) + } else { ret[id] = DefaultParams[id] - continue } - ret[id] = new(big.Int).SetBytes(data) } - return ret + return ¶meters{ + mutex: sync.RWMutex{}, + params: ret, + } } -func (p parameters) getLastParam(proposalID string) *big.Int { - if val, ok := p[proposalID]; ok { - return val +func updateParam(s dataSetter, id string, value *big.Int) error { + // save the param to the database (in a db txn, commit when the block is connected) + if err := s.SetData(genParamKey(id), value.Bytes()); err != nil { + return err } - return DefaultParams[proposalID] + // save the new value for the param, only active on the next block + systemParams.setNextBlockParam(id, value) + return nil } -func (p parameters) setLastParam(proposalID string, value *big.Int) *big.Int { - p[proposalID] = value - return value +// if a system param was changed, apply or discard its new value +func CommitParams(apply bool) { + for i := sysParamIndex(0); i < sysParamMax; i++ { + id := i.ID() + // check if the param has a new value + if param := systemParams.getNextBlockParam(id); param != nil { + if apply { + // set the new value for the current block + systemParams.setParam(id, param) + } + // delete the new value + systemParams.delNextBlockParam(id) + } + } } -func updateParam(s dataSetter, id string, value *big.Int) (*big.Int, error) { - if err := s.SetData(genParamKey(id), value.Bytes()); err != nil { - return nil, err +// get the param value for the next block +func GetNextBlockParam(proposalID string) *big.Int { + // check the value for the next block + if val := systemParams.getNextBlockParam(proposalID); val != nil { + return val } - ret := systemParams.setLastParam(id, value) - return ret, nil + // check the value for the current block + if val := systemParams.getParam(proposalID); val != nil { + return val + } + // default value + return DefaultParams[proposalID] +} + +// get the param value for the current block +func GetParam(proposalID string) *big.Int { + if val := systemParams.getParam(proposalID); val != nil { + return val + } + return DefaultParams[proposalID] } +// these 4 functions are reading the param value for the current block + func GetStakingMinimum() *big.Int { return GetParam(stakingMin.ID()) } @@ -94,6 +188,12 @@ func GetNamePrice() *big.Int { return GetParam(namePrice.ID()) } +func GetBpCount() int { + return int(GetParam(bpCount.ID()).Uint64()) +} + +// these functions are reading the param value directly from the state + func GetNamePriceFromState(scs *state.ContractState) *big.Int { return getParamFromState(scs, namePrice) } diff --git a/contract/system/param_test.go b/contract/system/param_test.go index e9812c92e..f23c601ab 100644 --- a/contract/system/param_test.go +++ b/contract/system/param_test.go @@ -8,17 +8,17 @@ import ( func TestValidateDefaultParams(t *testing.T) { // Staking minimum amount ( 10,000 aergo ) - stakingMin, ok := DefaultParams[stakingMin.ID()] - assert.Truef(t, ok, "stakingMin is not valid. check contract/system/param.go") + stakingMin := DefaultParams[stakingMin.ID()] + assert.NotNilf(t, stakingMin, "stakingMin is not valid. check contract/system/param.go") assert.Equalf(t, "10000000000000000000000", stakingMin.String(), "StakingMinimum is not valid. check contract/system/param.go") // gas price ( 50 gaer ) - gasPrice, ok := DefaultParams[gasPrice.ID()] - assert.Truef(t, ok, "gasPrice is not valid. check contract/system/param.go") + gasPrice := DefaultParams[gasPrice.ID()] + assert.NotNilf(t, gasPrice, "gasPrice is not valid. check contract/system/param.go") assert.Equalf(t, "50000000000", gasPrice.String(), "GasPrice is not valid. check contract/system/param.go") // Proposal price ( 1 aergo ) namePrice := DefaultParams[namePrice.ID()] - assert.Truef(t, ok, "namePrice is not valid. check contract/system/param.go") + assert.NotNilf(t, namePrice, "namePrice is not valid. check contract/system/param.go") assert.Equalf(t, "1000000000000000000", namePrice.String(), "ProposalPrice is not valid. check contract/system/param.go") } diff --git a/contract/system/proposal_test.go b/contract/system/proposal_test.go index e462508d9..77365d114 100644 --- a/contract/system/proposal_test.go +++ b/contract/system/proposal_test.go @@ -123,6 +123,14 @@ func TestProposalBPCount(t *testing.T) { _, err = ExecuteSystemTx(scs, validCandiTx.GetBody(), sender2, receiver, blockInfo) assert.NoError(t, err, "valid") + + // check the value for the current block + assert.Equal(t, 3, GetBpCount(), "check bp") + // check the value for the next block + assert.Equal(t, big.NewInt(13), GetNextBlockParam("BPCOUNT"), "check bp") + // commit the new value + CommitParams(true) + // check the value for the current block assert.Equal(t, 13, GetBpCount(), "check bp") } @@ -203,8 +211,20 @@ func TestFailProposals(t *testing.T) { _, err = ExecuteSystemTx(scs, validCandiTx.GetBody(), sender2, receiver, blockInfo) assert.NoError(t, err, "valid") + + // check the value for the current block + assert.Equal(t, 3, GetBpCount(), "check bp") + // check the value for the next block + assert.Equal(t, big.NewInt(13), GetNextBlockParam("BPCOUNT"), "check bp") + // commit the new value + CommitParams(true) + // check the value for the current block assert.Equal(t, 13, GetBpCount(), "check bp") + // gas price + + oldGasPrice := GetGasPrice() + invalidCandiTx.Body.Payload = []byte(`{"Name":"v1voteDAO", "Args":["gasprice", "500000000000000000000000001"]}`) _, err = ExecuteSystemTx(scs, invalidCandiTx.GetBody(), sender, receiver, blockInfo) assert.Error(t, err, "invalid range") @@ -221,5 +241,13 @@ func TestFailProposals(t *testing.T) { validCandiTx.Body.Payload = []byte(`{"Name":"v1voteDAO", "Args":["gasprice", "101"]}`) _, err = ExecuteSystemTx(scs, validCandiTx.GetBody(), sender2, receiver, blockInfo) assert.NoError(t, err, "valid") + + // check the value for the current block + assert.Equal(t, oldGasPrice, GetGasPrice(), "check gas price") + // check the value for the next block + assert.Equal(t, big.NewInt(101), GetNextBlockParam("GASPRICE"), "check gas price") + // commit the new value + CommitParams(true) + // check the value for the current block assert.Equal(t, big.NewInt(101), GetGasPrice(), "check gas price") } diff --git a/contract/system/staking.go b/contract/system/staking.go index fec058c84..7b3956db7 100644 --- a/contract/system/staking.go +++ b/contract/system/staking.go @@ -13,8 +13,6 @@ import ( "github.com/aergoio/aergo/v2/types" ) -var consensusType string - var ( stakingKey = []byte("staking") stakingTotalKey = []byte("stakingtotal") @@ -25,10 +23,6 @@ var ( const StakingDelay = 60 * 60 * 24 //block interval //const StakingDelay = 5 -func InitGovernance(consensus string) { - consensusType = consensus -} - type stakeCmd struct { *SystemContext amount *big.Int @@ -61,23 +55,18 @@ func (c *stakeCmd) run() (*types.Event, error) { } sender.SubBalance(amount) receiver.AddBalance(amount) + + jsonArgs := "" if c.SystemContext.BlockInfo.ForkVersion < 2 { - return &types.Event{ - ContractAddress: receiver.ID(), - EventIdx: 0, - EventName: "stake", - JsonArgs: `{"who":"` + - types.EncodeAddress(sender.ID()) + - `", "amount":"` + amount.String() + `"}`, - }, nil + jsonArgs = `{"who":"` + types.EncodeAddress(sender.ID()) + `", "amount":"` + amount.String() + `"}` + } else { + jsonArgs = `["` + types.EncodeAddress(sender.ID()) + `", {"_bignum":"` + amount.String() + `"}]` } return &types.Event{ ContractAddress: receiver.ID(), EventIdx: 0, EventName: "stake", - JsonArgs: `["` + - types.EncodeAddress(sender.ID()) + - `", {"_bignum":"` + amount.String() + `"}]`, + JsonArgs: jsonArgs, }, nil } @@ -114,23 +103,18 @@ func (c *unstakeCmd) run() (*types.Event, error) { } sender.AddBalance(balanceAdjustment) receiver.SubBalance(balanceAdjustment) + + jsonArgs := "" if c.SystemContext.BlockInfo.ForkVersion < 2 { - return &types.Event{ - ContractAddress: receiver.ID(), - EventIdx: 0, - EventName: "unstake", - JsonArgs: `{"who":"` + - types.EncodeAddress(sender.ID()) + - `", "amount":"` + balanceAdjustment.String() + `"}`, - }, nil + jsonArgs = `{"who":"` + types.EncodeAddress(sender.ID()) + `", "amount":"` + balanceAdjustment.String() + `"}` + } else { + jsonArgs = `["` + types.EncodeAddress(sender.ID()) + `", {"_bignum":"` + balanceAdjustment.String() + `"}]` } return &types.Event{ ContractAddress: receiver.ID(), EventIdx: 0, EventName: "unstake", - JsonArgs: `["` + - types.EncodeAddress(sender.ID()) + - `", {"_bignum":"` + balanceAdjustment.String() + `"}]`, + JsonArgs: jsonArgs, }, nil } diff --git a/contract/system/validation.go b/contract/system/validation.go index cf3fcd37c..33573835c 100644 --- a/contract/system/validation.go +++ b/contract/system/validation.go @@ -130,7 +130,7 @@ func validateForStaking(account []byte, txBody *types.TxBody, scs *state.Contrac return nil, types.ErrLessTimeHasPassed } toBe := new(big.Int).Add(staked.GetAmountBigInt(), txBody.GetAmountBigInt()) - stakingMin := GetStakingMinimumFromState(scs) + stakingMin := GetStakingMinimum() if stakingMin.Cmp(toBe) > 0 { return nil, types.ErrTooSmallAmount } @@ -164,7 +164,7 @@ func validateForUnstaking(account []byte, txBody *types.TxBody, scs *state.Contr return nil, types.ErrLessTimeHasPassed } toBe := new(big.Int).Sub(staked.GetAmountBigInt(), txBody.GetAmountBigInt()) - stakingMin := GetStakingMinimumFromState(scs) + stakingMin := GetStakingMinimum() if toBe.Cmp(big.NewInt(0)) != 0 && stakingMin.Cmp(toBe) > 0 { return nil, types.ErrTooSmallAmount } diff --git a/contract/system/vote.go b/contract/system/vote.go index 5d2ee9187..d859a982e 100644 --- a/contract/system/vote.go +++ b/contract/system/vote.go @@ -27,8 +27,6 @@ const ( var ( votingCatalog []types.VotingIssue - lastBpCount int - voteKey = []byte("vote") totalKey = []byte("total") sortKey = []byte("sort") @@ -94,7 +92,6 @@ func (c *vprCmd) subVote(v *types.Vote) error { votingPowerRank.sub(c.Sender.AccountID(), c.Sender.ID(), v.GetAmountBigInt()) // Hotfix - reproduce vpr calculation for block 138015125 // When block is reverted, votingPowerRank is not reverted and calculated three times. - // TODO : implement commit, revert, reorg for governance variables. if c.BlockInfo.No == 138015125 && c.Sender.AccountID().String() == "36t2u7Q31HmEbkkYZng7DHNm3xepxHKUfgGrAXNA8pMW" { for i := 0; i < 2; i++ { votingPowerRank.sub(c.Sender.AccountID(), c.Sender.ID(), v.GetAmountBigInt()) @@ -107,7 +104,6 @@ func (c *vprCmd) addVote(v *types.Vote) error { votingPowerRank.add(c.Sender.AccountID(), c.Sender.ID(), v.GetAmountBigInt()) // Hotfix - reproduce vpr calculation for block 138015125 // When block is reverted, votingPowerRank is not reverted and calculated three times. - // TODO : implement commit, revert, reorg for governance variables. if c.BlockInfo.No == 138015125 && c.Sender.AccountID().String() == "36t2u7Q31HmEbkkYZng7DHNm3xepxHKUfgGrAXNA8pMW" { for i := 0; i < 2; i++ { votingPowerRank.add(c.Sender.AccountID(), c.Sender.ID(), v.GetAmountBigInt()) @@ -198,23 +194,18 @@ func (c *voteCmd) run() (*types.Event, error) { if err := c.updateVoteResult(); err != nil { return nil, err } + + jsonArgs := "" if c.SystemContext.BlockInfo.ForkVersion < 2 { - return &types.Event{ - ContractAddress: c.Receiver.ID(), - EventIdx: 0, - EventName: c.op.ID(), - JsonArgs: `{"who":"` + - types.EncodeAddress(c.txBody.Account) + - `", "vote":` + string(c.args) + `}`, - }, nil + jsonArgs = `{"who":"` + types.EncodeAddress(c.txBody.Account) + `", "vote":` + string(c.args) + `}` + } else { + jsonArgs = `["` + types.EncodeAddress(c.txBody.Account) + `", ` + string(c.args) + `]` } return &types.Event{ ContractAddress: c.Receiver.ID(), EventIdx: 0, EventName: c.op.ID(), - JsonArgs: `["` + - types.EncodeAddress(c.txBody.Account) + - `", ` + string(c.args) + `]`, + JsonArgs: jsonArgs, }, nil } @@ -359,21 +350,6 @@ func GetVoteResult(ar AccountStateReader, id []byte, n int) (*types.VoteList, er return getVoteResult(scs, id, n) } -// initDefaultBpCount sets lastBpCount to bpCount. -// -// Caution: This function must be called only once before all the aergosvr -// services start. -func initDefaultBpCount(count int) { - // Ensure that it is not modified after it is initialized. - if DefaultParams[bpCount.ID()] == nil { - DefaultParams[bpCount.ID()] = big.NewInt(int64(count)) - } -} - -func GetBpCount() int { - return int(GetParam(bpCount.ID()).Uint64()) -} - // GetRankers returns the IDs of the top n rankers. func GetRankers(ar AccountStateReader) ([]string, error) { n := GetBpCount() @@ -390,10 +366,6 @@ func GetRankers(ar AccountStateReader) ([]string, error) { return bps, nil } -func GetParam(proposalID string) *big.Int { - return systemParams.getLastParam(proposalID) -} - func serializeVoteList(vl *types.VoteList, ex bool) []byte { var data []byte for _, v := range vl.GetVotes() { diff --git a/contract/system/vote_test.go b/contract/system/vote_test.go index 57b0562f4..8eff82f3b 100644 --- a/contract/system/vote_test.go +++ b/contract/system/vote_test.go @@ -35,7 +35,6 @@ func initTest(t *testing.T) (*state.ContractState, *state.V, *state.V) { t.Fatalf("failed init : %s", err.Error()) } // Need to pass the - InitGovernance("dpos") const testSender = "AmPNYHyzyh9zweLwDyuoiUuTVCdrdksxkRWDjVJS76WQLExa2Jr4" scs, err := bs.GetSystemAccountState() diff --git a/contract/system/voteresult.go b/contract/system/voteresult.go index 33d9aded0..53656739d 100644 --- a/contract/system/voteresult.go +++ b/contract/system/voteresult.go @@ -117,7 +117,7 @@ func (vr *VoteResult) Sync() error { if !ok { return fmt.Errorf("abnormal winner is in vote %s", string(vr.key)) } - if _, err := updateParam(vr.scs, string(vr.key), value); err != nil { + if err := updateParam(vr.scs, string(vr.key), value); err != nil { return err } } diff --git a/contract/vm_dummy/test_files/gas_per_function.lua b/contract/vm_dummy/test_files/gas_per_function.lua index 3b27a8192..bd1bf0be4 100644 --- a/contract/vm_dummy/test_files/gas_per_function.lua +++ b/contract/vm_dummy/test_files/gas_per_function.lua @@ -1286,9 +1286,9 @@ function run_test(function_name, ...) end -function deposit() +function default() -- do nothing, only receive native aergo tokens end abi.register(run_test) -abi.payable(deposit) +abi.payable(default) diff --git a/contract/vm_dummy/test_files/type_random.lua b/contract/vm_dummy/test_files/type_random.lua index e7fe68929..47f63d23c 100644 --- a/contract/vm_dummy/test_files/type_random.lua +++ b/contract/vm_dummy/test_files/type_random.lua @@ -1,5 +1,16 @@ function random(...) - return system.random(...) + return system.random(...) end -abi.register(random) +function get_numbers(count) + local list = {} + + for i = 1, count do + local num = system.random(1, 100) + table.insert(list, num) + end + + return list +end + +abi.register(random, get_numbers) diff --git a/contract/vm_dummy/test_files/type_random_caller.lua b/contract/vm_dummy/test_files/type_random_caller.lua new file mode 100644 index 000000000..9e87c9c6d --- /dev/null +++ b/contract/vm_dummy/test_files/type_random_caller.lua @@ -0,0 +1,35 @@ +-- check if numbers generated by a called contract are +-- the same if called on the same transaction +function check_if_equal(address) + + local list1 = contract.call(address, 'get_numbers', 10) + local list2 = contract.call(address, 'get_numbers', 10) + local list3 = contract.call(address, 'get_numbers', 10) + + if lists_are_equal(list1, list2) then + return true + end + if lists_are_equal(list2, list3) then + return true + end + + return false +end + +function lists_are_equal(list1, list2) + -- check if lengths are different + if #list1 ~= #list2 then + return false + end + + -- compare each element + for i = 1, #list1 do + if list1[i] ~= list2[i] then + return false + end + end + + return true +end + +abi.register(check_if_equal) diff --git a/contract/vm_dummy/vm_dummy.go b/contract/vm_dummy/vm_dummy.go index 3ded2810c..c1fbce3c6 100644 --- a/contract/vm_dummy/vm_dummy.go +++ b/contract/vm_dummy/vm_dummy.go @@ -134,7 +134,6 @@ func LoadDummyChain(opts ...DummyChainOptions) (*DummyChain, error) { // To pass the governance tests. types.InitGovernance("dpos", true) - system.InitGovernance("dpos") // To pass dao parameters test scs, err := bc.sdb.GetStateDB().GetSystemAccountState() diff --git a/contract/vm_dummy/vm_dummy_pub_test.go b/contract/vm_dummy/vm_dummy_pub_test.go index 988f6d8a4..2ca84e678 100644 --- a/contract/vm_dummy/vm_dummy_pub_test.go +++ b/contract/vm_dummy/vm_dummy_pub_test.go @@ -81,8 +81,8 @@ func TestGasPerFunction(t *testing.T) { // transfer funds to the contracts err = bc.ConnectBlock( - NewLuaTxCall("user", "contract_v2", uint64(10e18), `{"Name":"deposit"}`), - NewLuaTxCall("user", "contract_v3", uint64(10e18), `{"Name":"deposit"}`), + NewLuaTxCall("user", "contract_v2", uint64(10e18), `{"Name":"default"}`), + NewLuaTxCall("user", "contract_v3", uint64(10e18), `{"Name":"default"}`), ) assert.NoError(t, err, "sending funds to contracts") diff --git a/contract/vm_dummy/vm_dummy_test.go b/contract/vm_dummy/vm_dummy_test.go index a8fcd305b..88da6c7c4 100644 --- a/contract/vm_dummy/vm_dummy_test.go +++ b/contract/vm_dummy/vm_dummy_test.go @@ -2171,14 +2171,19 @@ func checkRandomIntValue(v string, min, max int) error { } func TestTypeRandom(t *testing.T) { - code := readLuaCode(t, "type_random.lua") + code1 := readLuaCode(t, "type_random.lua") + code2 := readLuaCode(t, "type_random_caller.lua") for version := min_version; version <= max_version; version++ { bc, err := LoadDummyChain(SetHardForkVersion(version)) require.NoErrorf(t, err, "failed to create dummy chain") defer bc.Release() - err = bc.ConnectBlock(NewLuaTxAccount("user1", 1, types.Aergo), NewLuaTxDeploy("user1", "random", 0, code)) + err = bc.ConnectBlock( + NewLuaTxAccount("user1", 1, types.Aergo), + NewLuaTxDeploy("user1", "random", 0, code1), + NewLuaTxDeploy("user1", "caller", 0, code2), + ) require.NoErrorf(t, err, "failed to deploy") err = bc.ConnectBlock(NewLuaTxCall("user1", "random", 0, `{"Name": "random", "Args":[]}`).Fail("1 or 2 arguments required")) @@ -2215,6 +2220,12 @@ func TestTypeRandom(t *testing.T) { err = bc.Query("random", `{"Name": "random", "Args":[3,1]}`, "system.random: the maximum value must be greater than the minimum value", "") require.NoErrorf(t, err, "failed to query") + tx = NewLuaTxCall("user1", "caller", 0, `{"Name": "check_if_equal", "Args":["`+nameToAddress("random")+`"]}`) + err = bc.ConnectBlock(tx) + require.NoErrorf(t, err, "failed to call tx") + receipt = bc.GetReceipt(tx.Hash()) + assert.Equalf(t, `false`, receipt.GetRet(), "random numbers are the same on the same transaction") + } } diff --git a/mempool/mempool.go b/mempool/mempool.go index 64bc9219f..9a4577301 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -676,15 +676,11 @@ func (mp *MemPool) validateTx(tx types.Transaction, account types.Address) error return err } case types.AergoName: - systemcs, err := mp.stateDB.GetSystemAccountState() - if err != nil { - return err - } sender, err := mp.stateDB.GetAccountStateV(account) if err != nil { return err } - if _, err := name.ValidateNameTx(tx.GetBody(), sender, scs, systemcs); err != nil { + if _, err := name.ValidateNameTx(tx.GetBody(), sender, scs); err != nil { return err } case types.AergoEnterprise: diff --git a/tests/bp01.id b/tests/bp01.id new file mode 100644 index 000000000..e6b88a555 --- /dev/null +++ b/tests/bp01.id @@ -0,0 +1 @@ +16Uiu2HAmG4PSXYUxkPbNb7qTcEExFpgAwBrm3hB32aJXuvX2f1sd \ No newline at end of file diff --git a/tests/bp01.key b/tests/bp01.key new file mode 100644 index 000000000..8ab66a8aa --- /dev/null +++ b/tests/bp01.key @@ -0,0 +1 @@ + A<��iT�B-:�1J �\�G��1�� T'�� \ No newline at end of file diff --git a/tests/bp01.pub b/tests/bp01.pub new file mode 100644 index 000000000..d42833955 Binary files /dev/null and b/tests/bp01.pub differ diff --git a/tests/bp02.id b/tests/bp02.id new file mode 100644 index 000000000..102b8a198 --- /dev/null +++ b/tests/bp02.id @@ -0,0 +1 @@ +16Uiu2HAmMzncFmnpjigZJRoraToKkABvZimMUAyXf6bdrZeN7mbJ \ No newline at end of file diff --git a/tests/bp02.key b/tests/bp02.key new file mode 100644 index 000000000..9c9f8c626 --- /dev/null +++ b/tests/bp02.key @@ -0,0 +1,2 @@ + �5 +&���d�f�#[k��1~� �Ľ�=�� \ No newline at end of file diff --git a/tests/bp02.pub b/tests/bp02.pub new file mode 100644 index 000000000..f9627f3fc --- /dev/null +++ b/tests/bp02.pub @@ -0,0 +1 @@ +!�˅����:^�p�B�X̾����2/���~� \ No newline at end of file diff --git a/tests/bp03.id b/tests/bp03.id new file mode 100644 index 000000000..ce5e264a5 --- /dev/null +++ b/tests/bp03.id @@ -0,0 +1 @@ +16Uiu2HAmKB7RYXe1uHNYMtkuuM2fEHxsv6P9PZ45ogJw6aZD3y7x \ No newline at end of file diff --git a/tests/bp03.key b/tests/bp03.key new file mode 100644 index 000000000..769f934f5 --- /dev/null +++ b/tests/bp03.key @@ -0,0 +1 @@ + ⧾o�{V�IԖu�Q���7��6$M���p�G� \ No newline at end of file diff --git a/tests/bp03.pub b/tests/bp03.pub new file mode 100644 index 000000000..8704fcc3d --- /dev/null +++ b/tests/bp03.pub @@ -0,0 +1 @@ +!`݋/�|t�i��+�յ͚��B�5mHK4[EC \ No newline at end of file diff --git a/tests/common.sh b/tests/common.sh index bd5abe899..6cd82200c 100644 --- a/tests/common.sh +++ b/tests/common.sh @@ -1,4 +1,41 @@ +start_nodes() { + + if [ "$consensus" == "sbp" ]; then + # open the aergo node in testmode + ../bin/aergosvr --testmode --home ./aergo-files > logs 2> logs & + pid=$! + else + # open the 3 nodes + ../bin/aergosvr --home ./node1 >> logs1 2>> logs1 & + pid1=$! + ../bin/aergosvr --home ./node2 >> logs2 2>> logs2 & + pid2=$! + ../bin/aergosvr --home ./node3 >> logs3 2>> logs3 & + pid3=$! + fi + + # wait the node(s) to be ready + if [ "$consensus" == "sbp" ]; then + sleep 3 + elif [ "$consensus" == "dpos" ]; then + sleep 5 + elif [ "$consensus" == "raft" ]; then + sleep 2 + fi + +} + +stop_nodes() { + + if [ "$consensus" == "sbp" ]; then + kill $pid + else + kill $pid1 $pid2 $pid3 + fi + +} + get_deploy_args() { contract_file=$1 @@ -27,7 +64,7 @@ get_receipt() { set +e while true; do - output=$(../bin/aergocli receipt get $txhash 2>&1 > receipt.json) + output=$(../bin/aergocli receipt get --port $query_port $txhash 2>&1 > receipt.json) #echo "output: $output" diff --git a/tests/config-node1.toml b/tests/config-node1.toml new file mode 100644 index 000000000..8ffb68f7e --- /dev/null +++ b/tests/config-node1.toml @@ -0,0 +1,48 @@ +# aergo TOML Configuration File (https://github.com/toml-lang/toml) +# base configurations +enableprofile = false + +[rpc] +netserviceaddr = "0.0.0.0" +netserviceport = 7845 +netservicetrace = false +nstls = false +nscert = "" +nskey = "" +nsallowcors = false + +[p2p] +netprotocoladdr = "127.0.0.1" +netprotocolport = 2001 +npbindaddr = "0.0.0.0" +npbindport = 2001 +nptls = false +npcert = "" +npkey = "bp01.key" +npaddpeers = [ +#"/ip4/127.0.0.1/tcp/2001/p2p/16Uiu2HAmG4PSXYUxkPbNb7qTcEExFpgAwBrm3hB32aJXuvX2f1sd", +"/ip4/127.0.0.1/tcp/2002/p2p/16Uiu2HAmMzncFmnpjigZJRoraToKkABvZimMUAyXf6bdrZeN7mbJ", +"/ip4/127.0.0.1/tcp/2003/p2p/16Uiu2HAmKB7RYXe1uHNYMtkuuM2fEHxsv6P9PZ45ogJw6aZD3y7x" +] +npexposeself = false +npdiscoverpeers = false +npusepolaris = false +peerrole = "producer" + +[blockchain] +maxblocksize = 1000000 + +[mempool] +showmetrics = false + +[consensus] +enablebp = true + +[consensus.raft] +newcluster=true +name="bp01" + +[hardfork] +v2 = "0" +v3 = "10000" +v4 = "10000" diff --git a/tests/config-node2.toml b/tests/config-node2.toml new file mode 100644 index 000000000..f68988e37 --- /dev/null +++ b/tests/config-node2.toml @@ -0,0 +1,48 @@ +# aergo TOML Configuration File (https://github.com/toml-lang/toml) +# base configurations +enableprofile = false + +[rpc] +netserviceaddr = "0.0.0.0" +netserviceport = 8845 +netservicetrace = false +nstls = false +nscert = "" +nskey = "" +nsallowcors = false + +[p2p] +netprotocoladdr = "127.0.0.1" +netprotocolport = 2002 +npbindaddr = "0.0.0.0" +npbindport = 2002 +nptls = false +npcert = "" +npkey = "bp02.key" +npaddpeers = [ +"/ip4/127.0.0.1/tcp/2001/p2p/16Uiu2HAmG4PSXYUxkPbNb7qTcEExFpgAwBrm3hB32aJXuvX2f1sd", +#"/ip4/127.0.0.1/tcp/2002/p2p/16Uiu2HAmMzncFmnpjigZJRoraToKkABvZimMUAyXf6bdrZeN7mbJ", +"/ip4/127.0.0.1/tcp/2003/p2p/16Uiu2HAmKB7RYXe1uHNYMtkuuM2fEHxsv6P9PZ45ogJw6aZD3y7x" +] +npexposeself = false +npdiscoverpeers = false +npusepolaris = false +peerrole = "producer" + +[blockchain] +maxblocksize = 1000000 + +[mempool] +showmetrics = false + +[consensus] +enablebp = true + +[consensus.raft] +newcluster=true +name="bp02" + +[hardfork] +v2 = "0" +v3 = "10000" +v4 = "10000" diff --git a/tests/config-node3.toml b/tests/config-node3.toml new file mode 100644 index 000000000..888aca265 --- /dev/null +++ b/tests/config-node3.toml @@ -0,0 +1,48 @@ +# aergo TOML Configuration File (https://github.com/toml-lang/toml) +# base configurations +enableprofile = false + +[rpc] +netserviceaddr = "0.0.0.0" +netserviceport = 9845 +netservicetrace = false +nstls = false +nscert = "" +nskey = "" +nsallowcors = false + +[p2p] +netprotocoladdr = "127.0.0.1" +netprotocolport = 2003 +npbindaddr = "0.0.0.0" +npbindport = 2003 +nptls = false +npcert = "" +npkey = "bp03.key" +npaddpeers = [ +"/ip4/127.0.0.1/tcp/2001/p2p/16Uiu2HAmG4PSXYUxkPbNb7qTcEExFpgAwBrm3hB32aJXuvX2f1sd", +"/ip4/127.0.0.1/tcp/2002/p2p/16Uiu2HAmMzncFmnpjigZJRoraToKkABvZimMUAyXf6bdrZeN7mbJ" +#"/ip4/127.0.0.1/tcp/2003/p2p/16Uiu2HAmKB7RYXe1uHNYMtkuuM2fEHxsv6P9PZ45ogJw6aZD3y7x" +] +npexposeself = false +npdiscoverpeers = false +npusepolaris = false +peerrole = "producer" + +[blockchain] +maxblocksize = 1000000 + +[mempool] +showmetrics = false + +[consensus] +enablebp = true + +[consensus.raft] +newcluster=true +name="bp03" + +[hardfork] +v2 = "0" +v3 = "10000" +v4 = "10000" diff --git a/tests/config.toml b/tests/config-sbp.toml similarity index 100% rename from tests/config.toml rename to tests/config-sbp.toml diff --git a/tests/genesis-dpos.json b/tests/genesis-dpos.json new file mode 100644 index 000000000..da860252f --- /dev/null +++ b/tests/genesis-dpos.json @@ -0,0 +1,17 @@ +{ + "chain_id":{ + "magic":"test.chain", + "public":true, + "mainnet":false, + "consensus":"dpos" + }, + "timestamp": 1559883600000000000, + "balance": { + "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R": "1000000000000000000000" + }, + "bps": [ + "16Uiu2HAmG4PSXYUxkPbNb7qTcEExFpgAwBrm3hB32aJXuvX2f1sd", + "16Uiu2HAmMzncFmnpjigZJRoraToKkABvZimMUAyXf6bdrZeN7mbJ", + "16Uiu2HAmKB7RYXe1uHNYMtkuuM2fEHxsv6P9PZ45ogJw6aZD3y7x" + ] +} diff --git a/tests/genesis-raft.json b/tests/genesis-raft.json new file mode 100644 index 000000000..c996b3590 --- /dev/null +++ b/tests/genesis-raft.json @@ -0,0 +1,31 @@ +{ + "chain_id":{ + "magic":"test.chain", + "public":true, + "mainnet":false, + "consensus":"raft" + }, + "timestamp": 1559883600000000000, + "balance": { + "AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R": "1000000000000000000000" + }, + "bps": [ + ], + "enterprise_bps": [ + { + "name": "bp01", + "address": "/ip4/127.0.0.1/tcp/2001", + "peerid": "16Uiu2HAmG4PSXYUxkPbNb7qTcEExFpgAwBrm3hB32aJXuvX2f1sd" + }, + { + "name": "bp02", + "address": "/ip4/127.0.0.1/tcp/2002", + "peerid": "16Uiu2HAmMzncFmnpjigZJRoraToKkABvZimMUAyXf6bdrZeN7mbJ" + }, + { + "name": "bp03", + "address": "/ip4/127.0.0.1/tcp/2003", + "peerid": "16Uiu2HAmKB7RYXe1uHNYMtkuuM2fEHxsv6P9PZ45ogJw6aZD3y7x" + } + ] +} diff --git a/tests/run_tests.sh b/tests/run_tests.sh index 0089ec715..83413a346 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -1,23 +1,72 @@ # stop on errors set -e +source common.sh -# run the brick test -./test-brick.sh +arg=$1 +if [ "$arg" != "sbp" ] && [ "$arg" != "dpos" ] && [ "$arg" != "raft" ] && [ "$arg" != "brick" ]; then + echo "Usage: $0 [brick|sbp|dpos|raft]" + exit 1 +fi +echo "Running integration tests for $arg" + +if [ "$arg" == "brick" ]; then + # run the brick test + ../bin/brick -V test.brick + exit 0 +fi + +consensus=$arg + +if [ "$consensus" == "sbp" ]; then + # delete and recreate the aergo folder + rm -rf ./aergo-files + mkdir aergo-files + # copy the config file + cp config-sbp.toml ./aergo-files/config.toml + # delete the old logs + rm -f logs +else + # delete and recreate the aergo folder + rm -rf node1 + rm -rf node2 + rm -rf node3 + mkdir node1 + mkdir node2 + mkdir node3 + # copy the config files + cp config-node1.toml node1/config.toml + cp config-node2.toml node2/config.toml + cp config-node3.toml node3/config.toml + # delete the old logs + rm -f logs1 logs2 logs3 + # create the genesis block + echo "creating genesis block..." + ../bin/aergosvr init --genesis ./genesis-$consensus.json --home ./node1 + ../bin/aergosvr init --genesis ./genesis-$consensus.json --home ./node2 + ../bin/aergosvr init --genesis ./genesis-$consensus.json --home ./node3 +fi -# delete and recreate the aergo folder -rm -rf ./aergo-files -mkdir aergo-files -# copy the config file -cp config.toml ./aergo-files/ +# define the config files according to the consensus +if [ "$consensus" == "sbp" ]; then + config_files=("./aergo-files/config.toml") +elif [ "$consensus" == "dpos" ]; then + config_files=("./node1/config.toml" "./node2/config.toml" "./node3/config.toml") +elif [ "$consensus" == "raft" ]; then + config_files=("./node1/config.toml" "./node2/config.toml" "./node3/config.toml") +fi + +# define which port used for queries +if [ "$consensus" == "sbp" ]; then + query_port="7845" +else + query_port="9845" +fi -# open the aergo server in testmode to create the config file echo "" -echo "starting the aergo server..." -../bin/aergosvr --testmode --home ./aergo-files > logs 2> logs & -pid=$! -# wait it to be ready -sleep 2 +echo "starting nodes..." +start_nodes +# get the current hardfork version version=$(../bin/aergocli blockchain | jq .ChainInfo.Chainid.Version | sed 's/"//g') function set_version() { @@ -31,21 +80,16 @@ function set_version() { block_no=$(../bin/aergocli blockchain | jq .Height | sed 's/"//g') # increment 2 numbers block_no=$((block_no+2)) - # terminate the server process - kill $pid - # save the hardfork config on the config file - echo "updating the config file..." - if [ $version -eq 2 ]; then - sed -i "s/^v2 = \"10000\"$/v2 = \"${block_no}\"/" ./aergo-files/config.toml - elif [ $version -eq 3 ]; then - sed -i "s/^v3 = \"10000\"$/v3 = \"${block_no}\"/" ./aergo-files/config.toml - fi + # terminate the server process(es) + stop_nodes + # save the hardfork config on the config file(s) + echo "updating the config file(s)..." + for config_file in "${config_files[@]}"; do + sed -i "s/^v$version = \"10000\"$/v$version = \"${block_no}\"/" $config_file + done # restart the aergo server - echo "restarting the aergo server..." - ../bin/aergosvr --testmode --home ./aergo-files > logs 2> logs & - pid=$! - # wait it to be ready - sleep 3 + echo "restarting the aergo nodes..." + start_nodes # check if it worked new_version=$(../bin/aergocli blockchain | jq .ChainInfo.Chainid.Version | sed 's/"//g') if [ $new_version -ne $version ]; then @@ -77,6 +121,10 @@ function check() { fi } +# make these variables accessible to the called scripts +export consensus +export query_port + # create the account used on tests echo "creating user account..." ../bin/aergocli account import --keystore . --if 47zh1byk8MqWkQo5y8dvbrex99ZMdgZqfydar7w2QQgQqc7YrmFsBuMeF1uHWa5TwA1ZwQ7V6 --password bmttest @@ -103,9 +151,9 @@ check ./test-contract-deploy.sh # terminate the server process echo "" -echo "closing the aergo server" +echo "closing the aergo nodes" echo "" -kill $pid +stop_nodes # print the summary if [ $num_failed_tests -gt 0 ]; then diff --git a/tests/test-brick.sh b/tests/test-brick.sh deleted file mode 100755 index 155dd32c6..000000000 --- a/tests/test-brick.sh +++ /dev/null @@ -1 +0,0 @@ -../bin/brick -V test.brick diff --git a/tests/test-gas-per-function-v2.sh b/tests/test-gas-per-function-v2.sh index 3fd16a4a8..40091b577 100755 --- a/tests/test-gas-per-function-v2.sh +++ b/tests/test-gas-per-function-v2.sh @@ -16,9 +16,26 @@ address=$(cat receipt.json | jq .contractAddress | sed 's/"//g') assert_equals "$status" "CREATED" +echo "-- transfer funds to the contract --" + +from=AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + sendtx --from $from --to $address --amount 5aergo \ + | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "{}" + + echo "-- get account's nonce --" -account_state=$(../bin/aergocli getstate --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R) +account_state=$(../bin/aergocli getstate --address $from) nonce=$(echo $account_state | jq .nonce | sed 's/"//g') @@ -141,7 +158,7 @@ add_test "system.getCreator" 135156 add_test "system.getOrigin" 135656 add_test "contract.send" 135716 -add_test "contract.balance" 135797 +#add_test "contract.balance" 135797 add_test "contract.deploy" 158752 add_test "contract.call" 149642 add_test "contract.pcall" 150563 diff --git a/tests/test-gas-per-function-v3.sh b/tests/test-gas-per-function-v3.sh index abe5ad2ee..35c39caff 100755 --- a/tests/test-gas-per-function-v3.sh +++ b/tests/test-gas-per-function-v3.sh @@ -16,9 +16,26 @@ address=$(cat receipt.json | jq .contractAddress | sed 's/"//g') assert_equals "$status" "CREATED" +echo "-- transfer funds to the contract --" + +from=AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R + +txhash=$(../bin/aergocli --keystore . --password bmttest \ + sendtx --from $from --to $address --amount 5aergo \ + | jq .hash | sed 's/"//g') + +get_receipt $txhash + +status=$(cat receipt.json | jq .status | sed 's/"//g') +ret=$(cat receipt.json | jq .ret | sed 's/"//g') + +assert_equals "$status" "SUCCESS" +assert_equals "$ret" "{}" + + echo "-- get account's nonce --" -account_state=$(../bin/aergocli getstate --address AmPpcKvToDCUkhT1FJjdbNvR4kNDhLFJGHkSqfjWe3QmHm96qv4R) +account_state=$(../bin/aergocli getstate --address $from) nonce=$(echo $account_state | jq .nonce | sed 's/"//g') @@ -141,7 +158,7 @@ add_test "system.getCreator" 135156 add_test "system.getOrigin" 135656 add_test "contract.send" 135716 -add_test "contract.balance" 135797 +#add_test "contract.balance" 135797 add_test "contract.deploy" 158752 add_test "contract.call" 149642 add_test "contract.pcall" 150563