The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
woop/core/blockchain_test.go

86 lines
3.4 KiB

Resolve harmony-one/bounties#77: Staking precompiles (#3906) * Resolve harmony-one/bounties#77: Staking precompiles Create write capable precompiles that can perform staking transactions Add hard fork logic (EpochTBD) for these precompiles Tests for new code with at least 80% unit test coverage Staking library + tests in MaxMustermann2/harmony-staking-precompiles * Fix small typo in comment * Run goimports on files to fix Travis * Do not activate staking precompile on shard 0 * Cascade readOnly to WriteCapableContract * No overlap in readOnly + writeCapable precompiles * Use function selector instead of directive From Solidity, use abi.encodeWithSelector and match it against the exact ABI of the functions. This allows us to remove the need for a directive (32) being encoded, and thus saves 28 bytes of data. * Do not allow contracts to become validators As discussed with Jacky on #3906 * Merge harmony-one/harmony/main properly this time * Run goimports * Update gas calculation for staking precompile Please see comment in core/vm/contracts_write.go RequiredGas * Do not allow contract to become validator (2/2) * Cache StakeMsgs from precompiled transactions Add the StakeMsgs to ProcessorResult and cascade them in insertChain * Remove ContractCode fields from validators Since smart contracts can no longer beecome validators, this field is superfluous. Remove it from the Wrapper structure, and do not assign it a value when creating a validator. Build and goimports checked * Update comments in response to feedback (1) Comments to start with function names (2) Comments for public variables (3) Comment to match function name RunPrecompiledContract (4) Clarify that CreateValidatorFunc + EditValidatorFunc are still used * Fix Travis build by reverting rosetta change * Add revert capability to 3 staking tx types - Delegate - Undelegate - CollectRewards * Fix build: Update evm_test for ValidatorWrapper * Merge main into harmony-staking-precompiles * Add gas for precompile calls and allow EOA usage - Each time the precompile is called, charge the base gas fee plus data cost (if data can be parsed successfully). A gas fee is added to prevent benevolent contract deployers from subsidizing the staking transactions for EOAs through repeated assembly `delegatecall`. - Allow EOAs to use the staking precompile directly. Some changes to the Solidity library are associated with this change. - Remove bytes from parsing address, since the ABI unpacks it into an address format correctly. - Add or update tests. Test coverage report to be attached to the PR shortly. * Run goimports * Check read only and write capable for overlap * Handle precompile stakeMsgs for block proposer The staking precompile generates staking messages which are cascaded to the block via the EVM in `state_processor.go`. This change cascades them in `worker.go` to allow block proposers and block verifiers to keep the same state. * Run goimports for cf2dfac4081444e36a120c9432f4e.. * Update staking precompile epoch to 2 for localnet Bring it in line with staking epoch. Change effects all configurations except mainnet and testnet. `goimports` included. * Add read only precompile to fetch the epoch num * Move epoch precompile to 250 * precompiles: left pad the returned epoch number * chainConfig: check epochs for precompiles panic if staking precompile epoch < pre staking epoch * Add staking migration precompile - Lives at address 251 - Migrates delegations + pending undelegations from address A to B - Useful if address A is hacked - Charges gas of 21k + cost of bytes for two addresses - Does not remove existing delegations, just sets them to zero. Replicates current undelegate setup - Unit tests and `goimports` included. Integration test following shortly in MaxMustermann2/harmony-staking-precompiles * Migration precompile: merge into staking Merge the two precompiles into one, add gas calculation for migration precompile. Move epoch precompile to 251 as a result. When migrating, add undelegations to `To`'s existing undelegations, if any match the epoch. * Add migration gas test, remove panic, add check In response to review comments, add tests for migration gas wherein there are 0/1/2 delegations to migrate. Add the index out of bound check to migration gas calculator and remove panics. Lastly, re-sort migrated undelegations if no existing undelegation in the same epoch was found on `To`. * Move undelegations sorting to end of loop
3 years ago
package core
import (
"crypto/ecdsa"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/core/types"
staking "github.com/harmony-one/harmony/staking/types"
)
func TestPrepareStakingMetadata(t *testing.T) {
key, _ := crypto.GenerateKey()
chain, db, header, _ := getTestEnvironment(*key)
// fake transaction
tx := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), 0, big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
txs := []*types.Transaction{tx}
// fake staking transactions
stx1 := signedCreateValidatorStakingTxn(key)
stx2 := signedDelegateStakingTxn(key)
stxs := []*staking.StakingTransaction{stx1, stx2}
// make a fake block header
block := types.NewBlock(header, txs, []*types.Receipt{types.NewReceipt([]byte{}, false, 0), types.NewReceipt([]byte{}, false, 0),
types.NewReceipt([]byte{}, false, 0)}, nil, nil, stxs)
// run it
if _, _, err := chain.prepareStakingMetaData(block, []staking.StakeMsg{&staking.Delegate{}}, db); err != nil {
if err.Error() != "address not present in state" { // when called in test for core/vm
t.Errorf("Got error %v in prepareStakingMetaData", err)
}
} else {
// when called independently there is no error
}
}
func signedCreateValidatorStakingTxn(key *ecdsa.PrivateKey) *staking.StakingTransaction {
stakePayloadMaker := func() (staking.Directive, interface{}) {
return staking.DirectiveCreateValidator, sampleCreateValidator(*key)
}
stx, _ := staking.NewStakingTransaction(0, 1e10, big.NewInt(10000), stakePayloadMaker)
signed, _ := staking.Sign(stx, staking.NewEIP155Signer(stx.ChainID()), key)
return signed
}
func signedEditValidatorStakingTxn(key *ecdsa.PrivateKey) *staking.StakingTransaction {
stakePayloadMaker := func() (staking.Directive, interface{}) {
return staking.DirectiveEditValidator, sampleEditValidator(*key)
}
stx, _ := staking.NewStakingTransaction(0, 1e10, big.NewInt(10000), stakePayloadMaker)
signed, _ := staking.Sign(stx, staking.NewEIP155Signer(stx.ChainID()), key)
return signed
}
func signedDelegateStakingTxn(key *ecdsa.PrivateKey) *staking.StakingTransaction {
stakePayloadMaker := func() (staking.Directive, interface{}) {
return staking.DirectiveDelegate, sampleDelegate(*key)
}
// nonce, gasLimit uint64, gasPrice *big.Int, f StakeMsgFulfiller
stx, _ := staking.NewStakingTransaction(0, 1e10, big.NewInt(10000), stakePayloadMaker)
signed, _ := staking.Sign(stx, staking.NewEIP155Signer(stx.ChainID()), key)
return signed
}
func signedUndelegateStakingTxn(key *ecdsa.PrivateKey) *staking.StakingTransaction {
stakePayloadMaker := func() (staking.Directive, interface{}) {
return staking.DirectiveUndelegate, sampleUndelegate(*key)
}
// nonce, gasLimit uint64, gasPrice *big.Int, f StakeMsgFulfiller
stx, _ := staking.NewStakingTransaction(0, 1e10, big.NewInt(10000), stakePayloadMaker)
signed, _ := staking.Sign(stx, staking.NewEIP155Signer(stx.ChainID()), key)
return signed
}
func signedCollectRewardsStakingTxn(key *ecdsa.PrivateKey) *staking.StakingTransaction {
stakePayloadMaker := func() (staking.Directive, interface{}) {
return staking.DirectiveCollectRewards, sampleCollectRewards(*key)
}
// nonce, gasLimit uint64, gasPrice *big.Int, f StakeMsgFulfiller
stx, _ := staking.NewStakingTransaction(0, 1e10, big.NewInt(10000), stakePayloadMaker)
signed, _ := staking.Sign(stx, staking.NewEIP155Signer(stx.ChainID()), key)
return signed
}