github.com/cranelv/ethereum_mpc@v0.0.0-20191031014521-23aeb1415092/core/vm/Deposit.go (about)

     1  package vm
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"strings"
     7  	"github.com/ethereum/go-ethereum/common"
     8  	"github.com/ethereum/go-ethereum/common/math"
     9  	"github.com/ethereum/go-ethereum/p2p/discover"
    10  	"github.com/ethereum/go-ethereum/params"
    11  	"github.com/ethereum/go-ethereum/accounts/abi"
    12  	"math/big"
    13  )
    14  var (
    15  	man				= new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)
    16  	minerThreshold	= new(big.Int).Mul(big.NewInt(10),man)
    17  	validatorThreshold	= new(big.Int).Mul(big.NewInt(10000),man)
    18  	withdrawState   = big.NewInt(1)
    19  	errParameters   = errors.New("error parameters")
    20  	errMethodId     = errors.New("error method id")
    21  	errDeposit      = errors.New("Deposit is not found")
    22  	errWithdraw     = errors.New("withdraw is not set")
    23  	errOverflow     = errors.New("Deposit is overflow")
    24  	errDepositEmpty = errors.New("DepositList is Empty")
    25  
    26  	depositDef = ` [{"constant": true,"inputs": [],"name": "getDepositList","outputs": [{"name": "","type": "address[]"}],"payable": false,"stateMutability": "view","type": "function"},
    27      		{"constant": true,"inputs": [{"name": "addr","type": "address"}],"name": "getDepositInfo","outputs": [{"name": "","type": "uint256"},{"name": "","type": "bytes"},{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},
    28      		{"constant": false,"inputs": [{"name": "nodeID","type": "bytes"}],"name": "valiDeposit","outputs": [],"payable": true,"stateMutability": "payable","type": "function"},
    29      		{"constant": false,"inputs": [{"name": "nodeID","type": "bytes"}],"name": "minerDeposit","outputs": [],"payable": true,"stateMutability": "payable","type": "function"},
    30      		{"constant": false,"inputs": [],"name": "withdraw","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"},
    31      		{"constant": false,"inputs": [],"name": "refund","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"}]`
    32  
    33  	depositAbi,Abierr = abi.JSON(strings.NewReader(depositDef))
    34  	valiDepositArr,minerDepositIdArr, withdrawIdArr, refundIdArr,getDepositListArr,getDepositInfoArr [4]byte
    35  	emptyHash                                = common.Hash{}
    36  )
    37  func init() {
    38  	if Abierr != nil {
    39  		panic("err in deposit sc initialize")
    40  	}
    41  
    42  	copy(valiDepositArr[:], depositAbi.Methods["valiDeposit"].Id())
    43  	copy(minerDepositIdArr[:], depositAbi.Methods["minerDeposit"].Id())
    44  	copy(withdrawIdArr[:], depositAbi.Methods["withdraw"].Id())
    45  	copy(refundIdArr[:], depositAbi.Methods["refund"].Id())
    46  	copy(getDepositListArr[:], depositAbi.Methods["getDepositList"].Id())
    47  	copy(getDepositInfoArr[:], depositAbi.Methods["getDepositInfo"].Id())
    48  }
    49  
    50  
    51  type MatrixDeposit struct {
    52  }
    53  
    54  func (md *MatrixDeposit) RequiredGas(input []byte) uint64 {
    55  	if len(input) < 4 {
    56  		return 0
    57  	}
    58  
    59  	return params.SstoreSetGas * 2
    60  }
    61  
    62  func (md *MatrixDeposit) Run(in []byte, contract *Contract, evm *EVM) ([]byte, error) {
    63  	if len(in) < 4 {
    64  		return nil, errParameters
    65  	}
    66  
    67  	var methodIdArr [4]byte
    68  	copy(methodIdArr[:], in[:4])
    69  
    70  	if methodIdArr == valiDepositArr {
    71  		return md.valiDeposit(in[4:], contract, evm)
    72  	}else if methodIdArr == minerDepositIdArr {
    73  		return md.minerDeposit(in[4:], contract, evm)
    74  	} else if methodIdArr == withdrawIdArr {
    75  		return md.withdraw(in[4:], contract, evm)
    76  	} else if methodIdArr == refundIdArr {
    77  		return md.refund(in[4:], contract, evm)
    78  	}else if methodIdArr == getDepositListArr {
    79  		return md.getDepositList(in[4:], contract, evm)
    80  	}else if methodIdArr == getDepositInfoArr {
    81  		return md.getDepositInfo(in[4:], contract, evm)
    82  	}
    83  
    84  	return nil, errParameters
    85  }
    86  func (md *MatrixDeposit) valiDeposit(in []byte, contract *Contract, evm *EVM) ([]byte, error) {
    87  	return md.deposit(in,contract,evm,validatorThreshold)
    88  }
    89  //deposit(uint nodeID-x, uint nodeID-y)
    90  func (md *MatrixDeposit) minerDeposit(in []byte, contract *Contract, evm *EVM) ([]byte, error) {
    91  	return md.deposit(in,contract,evm,minerThreshold)
    92  }
    93  func (md *MatrixDeposit) deposit(in []byte, contract *Contract, evm *EVM,threshold *big.Int) ([]byte, error) {
    94  	if len(in) < 4 {
    95  		return nil, errParameters
    96  	}
    97  	var nodeID []byte
    98  	err := depositAbi.Methods["deposit"].Inputs.Unpack(&nodeID,in)
    99  
   100  	if err != nil || len(nodeID)!=64 {
   101  		return nil, errDeposit
   102  	}
   103  	deposit := md.getDeposit(contract, evm.StateDB,contract.CallerAddress)
   104  	if deposit == nil{
   105  		deposit = big.NewInt(0)
   106  	}
   107  	deposit.Add(deposit,contract.value)
   108  	if deposit.Cmp(threshold)<0 {
   109  		return nil,errDeposit
   110  	}
   111  	addrSrc := contract.CallerAddress
   112  	if(contract.value.Sign()>0){
   113  		if !evm.CanTransfer(evm.StateDB, addrSrc, contract.value) {
   114  			return nil, ErrInsufficientBalance
   115  		}
   116  		evm.Transfer(evm.StateDB, contract.CallerAddress, contract.Address(), contract.value)
   117  	}
   118  	var discoverId discover.NodeID
   119  	copy(discoverId[:],nodeID)
   120  	md.modifyDepositState(contract, evm, discoverId)
   121  	/*
   122  	evm.StateDB.AddLog(&types.Log{
   123  		Address: contract.Address(),
   124  		Topics:  topics,
   125  		Data:    d,
   126  		// This is a non-consensus field, but assigned here because
   127  		// core/state doesn't know the current block number.
   128  		BlockNumber: evm.BlockNumber.Uint64(),
   129  	})
   130  	*/
   131  	return []byte{1}, nil
   132  }
   133  func (md *MatrixDeposit) withdraw(in []byte, contract *Contract, evm *EVM) ([]byte, error) {
   134  	err := md.modifyWithdrawState(contract, evm)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	return []byte{1}, nil
   140  }
   141  func (md *MatrixDeposit) refund(in []byte, contract *Contract, evm *EVM) ([]byte, error) {
   142  	value, err := md.modifyRefundState(contract, evm)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	if !evm.CanTransfer(evm.StateDB, contract.Address(), value) {
   147  		return nil, ErrInsufficientBalance
   148  	}
   149  	evm.Transfer(evm.StateDB, contract.Address(), contract.CallerAddress, value)
   150  	return []byte{1}, nil
   151  }
   152  
   153  func (md *MatrixDeposit) getOnlineTime(contract *Contract, stateDB StateDB,addr common.Address) *big.Int {
   154  	onlineKey := append(addr[:], 'O', 'T')
   155  	info := stateDB.GetState(contract.Address(), common.BytesToHash(onlineKey))
   156  	if info != emptyHash {
   157  		return info.Big()
   158  	}
   159  	return nil
   160  }
   161  func (md *MatrixDeposit) addOnlineTime(contract *Contract, stateDB StateDB, tm *big.Int) error {
   162  	onlineKey := append(contract.CallerAddress[:], 'O', 'T')
   163  	info := stateDB.GetState(contract.Address(), common.BytesToHash(onlineKey))
   164  	dep := info.Big()
   165  	dep.Add(dep, tm)
   166  	if len(dep.Bytes()) > 32 {
   167  		return errOverflow
   168  	}
   169  	stateDB.SetState(contract.Address(), common.BytesToHash(onlineKey), common.BigToHash(dep))
   170  	return nil
   171  }
   172  func (md *MatrixDeposit) setOnlineTime(contract *Contract, stateDB StateDB, tm *big.Int) error {
   173  	onlineKey := append(contract.CallerAddress[:], 'O', 'T')
   174  	stateDB.SetState(contract.Address(), common.BytesToHash(onlineKey), common.BigToHash(tm))
   175  	return nil
   176  }
   177  func (md *MatrixDeposit) getDeposit(contract *Contract, stateDB StateDB,addr common.Address) *big.Int {
   178  	depositKey := append(addr[:], 'D')
   179  	info := stateDB.GetState(contract.Address(), common.BytesToHash(depositKey))
   180  	if info != emptyHash {
   181  		return info.Big()
   182  	}
   183  	return big.NewInt(0)
   184  }
   185  func (md *MatrixDeposit) addDeposit(contract *Contract, stateDB StateDB) error {
   186  	depositKey := append(contract.CallerAddress[:], 'D')
   187  	info := stateDB.GetState(contract.Address(), common.BytesToHash(depositKey))
   188  	dep := info.Big()
   189  	dep.Add(dep, contract.value)
   190  	if len(dep.Bytes()) > 32 {
   191  		return errOverflow
   192  	}
   193  	stateDB.SetState(contract.Address(), common.BytesToHash(depositKey), common.BigToHash(dep))
   194  	return nil
   195  }
   196  func (md *MatrixDeposit) setDeposit(contract *Contract, stateDB StateDB, dep *big.Int) error {
   197  	depositKey := append(contract.CallerAddress[:], 'D')
   198  	stateDB.SetState(contract.Address(), common.BytesToHash(depositKey), common.BigToHash(dep))
   199  	return nil
   200  }
   201  func (md *MatrixDeposit) getNodeID(contract *Contract, stateDB StateDB,addr common.Address) *discover.NodeID {
   202  	nodeXKey := append(addr[:], 'N', 'X')
   203  	nodeX := stateDB.GetState(contract.Address(), common.BytesToHash(nodeXKey))
   204  	if nodeX == emptyHash {
   205  		return &discover.NodeID{}
   206  	}
   207  	nodeYKey := append(addr[:], 'N', 'Y')
   208  	nodeY := stateDB.GetState(contract.Address(), common.BytesToHash(nodeYKey))
   209  	if nodeY == emptyHash {
   210  		return &discover.NodeID{}
   211  	}
   212  	var nodeID discover.NodeID
   213  	copy(nodeID[:32], nodeX[:])
   214  	copy(nodeID[32:], nodeY[:])
   215  	return &nodeID
   216  }
   217  func (md *MatrixDeposit) setNodeID(contract *Contract, stateDB StateDB, nodeID discover.NodeID) error {
   218  	if (nodeID == discover.NodeID{}) {
   219  		return nil
   220  	}
   221  	nodeXKey := append(contract.CallerAddress[:], 'N', 'X')
   222  	stateDB.SetState(contract.Address(), common.BytesToHash(nodeXKey), common.BytesToHash(nodeID[:32]))
   223  	nodeYKey := append(contract.CallerAddress[:], 'N', 'Y')
   224  	stateDB.SetState(contract.Address(), common.BytesToHash(nodeYKey), common.BytesToHash(nodeID[32:]))
   225  	return nil
   226  }
   227  func (md *MatrixDeposit) getWithdrawHeight(contract *Contract, stateDB StateDB,addr common.Address) *big.Int {
   228  	nodeXKey := append(addr[:], 'W', 'H')
   229  	withdraw := stateDB.GetState(contract.Address(), common.BytesToHash(nodeXKey))
   230  	if withdraw == emptyHash {
   231  		return big.NewInt(0)
   232  	}
   233  	return withdraw.Big()
   234  }
   235  func (md *MatrixDeposit) setWithdrawHeight(contract *Contract, stateDB StateDB, height *big.Int) error {
   236  	withdrawKey := append(contract.CallerAddress[:], 'W', 'H')
   237  	stateDB.SetState(contract.Address(), common.BytesToHash(withdrawKey), common.BigToHash(height))
   238  	return nil
   239  }
   240  type DepositDetail struct {
   241  	Address common.Address
   242  	NodeID discover.NodeID
   243  	Deposit *big.Int
   244  	WithdrawH *big.Int
   245  	OnlineTime *big.Int
   246  }
   247  func (md *MatrixDeposit) getValidatorDepositList(in []byte,contract *Contract, stateDB StateDB)  []DepositDetail {
   248  	var detailList []DepositDetail
   249  	contractAddr := contract.Address()
   250  	numKey := append(contractAddr[:], 'D', 'N', 'U', 'M')
   251  	numHash := stateDB.GetState(contract.Address(), common.BytesToHash(numKey))
   252  	num := numHash.Big()
   253  	if num.Sign() != 0 {
   254  		count := num.Uint64()
   255  		for i := uint64(0); i < count; i++ {
   256  			addr := md.getDepositListItem(contract, stateDB, i)
   257  			detail,err := md.getDepositDetail(addr,contract,stateDB)
   258  			if err != nil && detail.WithdrawH.Sign() == 0 && detail.Deposit.Cmp(validatorThreshold)>=0 {
   259  				detailList = append(detailList,*detail)
   260  			}
   261  		}
   262  	}
   263  	return detailList
   264  }
   265  func (md *MatrixDeposit) getMinerDepositList(in []byte,contract *Contract, stateDB StateDB)  []DepositDetail {
   266  	var detailList []DepositDetail
   267  	contractAddr := contract.Address()
   268  	numKey := append(contractAddr[:], 'D', 'N', 'U', 'M')
   269  	numHash := stateDB.GetState(contract.Address(), common.BytesToHash(numKey))
   270  	num := numHash.Big()
   271  	if num.Sign() != 0 {
   272  		count := num.Uint64()
   273  		for i := uint64(0); i < count; i++ {
   274  			addr := md.getDepositListItem(contract, stateDB, i)
   275  			detail,err := md.getDepositDetail(addr,contract,stateDB)
   276  			if err != nil && detail.WithdrawH.Sign() == 0 && detail.Deposit.Cmp(validatorThreshold)<0 {
   277  				detailList = append(detailList,*detail)
   278  			}
   279  		}
   280  	}
   281  	return detailList
   282  }
   283  func (md *MatrixDeposit) getDepositDetail(addr common.Address,contract *Contract, stateDB StateDB)  (*DepositDetail, error) {
   284  	detail := DepositDetail{Address : addr}
   285  	detail.Deposit = md.getDeposit(contract, stateDB,addr)
   286  	if detail.Deposit == nil || detail.Deposit.Sign() == 0 {
   287  		return nil, errDepositEmpty
   288  	}
   289  	detail.NodeID = *(md.getNodeID(contract, stateDB,addr))
   290  	detail.WithdrawH = md.getWithdrawHeight(contract, stateDB,addr)
   291  	detail.OnlineTime = md.getOnlineTime(contract, stateDB,addr)
   292  	return &detail,nil
   293  }
   294  
   295  func (md *MatrixDeposit) getDepositList(in []byte,contract *Contract, evm *EVM)  ([]byte, error) {
   296  	var addrList []common.Address
   297  	contractAddr := contract.Address()
   298  	numKey := append(contractAddr[:], 'D', 'N', 'U', 'M')
   299  	numHash := evm.StateDB.GetState(contract.Address(), common.BytesToHash(numKey))
   300  	num := numHash.Big()
   301  	if num.Sign() != 0 {
   302  		count := num.Uint64()
   303  		addrList = make([]common.Address, count)
   304  		for i := uint64(0); i < count; i++ {
   305  			addrList[i] = md.getDepositListItem(contract, evm.StateDB, i)
   306  		}
   307  	}
   308  	return depositAbi.Methods["getDepositList"].Outputs.Pack(addrList)
   309  }
   310  
   311  func (md *MatrixDeposit) getDepositListNum(contract *Contract, stateDB StateDB) *big.Int {
   312  	contractAddr := contract.Address()
   313  	numKey := append(contractAddr[:], 'D', 'N', 'U', 'M')
   314  	num := stateDB.GetState(contract.Address(), common.BytesToHash(numKey))
   315  	if num == emptyHash {
   316  		return nil
   317  	}
   318  	return num.Big()
   319  }
   320  func (md *MatrixDeposit) setDepositListNum(contract *Contract, stateDB StateDB, num *big.Int) {
   321  	contractAddr := contract.Address()
   322  	numKey := append(contractAddr[:], 'D', 'N', 'U', 'M')
   323  	stateDB.SetState(contract.Address(), common.BytesToHash(numKey), common.BigToHash(num))
   324  }
   325  func (md *MatrixDeposit) getDepositListItem(contract *Contract, stateDB StateDB, index uint64) common.Address {
   326  	contractAddr := contract.Address()
   327  	key := make([]byte, 8)
   328  	binary.BigEndian.PutUint64(key, index)
   329  	depKey := append(contractAddr[:], 'D', 'I')
   330  	depKey = append(depKey, key...)
   331  	addrHash := stateDB.GetState(contract.Address(), common.BytesToHash(depKey))
   332  	return common.BytesToAddress(addrHash[:])
   333  }
   334  func (md *MatrixDeposit) SetDepositListItem(contract *Contract, stateDB StateDB, index uint64, addr common.Address) {
   335  	key := make([]byte, 8)
   336  	binary.BigEndian.PutUint64(key, index)
   337  	contractAddr := contract.Address()
   338  	depKey := append(contractAddr[:], 'D', 'I')
   339  	depKey = append(depKey, key...)
   340  	stateDB.SetState(contract.Address(), common.BytesToHash(depKey), common.BytesToHash(addr[:]))
   341  }
   342  func (md *MatrixDeposit) insertDepositList(contract *Contract, stateDB StateDB) {
   343  	num := md.getDepositListNum(contract, stateDB)
   344  	var count uint64
   345  	if num != nil {
   346  		count = num.Uint64()
   347  		num.Add(num, big.NewInt(1))
   348  	}else{
   349  		num = big.NewInt(1)
   350  	}
   351  	md.setDepositListNum(contract, stateDB, num)
   352  	md.SetDepositListItem(contract, stateDB, count, contract.CallerAddress)
   353  }
   354  func (md *MatrixDeposit) removeDepositList(contract *Contract, stateDB StateDB) error {
   355  	num := md.getDepositListNum(contract, stateDB)
   356  	if num == nil {
   357  		return errDepositEmpty
   358  	}
   359  	count := num.Uint64()
   360  	insert := uint64(math.MaxUint64)
   361  	for i := uint64(0); i < count; i++ {
   362  		addr := md.getDepositListItem(contract, stateDB, i)
   363  		if addr == contract.CallerAddress {
   364  			insert = i
   365  			break
   366  		}
   367  	}
   368  	if insert != math.MaxUint64 {
   369  		addr := md.getDepositListItem(contract, stateDB, count-1)
   370  		md.SetDepositListItem(contract, stateDB, insert, addr)
   371  		num.Sub(num, big.NewInt(1))
   372  		md.setDepositListNum(contract, stateDB, num)
   373  		return nil
   374  	} else {
   375  		return errDeposit
   376  	}
   377  }
   378  
   379  func (md *MatrixDeposit) getDepositInfo(in []byte,contract *Contract, evm *EVM) ([]byte, error) {
   380  	var addr common.Address
   381  	err := depositAbi.Methods["getDepositInfo"].Inputs.Unpack(&addr,in)
   382  	if err != nil{
   383  		return nil,err
   384  	}
   385  	deposit := md.getDeposit(contract, evm.StateDB,addr)
   386  	if deposit == nil || deposit.Sign() == 0 {
   387  		return nil, errDepositEmpty
   388  	}
   389  	nodeID := md.getNodeID(contract, evm.StateDB,addr)
   390  	withdraw := md.getWithdrawHeight(contract, evm.StateDB,addr)
   391  	return depositAbi.Methods["getDepositInfo"].Outputs.Pack(deposit, nodeID[:], withdraw)
   392  }
   393  func (md *MatrixDeposit) modifyDepositState(contract *Contract, evm *EVM, nodeID discover.NodeID) error {
   394  	deposit := md.getDeposit(contract, evm.StateDB,contract.CallerAddress)
   395  	bNew := deposit == nil || deposit.Sign() == 0
   396  	err := md.addDeposit(contract, evm.StateDB)
   397  	if err != nil {
   398  		return err
   399  	}
   400  	md.setNodeID(contract, evm.StateDB, nodeID)
   401  	if bNew {
   402  		md.insertDepositList(contract, evm.StateDB)
   403  	}
   404  	return nil
   405  }
   406  func (md *MatrixDeposit) modifyWithdrawState(contract *Contract, evm *EVM) error {
   407  	deposit := md.getDeposit(contract, evm.StateDB,contract.CallerAddress)
   408  	if deposit == nil || deposit.Sign() == 0 {
   409  		return errDeposit
   410  	}
   411  	md.setWithdrawHeight(contract, evm.StateDB, evm.BlockNumber)
   412  	return nil
   413  }
   414  func (md *MatrixDeposit) modifyRefundState(contract *Contract, evm *EVM) (*big.Int, error) {
   415  	deposit := md.getDeposit(contract, evm.StateDB,contract.CallerAddress)
   416  	if deposit == nil || deposit.Sign() == 0 {
   417  		return nil, errDeposit
   418  	}
   419  	withdrawHeight := md.getWithdrawHeight(contract, evm.StateDB,contract.CallerAddress)
   420  	if withdrawHeight == nil || withdrawHeight.Sign() == 0 {
   421  		return nil, errDeposit
   422  	}
   423  	withdrawHeight.Add(withdrawHeight, big.NewInt(600))
   424  	if withdrawHeight.Cmp(evm.BlockNumber) > 0 {
   425  		return nil, errDeposit
   426  	}
   427  
   428  	md.setDeposit(contract, evm.StateDB, big.NewInt(0))
   429  	md.setNodeID(contract, evm.StateDB, discover.NodeID{})
   430  	md.setWithdrawHeight(contract, evm.StateDB, big.NewInt(0))
   431  	md.setOnlineTime(contract, evm.StateDB, big.NewInt(0))
   432  	md.removeDepositList(contract, evm.StateDB)
   433  	return deposit, nil
   434  }