summaryrefslogtreecommitdiff
path: root/ledger/ledgercore/accountdata.go
blob: 69e2c543eb115237915d6e96aae4f64d278a50a5 (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// Copyright (C) 2019-2023 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand.  If not, see <https://www.gnu.org/licenses/>.

package ledgercore

import (
	"github.com/algorand/go-algorand/config"
	"github.com/algorand/go-algorand/crypto"
	"github.com/algorand/go-algorand/crypto/merklesignature"
	"github.com/algorand/go-algorand/data/basics"
)

// AccountData provides users of the Balances interface per-account data (like basics.AccountData)
// but without any maps containing AppParams, AppLocalState, AssetHolding, or AssetParams. This
// ensures that transaction evaluation must retrieve and mutate account, asset, and application data
// separately, to better support on-disk and in-memory schemas that do not store them together.
type AccountData struct {
	AccountBaseData
	VotingData
}

// AccountBaseData contains base account info like balance, status and total number of resources
type AccountBaseData struct {
	Status             basics.Status
	MicroAlgos         basics.MicroAlgos
	RewardsBase        uint64
	RewardedMicroAlgos basics.MicroAlgos
	AuthAddr           basics.Address

	TotalAppSchema      basics.StateSchema // Totals across created globals, and opted in locals.
	TotalExtraAppPages  uint32             // Total number of extra pages across all created apps
	TotalAppParams      uint64             // Total number of apps this account has created
	TotalAppLocalStates uint64             // Total number of apps this account is opted into.
	TotalAssetParams    uint64             // Total number of assets created by this account
	TotalAssets         uint64             // Total of asset creations and optins (i.e. number of holdings)
	TotalBoxes          uint64             // Total number of boxes associated to this account
	TotalBoxBytes       uint64             // Total bytes for this account's boxes. keys _and_ values count
}

// VotingData holds participation information
type VotingData struct {
	VoteID       crypto.OneTimeSignatureVerifier
	SelectionID  crypto.VRFVerifier
	StateProofID merklesignature.Commitment

	VoteFirstValid  basics.Round
	VoteLastValid   basics.Round
	VoteKeyDilution uint64
}

// OnlineAccountData holds MicroAlgosWithRewards and VotingData as needed for agreement
type OnlineAccountData struct {
	MicroAlgosWithRewards basics.MicroAlgos
	VotingData
}

// ToAccountData returns ledgercore.AccountData from basics.AccountData
func ToAccountData(acct basics.AccountData) AccountData {
	return AccountData{
		AccountBaseData: AccountBaseData{
			Status:             acct.Status,
			MicroAlgos:         acct.MicroAlgos,
			RewardsBase:        acct.RewardsBase,
			RewardedMicroAlgos: acct.RewardedMicroAlgos,

			AuthAddr: acct.AuthAddr,

			TotalAppSchema:      acct.TotalAppSchema,
			TotalExtraAppPages:  acct.TotalExtraAppPages,
			TotalAssetParams:    uint64(len(acct.AssetParams)),
			TotalAssets:         uint64(len(acct.Assets)),
			TotalAppParams:      uint64(len(acct.AppParams)),
			TotalAppLocalStates: uint64(len(acct.AppLocalStates)),
			TotalBoxes:          acct.TotalBoxes,
			TotalBoxBytes:       acct.TotalBoxBytes,
		},
		VotingData: VotingData{
			VoteID:          acct.VoteID,
			SelectionID:     acct.SelectionID,
			StateProofID:    acct.StateProofID,
			VoteFirstValid:  acct.VoteFirstValid,
			VoteLastValid:   acct.VoteLastValid,
			VoteKeyDilution: acct.VoteKeyDilution,
		},
	}
}

// AssignAccountData assigns the contents of AccountData to the fields in basics.AccountData,
// but does not touch the AppParams, AppLocalState, AssetHolding, or AssetParams data.
func AssignAccountData(a *basics.AccountData, acct AccountData) {
	a.Status = acct.Status
	a.MicroAlgos = acct.MicroAlgos
	a.RewardsBase = acct.RewardsBase
	a.RewardedMicroAlgos = acct.RewardedMicroAlgos

	a.VoteID = acct.VoteID
	a.SelectionID = acct.SelectionID
	a.StateProofID = acct.StateProofID
	a.VoteFirstValid = acct.VoteFirstValid
	a.VoteLastValid = acct.VoteLastValid
	a.VoteKeyDilution = acct.VoteKeyDilution

	a.AuthAddr = acct.AuthAddr
	a.TotalAppSchema = acct.TotalAppSchema
	a.TotalExtraAppPages = acct.TotalExtraAppPages
	a.TotalBoxes = acct.TotalBoxes
	a.TotalBoxBytes = acct.TotalBoxBytes
}

// WithUpdatedRewards calls basics account data WithUpdatedRewards
func (u AccountData) WithUpdatedRewards(proto config.ConsensusParams, rewardsLevel uint64) AccountData {
	u.MicroAlgos, u.RewardedMicroAlgos, u.RewardsBase = basics.WithUpdatedRewards(
		proto, u.Status, u.MicroAlgos, u.RewardedMicroAlgos, u.RewardsBase, rewardsLevel,
	)
	return u
}

// ClearOnlineState resets the account's fields to indicate that the account is an offline account
func (u *AccountData) ClearOnlineState() {
	u.Status = basics.Offline
	u.VotingData = VotingData{}
}

// MinBalance computes the minimum balance requirements for an account based on
// some consensus parameters. MinBalance should correspond roughly to how much
// storage the account is allowed to store on disk.
func (u AccountData) MinBalance(proto *config.ConsensusParams) (res basics.MicroAlgos) {
	return basics.MinBalance(
		proto,
		uint64(u.TotalAssets),
		u.TotalAppSchema,
		uint64(u.TotalAppParams), uint64(u.TotalAppLocalStates),
		uint64(u.TotalExtraAppPages),
		u.TotalBoxes, u.TotalBoxBytes,
	)
}

// IsZero checks if an AccountData value is the same as its zero value.
func (u AccountData) IsZero() bool {
	return u == AccountData{}
}

// Money is similar to basics account data Money function
func (u AccountData) Money(proto config.ConsensusParams, rewardsLevel uint64) (money basics.MicroAlgos, rewards basics.MicroAlgos) {
	e := u.WithUpdatedRewards(proto, rewardsLevel)
	return e.MicroAlgos, e.RewardedMicroAlgos
}

// OnlineAccountData calculates the online account data given an AccountData, by adding the rewards.
func (u AccountData) OnlineAccountData(proto config.ConsensusParams, rewardsLevel uint64) OnlineAccountData {
	if u.Status != basics.Online {
		// if the account is not Online and agreement requests it for some reason, clear it out
		return OnlineAccountData{}
	}

	microAlgos, _, _ := basics.WithUpdatedRewards(
		proto, u.Status, u.MicroAlgos, u.RewardedMicroAlgos, u.RewardsBase, rewardsLevel,
	)
	return OnlineAccountData{
		MicroAlgosWithRewards: microAlgos,
		VotingData: VotingData{
			VoteID:          u.VoteID,
			SelectionID:     u.SelectionID,
			StateProofID:    u.StateProofID,
			VoteFirstValid:  u.VoteFirstValid,
			VoteLastValid:   u.VoteLastValid,
			VoteKeyDilution: u.VoteKeyDilution,
		},
	}
}

// NormalizedOnlineBalance wraps basics.NormalizedOnlineAccountBalance
func (u *AccountData) NormalizedOnlineBalance(genesisProto config.ConsensusParams) uint64 {
	return basics.NormalizedOnlineAccountBalance(u.Status, u.RewardsBase, u.MicroAlgos, genesisProto)
}