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/state_transition_test.go

84 lines
2.3 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"
"fmt"
"math"
"testing"
"github.com/ethereum/go-ethereum/crypto"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/pkg/errors"
)
type applyStakingMessageTest struct {
name string
tx *staking.StakingTransaction
expectedError error
}
var ApplyStakingMessageTests []applyStakingMessageTest
var key *ecdsa.PrivateKey
func init() {
key, _ = crypto.GenerateKey()
stakingValidatorMissing := errors.New("staking validator does not exist")
ApplyStakingMessageTests = []applyStakingMessageTest{
{
tx: signedCreateValidatorStakingTxn(key),
name: "ApplyStakingMessage_CreateValidator",
},
{
tx: signedEditValidatorStakingTxn(key),
expectedError: stakingValidatorMissing,
name: "ApplyStakingMessage_EditValidator",
},
{
tx: signedDelegateStakingTxn(key),
expectedError: stakingValidatorMissing,
name: "ApplyStakingMessage_Delegate",
},
{
tx: signedUndelegateStakingTxn(key),
expectedError: stakingValidatorMissing,
name: "ApplyStakingMessage_Undelegate",
},
{
tx: signedCollectRewardsStakingTxn(key),
expectedError: errors.New("no rewards to collect"),
name: "ApplyStakingMessage_CollectRewards",
},
}
}
func TestApplyStakingMessages(t *testing.T) {
for _, test := range ApplyStakingMessageTests {
testApplyStakingMessage(test, t)
}
}
func testApplyStakingMessage(test applyStakingMessageTest, t *testing.T) {
chain, db, header, _ := getTestEnvironment(*key)
gp := new(GasPool).AddGas(math.MaxUint64)
t.Run(fmt.Sprintf("%s", test.name), func(t *testing.T) {
// add a fake staking transaction
msg, _ := StakingToMessage(test.tx, header.Number())
// make EVM
ctx := NewEVMContext(msg, header, chain, nil /* coinbase */)
vmenv := vm.NewEVM(ctx, db, params.TestChainConfig, vm.Config{})
// run the staking tx
_, err := ApplyStakingMessage(vmenv, msg, gp, chain)
if err != nil {
if test.expectedError == nil {
t.Errorf(fmt.Sprintf("Got error %v but expected none", err))
} else if test.expectedError.Error() != err.Error() {
t.Errorf(fmt.Sprintf("Got error %v, but expected %v", err, test.expectedError))
}
}
})
}