github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/core/vm/ota_storage.go (about) 1 // Copyright 2018 Wanchain Foundation Ltd 2 3 package vm 4 5 import ( 6 "bytes" 7 "errors" 8 "fmt" 9 "math/big" 10 "math/rand" 11 12 "strconv" 13 14 "github.com/wanchain/go-wanchain/common" 15 "github.com/wanchain/go-wanchain/crypto" 16 "github.com/wanchain/go-wanchain/log" 17 18 ) 19 20 var ( 21 ErrUnknown = errors.New("unknown error") 22 ErrInvalidOTAAddr = errors.New("invalid OTA addrss") 23 ErrInvalidOTAAX = errors.New("invalid OTA AX") 24 ErrOTAExistAlready = errors.New("OTA exist already") 25 ErrOTABalanceIsZero = errors.New("OTA balance is 0") 26 ) 27 28 // OTABalance2ContractAddr convert ota balance to ota storage address 29 // 30 // 1 wancoin --> (bigint)1000000000000000000 --> "0x0000000000000000000001000000000000000000" 31 // 32 func OTABalance2ContractAddr(balance *big.Int) common.Address { 33 if balance == nil { 34 return common.Address{} 35 } 36 37 return common.HexToAddress(balance.String()) 38 // return common.BigToAddress(balance) 39 } 40 41 // GetAXFromWanAddr retrieve ota AX from ota WanAddr 42 func GetAXFromWanAddr(otaWanAddr []byte) ([]byte, error) { 43 if len(otaWanAddr) != common.WAddressLength { 44 return nil, ErrInvalidOTAAddr 45 } 46 47 return otaWanAddr[1 : 1+common.HashLength], nil 48 } 49 50 // IsAXPointToWanAddr check whether AX point to otaWanAddr or not 51 func IsAXPointToWanAddr(AX []byte, otaWanAddr []byte) bool { 52 findAX, err := GetAXFromWanAddr(otaWanAddr) 53 if err != nil { 54 return false 55 } 56 57 return bytes.Equal(findAX, AX) 58 } 59 60 // GetOtaBalanceFromAX retrieve ota balance from ota AX 61 func GetOtaBalanceFromAX(statedb StateDB, otaAX []byte) (*big.Int, error) { 62 if statedb == nil { 63 return nil, ErrUnknown 64 } 65 66 if len(otaAX) != common.HashLength { 67 return nil, ErrInvalidOTAAX 68 } 69 70 balance := statedb.GetStateByteArray(otaBalanceStorageAddr, common.BytesToHash(otaAX)) 71 if len(balance) == 0 { 72 return common.Big0, nil 73 } 74 75 return new(big.Int).SetBytes(balance), nil 76 } 77 78 // SetOtaBalanceToAX set ota balance as 'balance'. Overwrite if ota balance exist already. 79 func SetOtaBalanceToAX(statedb StateDB, otaAX []byte, balance *big.Int) error { 80 if statedb == nil || balance == nil { 81 return ErrUnknown 82 } 83 84 if len(otaAX) != common.HashLength { 85 return ErrInvalidOTAAX 86 } 87 88 statedb.SetStateByteArray(otaBalanceStorageAddr, common.BytesToHash(otaAX), balance.Bytes()) 89 return nil 90 } 91 92 // ChechOTAExist checks the OTA exist or not. 93 // 94 // In order to avoid additional ota have conflict with existing, 95 // even if AX exist in balance storage already, will return true. 96 func CheckOTAAXExist(statedb StateDB, otaAX []byte) (exist bool, balance *big.Int, err error) { 97 if statedb == nil { 98 return false, nil, ErrUnknown 99 } 100 101 if len(otaAX) != common.HashLength { 102 return false, nil, ErrInvalidOTAAX 103 } 104 105 balance, err = GetOtaBalanceFromAX(statedb, otaAX[:common.HashLength]) 106 if err != nil { 107 return false, nil, err 108 } 109 110 if balance.Cmp(common.Big0) == 0 { 111 return false, nil, nil 112 } 113 114 return true, balance, nil 115 } 116 117 func CheckOTALongAddrExist(statedb StateDB, otaLongAddr []byte) (exist bool, balance *big.Int, err error) { 118 if statedb == nil { 119 return false, nil, ErrUnknown 120 } 121 122 if len(otaLongAddr) != 33 { 123 return false, nil, ErrInvalidOTAAX 124 } 125 126 otaAX := otaLongAddr[1 : 1+common.HashLength] 127 if err != nil { 128 return false, nil, err 129 } 130 131 balance, err = GetOtaBalanceFromAX(statedb, otaAX) 132 if err != nil { 133 return false, nil, err 134 } 135 136 if balance.Cmp(common.Big0) == 0 { 137 return false, nil, nil 138 } 139 140 mptAddr := OTABalance2ContractAddr(balance) 141 otaStored := statedb.GetStateByteArray(mptAddr, common.BytesToHash(otaAX)) 142 143 fmt.Println(common.ToHex(mptAddr.Bytes())) 144 fmt.Println(common.ToHex(otaLongAddr)) 145 146 if otaStored == nil { 147 return false, nil, nil 148 } 149 150 if !bytes.Equal(otaLongAddr, otaStored[:33]) { 151 return false, nil, nil 152 } 153 154 return true, balance, nil 155 } 156 157 158 159 func BatCheckOTAExist(statedb StateDB, otaLongAddrs [][]byte) (exist bool, balance *big.Int, unexistOta []byte, err error) { 160 if statedb == nil || len(otaLongAddrs) == 0 { 161 return false, nil, nil, ErrUnknown 162 } 163 164 for _, otaLongAddr := range otaLongAddrs { 165 if len(otaLongAddr) != 33 { 166 return false, nil, otaLongAddr, ErrInvalidOTAAX 167 } 168 169 exist, balanceTmp, err := CheckOTALongAddrExist(statedb, otaLongAddr) 170 if err != nil { 171 return false, nil, otaLongAddr, err 172 } else if !exist { 173 return false, nil, otaLongAddr, errors.New("ota doesn't exist:" + common.ToHex(otaLongAddr)) 174 } else if balanceTmp.Cmp(common.Big0) == 0 { 175 return false, nil, otaLongAddr, errors.New("ota balance is 0! ota:" + common.ToHex(otaLongAddr)) 176 } else if balance == nil { 177 balance = balanceTmp 178 continue 179 } else if balance.Cmp(balanceTmp) != 0 { 180 return false, nil, otaLongAddr, errors.New("otas have different balances! ota:" + common.ToHex(otaLongAddr)) 181 } 182 } 183 184 return true, balance, nil, nil 185 } 186 187 188 func GetUnspendOTATotalBalance(statedb StateDB) (*big.Int, error) { 189 if statedb == nil { 190 return nil, ErrUnknown 191 } 192 193 totalOTABalance, totalSpendedOTABalance := big.NewInt(0), big.NewInt(0) 194 195 // total history OTA balance (include spended) 196 statedb.ForEachStorageByteArray(otaBalanceStorageAddr, func(key common.Hash, value []byte) bool { 197 if len(value) == 0 { 198 log.Warn("total ota balance. value is empoty!", "key", key.String()) 199 return true 200 } 201 202 balance := new(big.Int).SetBytes(value) 203 totalOTABalance.Add(totalOTABalance, balance) 204 log.Debug("total ota balance.", "key", key.String(), "balance:", balance.String()) 205 return true 206 }) 207 208 // total spended OTA balance 209 statedb.ForEachStorageByteArray(otaImageStorageAddr, func(key common.Hash, value []byte) bool { 210 if len(value) == 0 { 211 log.Warn("total spended ota balance. value is empoty!", "key", key.String()) 212 return true 213 } 214 215 balance := new(big.Int).SetBytes(value) 216 totalSpendedOTABalance.Add(totalSpendedOTABalance, balance) 217 log.Debug("total spended ota balance.", "key", key.String(), "balance:", balance.String()) 218 return true 219 }) 220 221 log.Debug("total unspended OTA balance", "total history OTA balance:", totalOTABalance.String(), "total spended OTA balance:", totalSpendedOTABalance.String()) 222 223 return totalOTABalance.Sub(totalOTABalance, totalSpendedOTABalance), nil 224 } 225 226 // setOTA storage ota info, include balance and WanAddr. Overwrite if ota exist already. 227 func setOTA(statedb StateDB, balance *big.Int, otaWanAddr []byte) error { 228 if statedb == nil || balance == nil { 229 return ErrUnknown 230 } 231 if len(otaWanAddr) != common.WAddressLength { 232 return ErrInvalidOTAAddr 233 } 234 235 otaAX, _ := GetAXFromWanAddr(otaWanAddr) 236 //balanceOld, err := GetOtaBalanceFromAX(statedb, otaAX) 237 //if err != nil { 238 // return err 239 //} 240 // 241 //if balanceOld != nil && balanceOld.Cmp(common.Big0) != 0 { 242 // return errors.New("ota balance is not 0! old balance:" + balanceOld.String()) 243 //} 244 245 mptAddr := OTABalance2ContractAddr(balance) 246 statedb.SetStateByteArray(mptAddr, common.BytesToHash(otaAX), otaWanAddr) 247 return SetOtaBalanceToAX(statedb, otaAX, balance) 248 } 249 250 // AddOTAIfNotExist storage ota info if doesn't exist already. 251 func AddOTAIfNotExist(statedb StateDB, balance *big.Int, otaWanAddr []byte) (bool, error) { 252 if statedb == nil || balance == nil { 253 return false, ErrUnknown 254 } 255 if len(otaWanAddr) != common.WAddressLength { 256 return false, ErrInvalidOTAAddr 257 } 258 259 otaAX, _ := GetAXFromWanAddr(otaWanAddr) 260 otaAddrKey := common.BytesToHash(otaAX) 261 exist, _, err := CheckOTAAXExist(statedb, otaAddrKey[:]) 262 if err != nil { 263 return false, err 264 } 265 266 if exist { 267 return false, ErrOTAExistAlready 268 } 269 270 err = setOTA(statedb, balance, otaWanAddr) 271 if err != nil { 272 return false, err 273 } 274 275 return true, nil 276 } 277 278 // GetOTAInfoFromAX retrieve ota info, include balance and WanAddr 279 func GetOTAInfoFromAX(statedb StateDB, otaAX []byte) (otaWanAddr []byte, balance *big.Int, err error) { 280 if statedb == nil { 281 return nil, nil, ErrUnknown 282 } 283 if len(otaAX) < common.HashLength { 284 return nil, nil, ErrInvalidOTAAX 285 } 286 287 otaAddrKey := common.BytesToHash(otaAX) 288 balance, err = GetOtaBalanceFromAX(statedb, otaAddrKey[:]) 289 if err != nil { 290 return nil, nil, err 291 } 292 293 if balance == nil || balance.Cmp(common.Big0) == 0 { 294 return nil, nil, ErrOTABalanceIsZero 295 } 296 297 mptAddr := OTABalance2ContractAddr(balance) 298 299 otaValue := statedb.GetStateByteArray(mptAddr, otaAddrKey) 300 if otaValue != nil && len(otaValue) != 0 { 301 return otaValue, balance, nil 302 } 303 304 return nil, balance, nil 305 } 306 307 type GetOTASetEnv struct { 308 otaAX []byte 309 setNum int 310 getNum int 311 loopTimes int 312 rnd int 313 otaWanAddrSet [][]byte 314 } 315 316 func (env *GetOTASetEnv) OTAInSet(ota []byte) bool { 317 for _, exist := range env.otaWanAddrSet { 318 if bytes.Equal(exist, ota) { 319 return true 320 } 321 } 322 323 return false 324 } 325 326 func (env *GetOTASetEnv) UpdateRnd() { 327 env.rnd = rand.Intn(100) + 1 328 } 329 330 func (env *GetOTASetEnv) IsSetFull() bool { 331 return env.getNum >= env.setNum 332 } 333 334 func (env *GetOTASetEnv) RandomSelOTA(value []byte) bool { 335 env.loopTimes++ 336 if env.loopTimes%env.rnd == 0 { 337 env.otaWanAddrSet = append(env.otaWanAddrSet, value) 338 env.getNum++ 339 env.UpdateRnd() 340 return true 341 } else { 342 return false 343 } 344 } 345 346 // doOTAStorageTravelCallBack implement ota mpt travel call back 347 func doOTAStorageTravelCallBack(env *GetOTASetEnv, value []byte) (bool, error) { 348 // find self, return true to continue travel loop 349 if IsAXPointToWanAddr(env.otaAX, value) { 350 return true, nil 351 } 352 353 // ota contained in set already, return true to continue travel loop 354 if env.OTAInSet(value) { 355 return true, nil 356 } 357 358 // random select 359 // if set full already, return false to stop travel loop 360 if bGet := env.RandomSelOTA(value); bGet { 361 return !env.IsSetFull(), nil 362 } else { 363 return true, nil 364 } 365 } 366 367 // GetOTASet retrieve the setNum of same balance OTA address of the input OTA setting by otaAX, and ota balance. 368 // Rules: 369 // 1: The result can't contain otaAX self; 370 // 2: The result can't contain duplicate items; 371 // 3: No ota exist in the mpt, return error; 372 // 4: OTA total count in the mpt less or equal to the setNum, return error(returned set must 373 // can't contain otaAX self, so need more exist ota in mpt); 374 // 5: If find invalid ota wanaddr, return error; 375 // 6: Travel the ota mpt.Record loop exist ota cumulative times as loopTimes. 376 // Generate a random number as rnd. 377 // If loopTimes%rnd == 0, collect current exist ota to result set and update the rnd. 378 // Loop checking exist ota and loop traveling ota mpt, untile collect enough ota or find error. 379 // 380 func GetOTASet(statedb StateDB, otaAX []byte, setNum int) (otaWanAddrs [][]byte, balance *big.Int, err error) { 381 if statedb == nil { 382 return nil, nil, ErrUnknown 383 } 384 if len(otaAX) != common.HashLength { 385 return nil, nil, ErrInvalidOTAAX 386 } 387 388 balance, err = GetOtaBalanceFromAX(statedb, otaAX) 389 if err != nil { 390 return nil, nil, err 391 } else if balance == nil || balance.Cmp(common.Big0) == 0 { 392 return nil, nil, errors.New("can't find ota address balance!") 393 } 394 395 mptAddr := OTABalance2ContractAddr(balance) 396 log.Debug("GetOTASet", "mptAddr", common.ToHex(mptAddr[:])) 397 398 env := GetOTASetEnv{otaAX, setNum, 0, 0, 0, nil} 399 env.otaWanAddrSet = make([][]byte, 0, setNum) 400 env.UpdateRnd() 401 402 mptEleCount := 0 // total number of ota containing in mpt 403 404 for { 405 statedb.ForEachStorageByteArray(mptAddr, func(key common.Hash, value []byte) bool { 406 mptEleCount++ 407 408 if len(value) != common.WAddressLength { 409 log.Error("invalid OTA address!", "balance", balance, "value", value) 410 err = errors.New(fmt.Sprint("invalid OTA address! balance:", balance, ", ota:", value)) 411 return false 412 } 413 414 bContinue, err := doOTAStorageTravelCallBack(&env, value) 415 if err != nil { 416 return false 417 } else { 418 return bContinue 419 } 420 }) 421 422 if env.IsSetFull() { 423 return env.otaWanAddrSet, balance, nil 424 } else if err != nil { 425 return nil, nil, err 426 } else if mptEleCount == 0 { 427 return nil, balance, errors.New("no ota exist! balance:" + balance.String()) 428 } else if setNum >= mptEleCount { 429 return nil, balance, errors.New("too more required ota number! balance:" + balance.String() + 430 ", exist count:" + strconv.Itoa(mptEleCount)) 431 } else { 432 continue 433 } 434 } 435 } 436 437 // CheckOTAImageExist checks ota image key exist already or not 438 func CheckOTAImageExist(statedb StateDB, otaImage []byte) (bool, []byte, error) { 439 if statedb == nil || len(otaImage) == 0 { 440 return false, nil, errors.New("invalid input param!") 441 } 442 443 otaImageKey := crypto.Keccak256Hash(otaImage) 444 otaImageValue := statedb.GetStateByteArray(otaImageStorageAddr, otaImageKey) 445 if otaImageValue != nil && len(otaImageValue) != 0 { 446 return true, otaImageValue, nil 447 } 448 449 return false, nil, nil 450 } 451 452 // AddOTAImage storage ota image key. Overwrite if exist already. 453 func AddOTAImage(statedb StateDB, otaImage []byte, value []byte) error { 454 if statedb == nil || len(otaImage) == 0 || len(value) == 0 { 455 return errors.New("invalid input param!") 456 } 457 458 otaImageKey := crypto.Keccak256Hash(otaImage) 459 statedb.SetStateByteArray(otaImageStorageAddr, otaImageKey, value) 460 return nil 461 }