contract/name/execute.go
package name
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/aergoio/aergo/v2/contract/system"
"github.com/aergoio/aergo/v2/state"
"github.com/aergoio/aergo/v2/state/statedb"
"github.com/aergoio/aergo/v2/types"
)
func ExecuteNameTx(bs *state.BlockState, scs *statedb.ContractState, txBody *types.TxBody,
sender, receiver *state.AccountState, blockInfo *types.BlockHeaderInfo) ([]*types.Event, error) {
ci, err := ValidateNameTx(txBody, sender, scs)
if err != nil {
return nil, err
}
var nameState *state.AccountState
owner := getOwner(scs, []byte(types.AergoName), false)
if owner != nil {
if bytes.Equal(sender.ID(), owner) {
nameState = sender
} else {
if nameState, err = state.GetAccountState(owner, bs.StateDB); err != nil {
return nil, err
}
}
} else {
nameState = receiver
}
var events []*types.Event
switch ci.Name {
case types.NameCreate:
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":"` + nameArg + `"}`
} else {
jsonArgs = `["` + nameArg + `"]`
}
events = append(events, &types.Event{
ContractAddress: receiver.ID(),
EventIdx: 0,
EventName: "create name",
JsonArgs: jsonArgs,
})
case types.NameUpdate:
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":"` + nameArg + `","to":"` + toArg + `"}`
} else {
jsonArgs = `["` + nameArg + `","` + toArg + `"]`
}
events = append(events, &types.Event{
ContractAddress: receiver.ID(),
EventIdx: 0,
EventName: "update name",
JsonArgs: jsonArgs,
})
case types.SetContractOwner:
ownerArg := ci.Args[0].(string)
ownerState, err := SetContractOwner(bs, scs, ownerArg, nameState)
if err != nil {
return nil, err
}
ownerState.PutState()
}
nameState.PutState()
return events, nil
}
func ValidateNameTx(tx *types.TxBody, sender *state.AccountState, scs *statedb.ContractState) (*types.CallInfo, error) {
if sender != nil && sender.Balance().Cmp(tx.GetAmountBigInt()) < 0 {
return nil, types.ErrInsufficientBalance
}
var ci types.CallInfo
if err := json.Unmarshal(tx.Payload, &ci); err != nil {
return nil, err
}
nameArg := ci.Args[0].(string)
switch ci.Name {
case types.NameCreate:
if system.GetNamePrice().Cmp(tx.GetAmountBigInt()) > 0 {
return nil, types.ErrTooSmallAmount
}
if owner := getOwner(scs, []byte(nameArg), false); owner != nil {
return nil, fmt.Errorf("aleady occupied %s", string(nameArg))
}
case types.NameUpdate:
if system.GetNamePrice().Cmp(tx.GetAmountBigInt()) > 0 {
return nil, types.ErrTooSmallAmount
}
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:
if owner := getOwner(scs, []byte(types.AergoName), false); owner != nil {
return nil, fmt.Errorf("owner aleady set to %s", types.EncodeAddress(owner))
}
default:
return nil, errors.New("could not execute unknown cmd")
}
return &ci, nil
}
func SetContractOwner(bs *state.BlockState, scs *statedb.ContractState,
address string, nameState *state.AccountState) (*state.AccountState, error) {
rawaddr, err := types.DecodeAddress(address)
if err != nil {
return nil, err
}
ownerState, err := state.GetAccountState(rawaddr, bs.StateDB)
if err != nil {
return nil, err
}
if err = state.SendBalance(nameState, ownerState, nameState.Balance()); err != nil {
return nil, err
}
name := []byte(types.AergoName)
if err = registerOwner(scs, name, rawaddr, name); err != nil {
return nil, err
}
return ownerState, nil
}