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 }