Skip to content

Commit

Permalink
Merge pull request #137 from Taraxa-project/dpos_contract_logs
Browse files Browse the repository at this point in the history
feat: add dpos contract logs
  • Loading branch information
kstdl authored Jan 27, 2023
2 parents 79439f8 + 0d93aad commit dad8a35
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 62 deletions.
28 changes: 28 additions & 0 deletions accounts/abi/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ package abi

import (
"fmt"
"reflect"
"strings"

"github.com/Taraxa-project/taraxa-evm/common"
"github.com/Taraxa-project/taraxa-evm/core/vm"
"github.com/Taraxa-project/taraxa-evm/crypto"
)

Expand Down Expand Up @@ -55,3 +57,29 @@ func (e Event) Id() common.Hash {
}
return common.BytesToHash(crypto.Keccak256([]byte(fmt.Sprintf("%v(%v)", e.Name, strings.Join(types, ",")))))
}

func (e Event) MakeLog(args ...interface{}) (*vm.LogRecord, error) {
if len(e.Inputs) != len(args) {
return nil, fmt.Errorf("MakeLog: %v: expected %v arguments, but got %v", e.Name, len(e.Inputs), len(args))
}
log := new(vm.LogRecord)
log.Topics = append(log.Topics, e.Id())
data_set := false
for index, input := range e.Inputs {
bytes, err := input.Type.pack(reflect.ValueOf(args[index]))
if err != nil {
return nil, err
}
if input.Indexed {
log.Topics = append(log.Topics, common.BytesToHash(bytes))
} else {
if data_set {
return nil, fmt.Errorf("Only one not indexed param is supported right now")
}
data_set = true
log.Data = bytes
}

}
return log, nil
}
4 changes: 4 additions & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func (self *EVM) Init(get_hash GetHashFunc, state State, opts Opts, config param
return self
}

func (self *EVM) AddLog(log LogRecord) {
self.state.AddLog(log)
}

// func (self *EVM) GetRules() Rules {
// return self.rules
// }
Expand Down
5 changes: 3 additions & 2 deletions taraxa/state/dpos/precompiled/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/Taraxa-project/taraxa-evm/common"
"github.com/Taraxa-project/taraxa-evm/core/types"
"github.com/Taraxa-project/taraxa-evm/core/vm"
)

