core: implement skeletons for NEO/GAS native contracts
This commit is contained in:
parent
25354c44f9
commit
76700f31cf
9 changed files with 893 additions and 105 deletions
|
@ -198,6 +198,9 @@ func (bc *Blockchain) init() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bc.initNative(); err != nil {
|
||||
return err
|
||||
}
|
||||
return bc.storeBlock(genesisBlock)
|
||||
}
|
||||
if ver != version {
|
||||
|
@ -270,6 +273,27 @@ func (bc *Blockchain) init() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (bc *Blockchain) initNative() error {
|
||||
ic := bc.newInteropContext(trigger.Application, bc.dao, nil, nil)
|
||||
|
||||
gas := native.NewGAS()
|
||||
neo := native.NewNEO()
|
||||
neo.GAS = gas
|
||||
gas.NEO = neo
|
||||
|
||||
if err := gas.Initialize(ic); err != nil {
|
||||
return fmt.Errorf("can't initialize GAS native contract: %v", err)
|
||||
}
|
||||
if err := neo.Initialize(ic); err != nil {
|
||||
return fmt.Errorf("can't initialize NEO native contract: %v", err)
|
||||
}
|
||||
|
||||
bc.contracts.SetGAS(gas)
|
||||
bc.contracts.SetNEO(neo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run runs chain loop.
|
||||
func (bc *Blockchain) Run() {
|
||||
persistTimer := time.NewTimer(persistInterval)
|
||||
|
@ -639,7 +663,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
|||
return err
|
||||
}
|
||||
case *transaction.StateTX:
|
||||
if err := processStateTX(cache, t); err != nil {
|
||||
if err := bc.processStateTX(cache, tx, t); err != nil {
|
||||
return err
|
||||
}
|
||||
case *transaction.PublishTX:
|
||||
|
@ -887,21 +911,8 @@ func processTXWithValidatorsSubtract(output *transaction.Output, account *state.
|
|||
|
||||
// modAccountVotes adds given value to given account voted validators.
|
||||
func modAccountVotes(account *state.Account, dao *dao.Cached, value util.Fixed8) error {
|
||||
for _, vote := range account.Votes {
|
||||
validator, err := dao.GetValidatorStateOrNew(vote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
validator.Votes += value
|
||||
if validator.UnregisteredAndHasNoVotes() {
|
||||
if err := dao.DeleteValidatorState(validator); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := dao.PutValidatorState(validator); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := native.ModifyAccountVotes(account, dao, value); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(account.Votes) > 0 {
|
||||
vc, err := dao.GetValidatorsCount()
|
||||
|
@ -937,55 +948,19 @@ func processValidatorStateDescriptor(descriptor *transaction.StateDescriptor, da
|
|||
return nil
|
||||
}
|
||||
|
||||
func processAccountStateDescriptor(descriptor *transaction.StateDescriptor, dao *dao.Cached) error {
|
||||
func (bc *Blockchain) processAccountStateDescriptor(descriptor *transaction.StateDescriptor, t *transaction.Transaction, dao *dao.Cached) error {
|
||||
hash, err := util.Uint160DecodeBytesBE(descriptor.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
account, err := dao.GetAccountStateOrNew(hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if descriptor.Field == "Votes" {
|
||||
balance := account.GetBalanceValues()[GoverningTokenID()]
|
||||
if err = modAccountVotes(account, dao, -balance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
votes := keys.PublicKeys{}
|
||||
err := votes.DecodeBytes(descriptor.Value)
|
||||
if err != nil {
|
||||
if err := votes.DecodeBytes(descriptor.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(votes) > state.MaxValidatorsVoted {
|
||||
return errors.New("voting candidate limit exceeded")
|
||||
}
|
||||
if len(votes) > 0 {
|
||||
account.Votes = votes
|
||||
for _, vote := range account.Votes {
|
||||
validatorState, err := dao.GetValidatorStateOrNew(vote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
validatorState.Votes += balance
|
||||
if err = dao.PutValidatorState(validatorState); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
vc, err := dao.GetValidatorsCount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vc[len(account.Votes)-1] += balance
|
||||
err = dao.PutValidatorsCount(vc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
account.Votes = nil
|
||||
}
|
||||
return dao.PutAccountState(account)
|
||||
ic := bc.newInteropContext(trigger.Application, dao, nil, t)
|
||||
return bc.contracts.NEO.VoteInternal(ic, hash, votes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1807,59 +1782,14 @@ func (bc *Blockchain) GetValidators(txes ...*transaction.Transaction) ([]*keys.P
|
|||
return nil, err
|
||||
}
|
||||
case *transaction.StateTX:
|
||||
if err := processStateTX(cache, t); err != nil {
|
||||
if err := bc.processStateTX(cache, tx, t); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validators := cache.GetValidators()
|
||||
sort.Slice(validators, func(i, j int) bool {
|
||||
// Unregistered validators go to the end of the list.
|
||||
if validators[i].Registered != validators[j].Registered {
|
||||
return validators[i].Registered
|
||||
}
|
||||
// The most-voted validators should end up in the front of the list.
|
||||
if validators[i].Votes != validators[j].Votes {
|
||||
return validators[i].Votes > validators[j].Votes
|
||||
}
|
||||
// Ties are broken with public keys.
|
||||
return validators[i].PublicKey.Cmp(validators[j].PublicKey) == -1
|
||||
})
|
||||
|
||||
validatorsCount, err := cache.GetValidatorsCount()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count := validatorsCount.GetWeightedAverage()
|
||||
standByValidators, err := bc.GetStandByValidators()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if count < len(standByValidators) {
|
||||
count = len(standByValidators)
|
||||
}
|
||||
|
||||
uniqueSBValidators := standByValidators.Unique()
|
||||
result := keys.PublicKeys{}
|
||||
for _, validator := range validators {
|
||||
if validator.RegisteredAndHasVotes() || uniqueSBValidators.Contains(validator.PublicKey) {
|
||||
result = append(result, validator.PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
if result.Len() >= count {
|
||||
result = result[:count]
|
||||
} else {
|
||||
for i := 0; i < uniqueSBValidators.Len() && result.Len() < count; i++ {
|
||||
if !result.Contains(uniqueSBValidators[i]) {
|
||||
result = append(result, uniqueSBValidators[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Sort(result)
|
||||
return result, nil
|
||||
return bc.contracts.NEO.GetValidatorsInternal(bc, cache)
|
||||
}
|
||||
|
||||
// GetEnrollments returns all registered validators and non-registered SB validators
|
||||
|
@ -1896,11 +1826,11 @@ func (bc *Blockchain) GetEnrollments() ([]*state.Validator, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func processStateTX(dao *dao.Cached, tx *transaction.StateTX) error {
|
||||
func (bc *Blockchain) processStateTX(dao *dao.Cached, t *transaction.Transaction, tx *transaction.StateTX) error {
|
||||
for _, desc := range tx.Descriptors {
|
||||
switch desc.Type {
|
||||
case transaction.Account:
|
||||
if err := processAccountStateDescriptor(desc, dao); err != nil {
|
||||
if err := bc.processAccountStateDescriptor(desc, t, dao); err != nil {
|
||||
return err
|
||||
}
|
||||
case transaction.Validator:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue