-
Notifications
You must be signed in to change notification settings - Fork 199
/
saveUserName.go
112 lines (97 loc) · 3.18 KB
/
saveUserName.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package builtInFunctions
import (
"encoding/hex"
"math/big"
"sync"
"github.com/ElrondNetwork/elrond-go/core"
"github.com/ElrondNetwork/elrond-go/core/check"
"github.com/ElrondNetwork/elrond-go/core/vmcommon"
"github.com/ElrondNetwork/elrond-go/data/state"
"github.com/ElrondNetwork/elrond-go/process"
)
var _ process.BuiltinFunction = (*saveUserName)(nil)
type saveUserName struct {
gasCost uint64
mapDnsAddresses map[string]struct{}
enableChange bool
mutExecution sync.RWMutex
}
// NewSaveUserNameFunc returns a username built in function implementation
func NewSaveUserNameFunc(
gasCost uint64,
mapDnsAddresses map[string]struct{},
enableChange bool,
) (*saveUserName, error) {
if mapDnsAddresses == nil {
return nil, process.ErrNilDnsAddresses
}
s := &saveUserName{
gasCost: gasCost,
enableChange: enableChange,
}
s.mapDnsAddresses = make(map[string]struct{}, len(mapDnsAddresses))
for key := range mapDnsAddresses {
s.mapDnsAddresses[key] = struct{}{}
}
return s, nil
}
// SetNewGasConfig is called whenever gas cost is changed
func (s *saveUserName) SetNewGasConfig(gasCost *process.GasCost) {
s.mutExecution.Lock()
s.gasCost = gasCost.BuiltInCost.SaveUserName
s.mutExecution.Unlock()
}
// ProcessBuiltinFunction sets the username to the account if it is allowed
func (s *saveUserName) ProcessBuiltinFunction(
_, acntDst state.UserAccountHandler,
vmInput *vmcommon.ContractCallInput,
) (*vmcommon.VMOutput, error) {
s.mutExecution.RLock()
defer s.mutExecution.RUnlock()
if vmInput == nil {
return nil, process.ErrNilVmInput
}
if vmInput.CallValue.Cmp(zero) != 0 {
return nil, process.ErrBuiltInFunctionCalledWithValue
}
if vmInput.GasProvided < s.gasCost {
return nil, process.ErrNotEnoughGas
}
_, ok := s.mapDnsAddresses[string(vmInput.CallerAddr)]
if !ok {
return nil, process.ErrCallerIsNotTheDNSAddress
}
if len(vmInput.Arguments) != 1 {
return nil, process.ErrInvalidArguments
}
if check.IfNil(acntDst) {
log.Trace("setUserName called dst not in shard")
// cross-shard call, in sender shard only the gas is taken out
vmOutput := &vmcommon.VMOutput{ReturnCode: vmcommon.Ok}
vmOutput.OutputAccounts = make(map[string]*vmcommon.OutputAccount)
setUserNameTxData := core.BuiltInFunctionSetUserName + "@" + hex.EncodeToString(vmInput.Arguments[0])
outTransfer := vmcommon.OutputTransfer{
Value: big.NewInt(0),
GasLimit: vmInput.GasProvided,
GasLocked: vmInput.GasLocked,
Data: []byte(setUserNameTxData),
CallType: vmcommon.AsynchronousCall,
}
vmOutput.OutputAccounts[string(vmInput.RecipientAddr)] = &vmcommon.OutputAccount{
Address: vmInput.RecipientAddr,
OutputTransfers: []vmcommon.OutputTransfer{outTransfer},
}
return vmOutput, nil
}
log.Trace("setUserName called in shard")
currentUserName := acntDst.GetUserName()
if !s.enableChange && len(currentUserName) > 0 {
return nil, process.ErrUserNameChangeIsDisabled
}
acntDst.SetUserName(vmInput.Arguments[0])
return &vmcommon.VMOutput{GasRemaining: vmInput.GasProvided - s.gasCost, ReturnCode: vmcommon.Ok}, nil
}
// IsInterfaceNil returns true if underlying object in nil
func (s *saveUserName) IsInterfaceNil() bool {
return s == nil
}