decred.org/dcrdex@v1.0.5/server/account/account.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package account 5 6 import ( 7 "database/sql/driver" 8 "encoding/hex" 9 "encoding/json" 10 "fmt" 11 "math" 12 13 "github.com/decred/dcrd/crypto/blake256" 14 "github.com/decred/dcrd/dcrec/secp256k1/v4" 15 ) 16 17 // PrivateKey is the private key type used by DEX. 18 type PrivateKey = secp256k1.PrivateKey 19 20 const ( 21 PrivKeySize = secp256k1.PrivKeyBytesLen 22 PubKeySize = secp256k1.PubKeyBytesLenCompressed 23 HashSize = blake256.Size 24 PrepaidBondID = math.MaxInt32 25 ) 26 27 // HashFunc is the hash function used to generate account IDs from pubkeys. 28 var HashFunc = blake256.Sum256 29 30 // AccountID is a DEX account identifier. 31 type AccountID [HashSize]byte 32 33 // NewID generates a unique account id with the provided public key bytes. 34 func NewID(pk []byte) AccountID { 35 // Hash the pubkey hash. 36 h := HashFunc(pk) 37 return HashFunc(h[:]) 38 } 39 40 // String returns a hexadecimal representation of the AccountID. String 41 // implements fmt.Stringer. 42 func (aid AccountID) String() string { 43 return hex.EncodeToString(aid[:]) 44 } 45 46 // MarshalJSON satisfies the json.Marshaller interface, and will marshal the 47 // id to a hex string. 48 func (aid AccountID) MarshalJSON() ([]byte, error) { 49 return json.Marshal(aid.String()) 50 } 51 52 // Value implements the sql/driver.Valuer interface. 53 func (aid AccountID) Value() (driver.Value, error) { 54 return aid[:], nil // []byte 55 } 56 57 // Scan implements the sql.Scanner interface. 58 func (aid *AccountID) Scan(src any) error { 59 switch src := src.(type) { 60 case []byte: 61 copy(aid[:], src) 62 return nil 63 //case string: 64 // case nil: 65 // *oid = nil 66 // return nil 67 } 68 69 return fmt.Errorf("cannot convert %T to AccountID", src) 70 } 71 72 // Account represents a dex client account. 73 type Account struct { 74 ID AccountID 75 PubKey *secp256k1.PublicKey 76 } 77 78 // NewAccountFromPubKey creates a dex client account from the provided public 79 // key bytes. 80 func NewAccountFromPubKey(pk []byte) (*Account, error) { 81 if len(pk) != PubKeySize { 82 return nil, fmt.Errorf("invalid pubkey length, "+ 83 "expected %d, got %d", PubKeySize, len(pk)) 84 } 85 86 pubKey, err := secp256k1.ParsePubKey(pk) 87 if err != nil { 88 return nil, err 89 } 90 91 return &Account{ 92 ID: NewID(pk), 93 PubKey: pubKey, 94 }, nil 95 } 96 97 // Rule represents a rule of community conduct. 98 type Rule uint8 99 100 const ( 101 // NoRule indicates that no rules have been broken. This may be an invalid 102 // value in some contexts. 103 NoRule Rule = iota 104 // PreimageReveal means an account failed to respond with a valid preimage 105 // for their order during epoch processing. 106 PreimageReveal 107 // FailureToAct means that an account has not followed through on one of their 108 // swap negotiation steps. 109 FailureToAct 110 // CancellationRate means the account's cancellation rate has dropped below 111 // the acceptable level. 112 CancellationRate 113 // LowFees means an account made a transaction that didn't pay fees at the 114 // requisite level. 115 LowFees 116 // MaxRule in not an actual rule. It is a placeholder that is used to 117 // determine the total number of rules. It must always be the last 118 // definition in this list. 119 MaxRule 120 ) 121 122 // details holds rule specific details. 123 type details struct { 124 name, description string 125 } 126 127 // ruleDetails maps rules to rule details. 128 var ruleDetails = map[Rule]details{ 129 NoRule: { 130 name: "NoRule", 131 description: "no rules have been broken", 132 }, 133 PreimageReveal: { 134 name: "PreimageReveal", 135 description: "failed to respond with a valid preimage for an order during epoch processing", 136 }, 137 FailureToAct: { 138 name: "FailureToAct", 139 description: "did not follow through on a swap negotiation step", 140 }, 141 CancellationRate: { 142 name: "CancellationRate", 143 description: "cancellation rate dropped below the acceptable level", 144 }, 145 LowFees: { 146 name: "LowFees", 147 description: "did not pay transaction mining fees at the requisite level", 148 }, 149 } 150 151 // String satisfies the Stringer interface. 152 func (r Rule) String() string { 153 if d, ok := ruleDetails[r]; ok { 154 return d.name 155 } 156 return "unknown rule" 157 } 158 159 // Description returns a description of the rule. 160 func (r Rule) Description() string { 161 if d, ok := ruleDetails[r]; ok { 162 return d.description 163 } 164 return "description not specified" 165 } 166 167 // Punishable returns whether breaking this rule incurs a penalty. 168 func (r Rule) Punishable() bool { 169 return r > NoRule && r < MaxRule 170 } 171 172 // Reputation is a part of a number of server-originating messages. It was 173 // introduced with the v2 ConnectResult. 174 type Reputation struct { 175 // BondedTier is the tier indicated by the user's active bonds. BondedTier 176 // does not account for penalties. 177 BondedTier int64 `json:"bondedTier"` 178 // Penalties are the number of tiers that are currently revoked due to low 179 // user score. 180 Penalties uint16 `json:"penalties"` 181 // Score is the user's current score. Score must be evaluated against a 182 // server's configured penalty threshold to calculate penalties. 183 Score int32 `json:"score"` 184 } 185 186 // Effective calculates the effective tier for trading limit calculations. 187 func (r *Reputation) EffectiveTier() int64 { 188 tier := r.BondedTier - int64(r.Penalties) 189 return tier 190 }