aergoio/aergo

View on GitHub
contract/name/execute.go

Summary

Maintainability
B
4 hrs
Test Coverage
C
79%
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
}