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  }