func ContractAddress() common.Address {
Expand Down Expand Up @@ -111,8 +112,8 @@ func (self *API) UpdateConfig(blk_n types.BlockNum, cfg Config) {
self.cfg = cfg
}

func (self *API) NewContract(storage Storage, reader Reader) *Contract {
return new(Contract).Init(self.cfg, storage, reader)
func (self *API) NewContract(storage Storage, reader Reader, evm *vm.EVM) *Contract {
return new(Contract).Init(self.cfg, storage, reader, evm)
}

func (self *API) NewReader(blk_n types.BlockNum, storage_factory func(types.BlockNum) StorageReader) (ret Reader) {
Expand Down
91 changes: 53 additions & 38 deletions taraxa/state/dpos/precompiled/dpos_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ type Contract struct {
// delayed storage for PBFT
delayedStorage Reader
// ABI of the contract
Abi abi.ABI
Abi abi.ABI
logs Logs
evm *vm.EVM

// Iterable storages
validators Validators
Expand All @@ -150,10 +152,11 @@ type Contract struct {
}

// Initialize contract class
func (self *Contract) Init(cfg Config, storage Storage, readStorage Reader) *Contract {
func (self *Contract) Init(cfg Config, storage Storage, readStorage Reader, evm *vm.EVM) *Contract {
self.cfg = cfg
self.storage.Init(storage)
self.delayedStorage = readStorage
self.evm = evm
return self
}

Expand All @@ -177,7 +180,7 @@ func (self *Contract) Register(registry func(*common.Address, vm.PrecompiledCont
func (self *Contract) RequiredGas(ctx vm.CallFrame, evm *vm.EVM) uint64 {
// Init abi and some of the structures required for calculating gas, e.g. self.validators for getValidators
self.lazy_init()

method, err := self.Abi.MethodById(ctx.Input)
if err != nil {
return 0
Expand Down Expand Up @@ -279,6 +282,7 @@ func (self *Contract) lazy_init() {
}

self.Abi, _ = abi.JSON(strings.NewReader(sol.TaraxaDposClientMetaData))
self.logs = *new(Logs).Init(self.Abi.Events)

self.validators.Init(&self.storage, field_validators)
self.delegations.Init(&self.storage, field_delegations)
Expand Down Expand Up @@ -432,7 +436,6 @@ func (self *Contract) Run(ctx vm.CallFrame, evm *vm.EVM) ([]byte, error) {
return nil, self.setCommission(ctx, evm.GetBlock().Number, args)

case "registerValidator":

var args sol.RegisterValidatorArgs
if err = method.Inputs.Unpack(&args, input); err != nil {
fmt.Println("Unable to parse registerValidator input args: ", err)
Expand Down Expand Up @@ -713,6 +716,8 @@ func (self *Contract) delegate(ctx vm.CallFrame, block types.BlockNum, args sol.
state.Count++
self.state_put(&state_k, state)
self.validators.ModifyValidator(&args.Validator, validator)
self.evm.AddLog(self.logs.MakeDelegatedLog(ctx.CallerAccount.Address(), &args.Validator, ctx.Value))

return nil
}

Expand Down Expand Up @@ -788,11 +793,12 @@ func (self *Contract) undelegate(ctx vm.CallFrame, block types.BlockNum, args so
self.state_put(&state_k, state)
self.validators.ModifyValidator(&args.Validator, validator)
}
self.evm.AddLog(self.logs.MakeUndelegatedLog(ctx.CallerAccount.Address(), &args.Validator, args.Amount))

return nil
}

// Removes undelegation from queue and moves staked toknes back to delegator
// Removes undelegation from queue and moves staked tokens back to delegator
// This only works after lock-up period expires
func (self *Contract) confirmUndelegate(ctx vm.CallFrame, block types.BlockNum, args sol.ValidatorAddressArgs) error {
if !self.undelegations.UndelegationExists(ctx.CallerAccount.Address(), &args.Validator) {
Expand All @@ -805,6 +811,8 @@ func (self *Contract) confirmUndelegate(ctx vm.CallFrame, block types.BlockNum,
self.undelegations.RemoveUndelegation(ctx.CallerAccount.Address(), &args.Validator)
// TODO slashing of balance
ctx.CallerAccount.AddBalance(undelegation.Amount)
self.evm.AddLog(self.logs.MakeUndelegateConfirmedLog(ctx.CallerAccount.Address(), &args.Validator, undelegation.Amount))

return nil
}

Expand Down Expand Up @@ -859,6 +867,8 @@ func (self *Contract) cancelUndelegate(ctx vm.CallFrame, block types.BlockNum, a
state.Count++
self.state_put(&state_k, state)
self.validators.ModifyValidator(&args.Validator, validator)
self.evm.AddLog(self.logs.MakeUndelegateCanceledLog(ctx.CallerAccount.Address(), &args.Validator, undelegation.Amount))

return nil
}

Expand Down Expand Up @@ -937,45 +947,44 @@ func (self *Contract) redelegate(ctx vm.CallFrame, block types.BlockNum, args so
}

// Now we delegate
{
state, state_k := self.state_get(args.ValidatorTo[:], BlockToBytes(block))
if state == nil {
old_state := self.state_get_and_decrement(args.ValidatorTo[:], BlockToBytes(validator_to.LastUpdated))
state = new(State)
state.RewardsPer1Stake = bigutil.Add(old_state.RewardsPer1Stake, self.calculateRewardPer1Stake(validator_to.RewardsPool, validator_to.TotalStake))
validator_to.RewardsPool = big.NewInt(0)
validator_to.LastUpdated = block
state.Count++
}

delegation := self.delegations.GetDelegation(ctx.CallerAccount.Address(), &args.ValidatorTo)
state, state_k := self.state_get(args.ValidatorTo[:], BlockToBytes(block))
if state == nil {
old_state := self.state_get_and_decrement(args.ValidatorTo[:], BlockToBytes(validator_to.LastUpdated))
state = new(State)
state.RewardsPer1Stake = bigutil.Add(old_state.RewardsPer1Stake, self.calculateRewardPer1Stake(validator_to.RewardsPool, validator_to.TotalStake))
validator_to.RewardsPool = big.NewInt(0)
validator_to.LastUpdated = block
state.Count++
}

if delegation == nil {
self.delegations.CreateDelegation(ctx.CallerAccount.Address(), &args.ValidatorTo, block, args.Amount)
validator_to.TotalStake.Add(validator_to.TotalStake, args.Amount)
} else {
// We need to claim rewards first
old_state := self.state_get_and_decrement(args.ValidatorTo[:], BlockToBytes(delegation.LastUpdated))
reward_per_stake := bigutil.Sub(state.RewardsPer1Stake, old_state.RewardsPer1Stake)
ctx.CallerAccount.AddBalance(self.calculateDelegatorReward(reward_per_stake, delegation.Stake))
delegation := self.delegations.GetDelegation(ctx.CallerAccount.Address(), &args.ValidatorTo)

delegation.Stake.Add(delegation.Stake, args.Amount)
delegation.LastUpdated = block
self.delegations.ModifyDelegation(ctx.CallerAccount.Address(), &args.ValidatorTo, delegation)
if delegation == nil {
self.delegations.CreateDelegation(ctx.CallerAccount.Address(), &args.ValidatorTo, block, args.Amount)
validator_to.TotalStake.Add(validator_to.TotalStake, args.Amount)
} else {
// We need to claim rewards first
old_state := self.state_get_and_decrement(args.ValidatorTo[:], BlockToBytes(delegation.LastUpdated))
reward_per_stake := bigutil.Sub(state.RewardsPer1Stake, old_state.RewardsPer1Stake)
ctx.CallerAccount.AddBalance(self.calculateDelegatorReward(reward_per_stake, delegation.Stake))

validator_to.TotalStake.Add(validator_to.TotalStake, args.Amount)
}
delegation.Stake.Add(delegation.Stake, args.Amount)
delegation.LastUpdated = block
self.delegations.ModifyDelegation(ctx.CallerAccount.Address(), &args.ValidatorTo, delegation)

new_vote_count := voteCount(validator_to.TotalStake, self.cfg.EligibilityBalanceThreshold, self.cfg.VoteEligibilityBalanceStep)
if prev_vote_count_to != new_vote_count {
self.eligible_vote_count -= prev_vote_count_to
self.eligible_vote_count = add64p(self.eligible_vote_count, new_vote_count)
}
validator_to.TotalStake.Add(validator_to.TotalStake, args.Amount)
}

state.Count++
self.state_put(&state_k, state)
self.validators.ModifyValidator(&args.ValidatorTo, validator_to)
new_vote_count := voteCount(validator_to.TotalStake, self.cfg.EligibilityBalanceThreshold, self.cfg.VoteEligibilityBalanceStep)
if prev_vote_count_to != new_vote_count {
self.eligible_vote_count -= prev_vote_count_to
self.eligible_vote_count = add64p(self.eligible_vote_count, new_vote_count)
}

state.Count++
self.state_put(&state_k, state)
self.validators.ModifyValidator(&args.ValidatorTo, validator_to)
self.evm.AddLog(self.logs.MakeRedelegatedLog(ctx.CallerAccount.Address(), &args.ValidatorFrom, &args.ValidatorTo, args.Amount))
return nil
}

Expand Down Expand Up @@ -1010,6 +1019,7 @@ func (self *Contract) claimRewards(ctx vm.CallFrame, block types.BlockNum, args

state.Count++
self.state_put(&state_k, state)
self.evm.AddLog(self.logs.MakeRewardsClaimedLog(ctx.CallerAccount.Address(), &args.Validator))

return nil
}
Expand All @@ -1034,6 +1044,7 @@ func (self *Contract) claimCommissionRewards(ctx vm.CallFrame, block types.Block
} else {
self.validators.ModifyValidator(&args.Validator, validator)
}
self.evm.AddLog(self.logs.MakeCommissionRewardsClaimedLog(ctx.CallerAccount.Address(), &args.Validator))

return nil
}
Expand Down Expand Up @@ -1101,8 +1112,10 @@ func (self *Contract) registerValidatorWithoutChecks(ctx vm.CallFrame, block typ
// Creates validator related objects in storage
validator := self.validators.CreateValidator(owner_address, &args.Validator, args.VrfKey, block, args.Commission, args.Description, args.Endpoint)
state.Count++
self.evm.AddLog(self.logs.MakeValidatorRegisteredLog(&args.Validator))

if ctx.Value.Cmp(big.NewInt(0)) == 1 {
self.evm.AddLog(self.logs.MakeDelegatedLog(owner_address, &args.Validator, ctx.Value))
self.delegations.CreateDelegation(owner_address, &args.Validator, block, ctx.Value)
self.delegate_update_values(ctx, validator, 0)
self.validators.ModifyValidator(&args.Validator, validator)
Expand Down Expand Up @@ -1150,6 +1163,7 @@ func (self *Contract) setValidatorInfo(ctx vm.CallFrame, args sol.SetValidatorIn
validator_info.Endpoint = args.Endpoint

self.validators.ModifyValidatorInfo(&args.Validator, validator_info)
self.evm.AddLog(self.logs.MakeValidatorInfoSetLog(&args.Validator))

return nil
}
Expand Down Expand Up @@ -1180,6 +1194,7 @@ func (self *Contract) setCommission(ctx vm.CallFrame, block types.BlockNum, args
validator.Commission = args.Commission
validator.LastCommissionChange = block
self.validators.ModifyValidator(&args.Validator, validator)
self.evm.AddLog(self.logs.MakeCommissionSetLog(&args.Validator, args.Commission))

return nil
}
Expand Down
100 changes: 100 additions & 0 deletions taraxa/state/dpos/precompiled/dpos_logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package dpos

import (
"math/big"

"github.com/Taraxa-project/taraxa-evm/accounts/abi"
"github.com/Taraxa-project/taraxa-evm/common"
"github.com/Taraxa-project/taraxa-evm/core/vm"
)

func checkError(log *vm.LogRecord, err error) *vm.LogRecord {
if err != nil {
panic("Update logs methods to correspond ABI: " + err.Error())
}
return log
}

type Logs struct {
Events map[string]abi.Event
}

func (self *Logs) Init(events map[string]abi.Event) *Logs {
self.Events = events

return self
}

// All Make functions below are making log records for events.
// All hashes and data types should be the same as we have in solidity interface in ../solidity/dpos_contract_interface.sol
// If some event will be added or changed TestMakeLogsCheckTopics test should be modified

// event Delegated(address indexed delegator, address indexed validator, uint256 amount);
func (self *Logs) MakeDelegatedLog(delegator, validator *common.Address, amount *big.Int) vm.LogRecord {
event := self.Events["Delegated"]

return *checkError(event.MakeLog(delegator, validator, amount))
}

// event Undelegated(address indexed delegator, address indexed validator, uint256 amount);
func (self *Logs) MakeUndelegatedLog(delegator, validator *common.Address, amount *big.Int) vm.LogRecord {
event := self.Events["Undelegated"]

return *checkError(event.MakeLog(delegator, validator, amount))
}

// event UndelegateConfirmed(address indexed delegator, address indexed validator, uint256 amount);
func (self *Logs) MakeUndelegateConfirmedLog(delegator, validator *common.Address, amount *big.Int) vm.LogRecord {
event := self.Events["UndelegateConfirmed"]

return *checkError(event.MakeLog(delegator, validator, amount))
}

// event UndelegateCanceled(address indexed delegator, address indexed validator, uint256 amount);
func (self *Logs) MakeUndelegateCanceledLog(delegator, validator *common.Address, amount *big.Int) vm.LogRecord {
event := self.Events["UndelegateCanceled"]

return *checkError(event.MakeLog(delegator, validator, amount))
}

// event Redelegated(address indexed delegator, address indexed from, address indexed to, uint256 amount);
func (self *Logs) MakeRedelegatedLog(delegator, from, to *common.Address, amount *big.Int) vm.LogRecord {
event := self.Events["Redelegated"]

return *checkError(event.MakeLog(delegator, from, to, amount))
}

// event RewardsClaimed(address indexed account, address indexed validator);
func (self *Logs) MakeRewardsClaimedLog(account, validator *common.Address) vm.LogRecord {
event := self.Events["RewardsClaimed"]

return *checkError(event.MakeLog(account, validator))
}

// event CommissionRewardsClaimed(address indexed account, address indexed validator);
func (self *Logs) MakeCommissionRewardsClaimedLog(account, validator *common.Address) vm.LogRecord {
event := self.Events["CommissionRewardsClaimed"]

return *checkError(event.MakeLog(account, validator))
}

// event CommissionSet(address indexed validator, uint16 commission);
func (self *Logs) MakeCommissionSetLog(account *common.Address, amount uint16) vm.LogRecord {
event := self.Events["CommissionSet"]

return *checkError(event.MakeLog(account, amount))
}

// event ValidatorRegistered(address indexed validator);
func (self *Logs) MakeValidatorRegisteredLog(account *common.Address) vm.LogRecord {
event := self.Events["ValidatorRegistered"]

return *checkError(event.MakeLog(account))
}

// event ValidatorInfoSet(address indexed validator);
func (self *Logs) MakeValidatorInfoSetLog(account *common.Address) vm.LogRecord {
event := self.Events["ValidatorInfoSet"]

return *checkError(event.MakeLog(account))
}
Loading

0 comments on commit dad8a35

Please sign in to comment.