gitlab.com/flarenetwork/coreth@v0.1.1/core/state_connector.go (about) 1 // (c) 2021, Flare Networks Limited. All rights reserved. 2 // Please see the file LICENSE for licensing terms. 3 4 package core 5 6 import ( 7 "bytes" 8 "crypto/sha256" 9 "encoding/binary" 10 "encoding/hex" 11 "encoding/json" 12 "fmt" 13 "io/ioutil" 14 "math" 15 "math/big" 16 "net/http" 17 "os" 18 "strconv" 19 "strings" 20 "time" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/common/hexutil" 24 "github.com/ethereum/go-ethereum/crypto" 25 ) 26 27 var ( 28 testingChainID = new(big.Int).SetUint64(16) 29 stateConnectorActivationTime = new(big.Int).SetUint64(1636070400) 30 tr = &http.Transport{ 31 MaxIdleConns: 100, 32 MaxConnsPerHost: 100, 33 MaxIdleConnsPerHost: 100, 34 IdleConnTimeout: 60 * time.Second, 35 DisableCompression: true, 36 } 37 client = &http.Client{ 38 Transport: tr, 39 Timeout: 5 * time.Second, 40 } 41 apiRetries = 3 42 apiRetryDelay = 1 * time.Second 43 ) 44 45 func GetStateConnectorActivated(chainID *big.Int, blockTime *big.Int) bool { 46 // Return true if chainID is 16 or if block.timestamp is greater than the state connector activation time on any chain 47 return chainID.Cmp(testingChainID) == 0 || blockTime.Cmp(stateConnectorActivationTime) > 0 48 } 49 50 func GetStateConnectorGasDivisor(blockTime *big.Int) uint64 { 51 switch { 52 default: 53 return 3 54 } 55 } 56 57 func GetMaxAllowedChains(blockTime *big.Int) uint32 { 58 switch { 59 default: 60 return 5 61 } 62 } 63 64 func GetStateConnectorContractAddr(blockTime *big.Int) string { 65 switch { 66 default: 67 return "0x1000000000000000000000000000000000000001" 68 } 69 } 70 71 func GetProveDataAvailabilityPeriodFinalitySelector(blockTime *big.Int) []byte { 72 switch { 73 default: 74 return []byte{0xc5, 0xd6, 0x4c, 0xd1} 75 } 76 } 77 78 func GetProvePaymentFinalitySelector(blockTime *big.Int) []byte { 79 switch { 80 default: 81 return []byte{0x38, 0x84, 0x92, 0xdd} 82 } 83 } 84 85 func GetDisprovePaymentFinalitySelector(blockTime *big.Int) []byte { 86 switch { 87 default: 88 return []byte{0x7f, 0x58, 0x24, 0x32} 89 } 90 } 91 92 // ======================================================= 93 // Proof of Work Common 94 // ======================================================= 95 96 type GetPoWRequestPayload struct { 97 Method string `json:"method"` 98 Params []string `json:"params"` 99 } 100 type GetPoWBlockCountResp struct { 101 Result uint64 `json:"result"` 102 Error interface{} `json:"error"` 103 } 104 105 func GetPoWBlockCount(chainURL string, username string, password string) (uint64, bool) { 106 data := GetPoWRequestPayload{ 107 Method: "getblockcount", 108 Params: []string{}, 109 } 110 payloadBytes, err := json.Marshal(data) 111 if err != nil { 112 return 0, true 113 } 114 body := bytes.NewReader(payloadBytes) 115 req, err := http.NewRequest("POST", chainURL, body) 116 if err != nil { 117 return 0, true 118 } 119 req.Header.Set("Content-Type", "application/json") 120 if username != "" && password != "" { 121 req.SetBasicAuth(username, password) 122 } 123 resp, err := client.Do(req) 124 if err != nil { 125 return 0, true 126 } 127 defer resp.Body.Close() 128 if resp.StatusCode != 200 { 129 return 0, true 130 } 131 respBody, err := ioutil.ReadAll(resp.Body) 132 if err != nil { 133 return 0, true 134 } 135 var jsonResp GetPoWBlockCountResp 136 err = json.Unmarshal(respBody, &jsonResp) 137 if err != nil { 138 return 0, true 139 } 140 if jsonResp.Error != nil { 141 return 0, true 142 } 143 return jsonResp.Result, false 144 } 145 146 type GetPoWBlockHeaderResult struct { 147 Hash string `json:"hash"` 148 Confirmations uint64 `json:"confirmations"` 149 Height uint64 `json:"height"` 150 } 151 type GetPoWBlockHeaderResp struct { 152 Result GetPoWBlockHeaderResult `json:"result"` 153 Error interface{} `json:"error"` 154 } 155 156 func GetPoWBlockHeader(ledgerHash string, requiredConfirmations uint64, chainURL string, username string, password string) (uint64, bool) { 157 data := GetPoWRequestPayload{ 158 Method: "getblockheader", 159 Params: []string{ 160 ledgerHash, 161 }, 162 } 163 payloadBytes, err := json.Marshal(data) 164 if err != nil { 165 return 0, true 166 } 167 body := bytes.NewReader(payloadBytes) 168 req, err := http.NewRequest("POST", chainURL, body) 169 if err != nil { 170 return 0, true 171 } 172 req.Header.Set("Content-Type", "application/json") 173 if username != "" && password != "" { 174 req.SetBasicAuth(username, password) 175 } 176 resp, err := client.Do(req) 177 if err != nil { 178 return 0, true 179 } 180 defer resp.Body.Close() 181 if resp.StatusCode != 200 { 182 return 0, true 183 } 184 respBody, err := ioutil.ReadAll(resp.Body) 185 if err != nil { 186 return 0, true 187 } 188 var jsonResp GetPoWBlockHeaderResp 189 err = json.Unmarshal(respBody, &jsonResp) 190 if err != nil { 191 return 0, true 192 } 193 if jsonResp.Error != nil { 194 return 0, false 195 } else if jsonResp.Result.Confirmations < requiredConfirmations { 196 return 0, false 197 } 198 return jsonResp.Result.Height, false 199 } 200 201 func ProveDataAvailabilityPeriodFinalityPoW(checkRet []byte, chainURL string, username string, password string) (bool, bool) { 202 blockCount, err := GetPoWBlockCount(chainURL, username, password) 203 if err { 204 return false, true 205 } 206 ledger := binary.BigEndian.Uint64(checkRet[56:64]) 207 requiredConfirmations := binary.BigEndian.Uint64(checkRet[88:96]) 208 if blockCount < ledger+requiredConfirmations { 209 return false, true 210 } 211 ledgerResp, err := GetPoWBlockHeader(hex.EncodeToString(checkRet[96:128]), requiredConfirmations, chainURL, username, password) 212 if err { 213 return false, true 214 } else if ledgerResp > 0 && ledgerResp == ledger { 215 return true, false 216 } else { 217 return false, false 218 } 219 } 220 221 type GetPoWTxRequestParams struct { 222 TxID string `json:"txid"` 223 Verbose bool `json:"verbose"` 224 } 225 type GetPoWTxRequestPayload struct { 226 Method string `json:"method"` 227 Params GetPoWTxRequestParams `json:"params"` 228 } 229 type GetPoWTxResult struct { 230 TxID string `json:"txid"` 231 BlockHash string `json:"blockhash"` 232 Confirmations uint64 `json:"confirmations"` 233 Vout []struct { 234 Value float64 `json:"value"` 235 N uint64 `json:"n"` 236 ScriptPubKey struct { 237 Type string `json:"type"` 238 Addresses []string `json:"addresses"` 239 } `json:"scriptPubKey"` 240 } `json:"vout"` 241 } 242 type GetPoWTxResp struct { 243 Result GetPoWTxResult `json:"result"` 244 Error interface{} `json:"error"` 245 } 246 247 func GetPoWTx(txHash string, voutN uint64, latestAvailableBlock uint64, currencyCode string, chainURL string, username string, password string) ([]byte, uint64, bool) { 248 data := GetPoWTxRequestPayload{ 249 Method: "getrawtransaction", 250 Params: GetPoWTxRequestParams{ 251 TxID: txHash[1:], 252 Verbose: true, 253 }, 254 } 255 payloadBytes, err := json.Marshal(data) 256 if err != nil { 257 return []byte{}, 0, true 258 } 259 body := bytes.NewReader(payloadBytes) 260 req, err := http.NewRequest("POST", chainURL, body) 261 if err != nil { 262 return []byte{}, 0, true 263 } 264 req.Header.Set("Content-Type", "application/json") 265 if username != "" && password != "" { 266 req.SetBasicAuth(username, password) 267 } 268 resp, err := client.Do(req) 269 if err != nil { 270 return []byte{}, 0, true 271 } 272 defer resp.Body.Close() 273 if resp.StatusCode != 200 { 274 return []byte{}, 0, true 275 } 276 respBody, err := ioutil.ReadAll(resp.Body) 277 if err != nil { 278 return []byte{}, 0, true 279 } 280 var jsonResp GetPoWTxResp 281 err = json.Unmarshal(respBody, &jsonResp) 282 if err != nil { 283 return []byte{}, 0, true 284 } 285 if jsonResp.Error != nil { 286 return []byte{}, 0, true 287 } 288 if uint64(len(jsonResp.Result.Vout)) <= voutN { 289 return []byte{}, 0, false 290 } 291 if jsonResp.Result.Vout[voutN].ScriptPubKey.Type != "pubkeyhash" || len(jsonResp.Result.Vout[voutN].ScriptPubKey.Addresses) != 1 { 292 return []byte{}, 0, false 293 } 294 inBlock, getBlockErr := GetPoWBlockHeader(jsonResp.Result.BlockHash, jsonResp.Result.Confirmations, chainURL, username, password) 295 if getBlockErr { 296 return []byte{}, 0, true 297 } 298 if inBlock == 0 || inBlock >= latestAvailableBlock { 299 return []byte{}, 0, false 300 } 301 txIdHash := crypto.Keccak256([]byte(txHash)) 302 destinationHash := crypto.Keccak256([]byte(jsonResp.Result.Vout[voutN].ScriptPubKey.Addresses[0])) 303 amountHash := crypto.Keccak256(common.LeftPadBytes(common.FromHex(hexutil.EncodeUint64(uint64(jsonResp.Result.Vout[voutN].Value*math.Pow(10, 8)))), 32)) 304 currencyHash := crypto.Keccak256([]byte(currencyCode)) 305 return crypto.Keccak256(txIdHash, destinationHash, amountHash, currencyHash), inBlock, false 306 } 307 308 func ProvePaymentFinalityPoW(checkRet []byte, isDisprove bool, currencyCode string, chainURL string, username string, password string) (bool, bool) { 309 if len(checkRet) < 257 { 310 return false, false 311 } 312 voutN, err := strconv.ParseUint(string(checkRet[192:193]), 16, 64) 313 if err != nil { 314 return false, false 315 } 316 paymentHash, inBlock, getPoWTxErr := GetPoWTx(string(checkRet[192:257]), voutN, binary.BigEndian.Uint64(checkRet[88:96]), currencyCode, chainURL, username, password) 317 if getPoWTxErr { 318 return false, true 319 } 320 if !isDisprove { 321 if len(paymentHash) > 0 && bytes.Equal(paymentHash, checkRet[96:128]) && inBlock == binary.BigEndian.Uint64(checkRet[56:64]) { 322 return true, false 323 } 324 } else { 325 if len(paymentHash) > 0 && bytes.Equal(paymentHash, checkRet[96:128]) && inBlock > binary.BigEndian.Uint64(checkRet[56:64]) { 326 return true, false 327 } else if len(paymentHash) == 0 { 328 return true, false 329 } 330 } 331 return false, false 332 } 333 334 func ProvePoW(sender common.Address, blockTime *big.Int, functionSelector []byte, checkRet []byte, currencyCode string, chainURL string) (bool, bool) { 335 var username, password string 336 chainURLhash := sha256.Sum256([]byte(chainURL)) 337 chainURLchecksum := hex.EncodeToString(chainURLhash[0:4]) 338 switch currencyCode { 339 case "btc": 340 username = os.Getenv("BTC_U_" + chainURLchecksum) 341 password = os.Getenv("BTC_P_" + chainURLchecksum) 342 case "ltc": 343 username = os.Getenv("LTC_U_" + chainURLchecksum) 344 password = os.Getenv("LTC_P_" + chainURLchecksum) 345 case "dog": 346 username = os.Getenv("DOGE_U_" + chainURLchecksum) 347 password = os.Getenv("DOGE_P_" + chainURLchecksum) 348 } 349 if bytes.Equal(functionSelector, GetProveDataAvailabilityPeriodFinalitySelector(blockTime)) { 350 return ProveDataAvailabilityPeriodFinalityPoW(checkRet, chainURL, username, password) 351 } else if bytes.Equal(functionSelector, GetProvePaymentFinalitySelector(blockTime)) { 352 return ProvePaymentFinalityPoW(checkRet, false, currencyCode, chainURL, username, password) 353 } else if bytes.Equal(functionSelector, GetDisprovePaymentFinalitySelector(blockTime)) { 354 return ProvePaymentFinalityPoW(checkRet, true, currencyCode, chainURL, username, password) 355 } 356 return false, false 357 } 358 359 // ======================================================= 360 // XRP 361 // ======================================================= 362 363 type GetXRPBlockRequestParams struct { 364 LedgerIndex uint64 `json:"ledger_index"` 365 Full bool `json:"full"` 366 Accounts bool `json:"accounts"` 367 Transactions bool `json:"transactions"` 368 Expand bool `json:"expand"` 369 OwnerFunds bool `json:"owner_funds"` 370 } 371 type GetXRPBlockRequestPayload struct { 372 Method string `json:"method"` 373 Params []GetXRPBlockRequestParams `json:"params"` 374 } 375 type CheckXRPErrorResponse struct { 376 Error string `json:"error"` 377 } 378 type GetXRPBlockResponse struct { 379 LedgerHash string `json:"ledger_hash"` 380 LedgerIndex int `json:"ledger_index"` 381 Validated bool `json:"validated"` 382 } 383 384 func GetXRPBlock(ledger uint64, chainURL string) (string, bool) { 385 data := GetXRPBlockRequestPayload{ 386 Method: "ledger", 387 Params: []GetXRPBlockRequestParams{ 388 { 389 LedgerIndex: ledger, 390 Full: false, 391 Accounts: false, 392 Transactions: false, 393 Expand: false, 394 OwnerFunds: false, 395 }, 396 }, 397 } 398 payloadBytes, err := json.Marshal(data) 399 if err != nil { 400 return "", true 401 } 402 body := bytes.NewReader(payloadBytes) 403 req, err := http.NewRequest("POST", chainURL, body) 404 if err != nil { 405 return "", true 406 } 407 req.Header.Set("Content-Type", "application/json") 408 resp, err := client.Do(req) 409 if err != nil { 410 return "", true 411 } 412 defer resp.Body.Close() 413 if resp.StatusCode != 200 { 414 return "", true 415 } 416 respBody, err := ioutil.ReadAll(resp.Body) 417 if err != nil { 418 return "", true 419 } 420 var checkErrorResp map[string]CheckXRPErrorResponse 421 err = json.Unmarshal(respBody, &checkErrorResp) 422 if err != nil { 423 return "", true 424 } 425 if checkErrorResp["result"].Error != "" { 426 return "", true 427 } 428 var jsonResp map[string]GetXRPBlockResponse 429 err = json.Unmarshal(respBody, &jsonResp) 430 if err != nil { 431 return "", true 432 } 433 if !jsonResp["result"].Validated { 434 return "", true 435 } 436 return jsonResp["result"].LedgerHash, false 437 } 438 439 func ProveDataAvailabilityPeriodFinalityXRP(checkRet []byte, chainURL string) (bool, bool) { 440 ledger := binary.BigEndian.Uint64(checkRet[56:64]) 441 ledgerHashString, err := GetXRPBlock(ledger, chainURL) 442 if err { 443 return false, true 444 } 445 if ledgerHashString != "" && bytes.Equal(crypto.Keccak256([]byte(ledgerHashString)), checkRet[96:128]) { 446 return true, false 447 } 448 return false, false 449 } 450 451 type GetXRPTxRequestParams struct { 452 Transaction string `json:"transaction"` 453 Binary bool `json:"binary"` 454 } 455 type GetXRPTxRequestPayload struct { 456 Method string `json:"method"` 457 Params []GetXRPTxRequestParams `json:"params"` 458 } 459 type GetXRPTxResponse struct { 460 Destination string `json:"Destination"` 461 DestinationTag int `json:"DestinationTag"` 462 TransactionType string `json:"TransactionType"` 463 Hash string `json:"hash"` 464 InLedger int `json:"inLedger"` 465 Validated bool `json:"validated"` 466 Meta struct { 467 TransactionResult string `json:"TransactionResult"` 468 Amount interface{} `json:"delivered_amount"` 469 } `json:"meta"` 470 } 471 472 type GetXRPTxIssuedCurrency struct { 473 Currency string `json:"currency"` 474 Issuer string `json:"issuer"` 475 Value string `json:"value"` 476 } 477 478 func GetXRPTx(txHash string, latestAvailableLedger uint64, chainURL string) ([]byte, uint64, bool) { 479 data := GetXRPTxRequestPayload{ 480 Method: "tx", 481 Params: []GetXRPTxRequestParams{ 482 { 483 Transaction: txHash, 484 Binary: false, 485 }, 486 }, 487 } 488 payloadBytes, err := json.Marshal(data) 489 if err != nil { 490 return []byte{}, 0, true 491 } 492 body := bytes.NewReader(payloadBytes) 493 req, err := http.NewRequest("POST", chainURL, body) 494 if err != nil { 495 return []byte{}, 0, true 496 } 497 req.Header.Set("Content-Type", "application/json") 498 resp, err := client.Do(req) 499 if err != nil { 500 return []byte{}, 0, true 501 } 502 defer resp.Body.Close() 503 if resp.StatusCode != 200 { 504 return []byte{}, 0, true 505 } 506 respBody, err := ioutil.ReadAll(resp.Body) 507 if err != nil { 508 return []byte{}, 0, true 509 } 510 var checkErrorResp map[string]CheckXRPErrorResponse 511 err = json.Unmarshal(respBody, &checkErrorResp) 512 if err != nil { 513 return []byte{}, 0, true 514 } 515 respErrString := checkErrorResp["result"].Error 516 if respErrString != "" { 517 if respErrString == "amendmentBlocked" || 518 respErrString == "failedToForward" || 519 respErrString == "invalid_API_version" || 520 respErrString == "noClosed" || 521 respErrString == "noCurrent" || 522 respErrString == "noNetwork" || 523 respErrString == "tooBusy" { 524 return []byte{}, 0, true 525 } else { 526 return []byte{}, 0, false 527 } 528 } 529 var jsonResp map[string]GetXRPTxResponse 530 err = json.Unmarshal(respBody, &jsonResp) 531 if err != nil { 532 return []byte{}, 0, false 533 } 534 if jsonResp["result"].TransactionType != "Payment" || !jsonResp["result"].Validated || jsonResp["result"].Meta.TransactionResult != "tesSUCCESS" { 535 return []byte{}, 0, false 536 } 537 inLedger := uint64(jsonResp["result"].InLedger) 538 if inLedger == 0 || inLedger >= latestAvailableLedger || !jsonResp["result"].Validated { 539 return []byte{}, 0, false 540 } 541 var currency string 542 var amount uint64 543 if stringAmount, ok := jsonResp["result"].Meta.Amount.(string); ok { 544 amount, err = strconv.ParseUint(stringAmount, 10, 64) 545 if err != nil { 546 return []byte{}, 0, false 547 } 548 currency = "xrp" 549 } else { 550 amountStruct, err := json.Marshal(jsonResp["result"].Meta.Amount) 551 if err != nil { 552 return []byte{}, 0, false 553 } 554 var issuedCurrencyResp GetXRPTxIssuedCurrency 555 err = json.Unmarshal(amountStruct, &issuedCurrencyResp) 556 if err != nil { 557 return []byte{}, 0, false 558 } 559 floatAmount, err := strconv.ParseFloat(issuedCurrencyResp.Value, 64) 560 if err != nil { 561 return []byte{}, 0, false 562 } 563 amount = uint64(floatAmount * math.Pow(10, 15)) 564 currency = issuedCurrencyResp.Currency + issuedCurrencyResp.Issuer 565 } 566 txIdHash := crypto.Keccak256([]byte(jsonResp["result"].Hash)) 567 destinationHash := crypto.Keccak256([]byte(jsonResp["result"].Destination)) 568 destinationTagHash := crypto.Keccak256(common.LeftPadBytes(common.FromHex(hexutil.EncodeUint64(uint64(jsonResp["result"].DestinationTag))), 32)) 569 destinationHash = crypto.Keccak256(destinationHash, destinationTagHash) 570 amountHash := crypto.Keccak256(common.LeftPadBytes(common.FromHex(hexutil.EncodeUint64(amount)), 32)) 571 currencyHash := crypto.Keccak256([]byte(currency)) 572 return crypto.Keccak256(txIdHash, destinationHash, amountHash, currencyHash), inLedger, false 573 } 574 575 func ProvePaymentFinalityXRP(checkRet []byte, isDisprove bool, chainURL string) (bool, bool) { 576 paymentHash, inLedger, err := GetXRPTx(string(checkRet[192:]), binary.BigEndian.Uint64(checkRet[88:96]), chainURL) 577 if err { 578 return false, true 579 } 580 if !isDisprove { 581 if len(paymentHash) > 0 && bytes.Equal(paymentHash, checkRet[96:128]) && inLedger == binary.BigEndian.Uint64(checkRet[56:64]) { 582 return true, false 583 } 584 } else { 585 if len(paymentHash) > 0 && bytes.Equal(paymentHash, checkRet[96:128]) && inLedger > binary.BigEndian.Uint64(checkRet[56:64]) { 586 return true, false 587 } else if len(paymentHash) == 0 { 588 return true, false 589 } 590 } 591 return false, false 592 } 593 594 func ProveXRP(sender common.Address, blockTime *big.Int, functionSelector []byte, checkRet []byte, chainURL string) (bool, bool) { 595 if bytes.Equal(functionSelector, GetProveDataAvailabilityPeriodFinalitySelector(blockTime)) { 596 return ProveDataAvailabilityPeriodFinalityXRP(checkRet, chainURL) 597 } else if bytes.Equal(functionSelector, GetProvePaymentFinalitySelector(blockTime)) { 598 return ProvePaymentFinalityXRP(checkRet, false, chainURL) 599 } else if bytes.Equal(functionSelector, GetDisprovePaymentFinalitySelector(blockTime)) { 600 return ProvePaymentFinalityXRP(checkRet, true, chainURL) 601 } 602 return false, false 603 } 604 605 // ======================================================= 606 // ALGO 607 // ======================================================= 608 609 func ProveALGO(sender common.Address, blockTime *big.Int, functionSelector []byte, checkRet []byte, chainURL string) (bool, bool) { 610 return false, false 611 } 612 613 // ======================================================= 614 // Common 615 // ======================================================= 616 617 func ProveChain(sender common.Address, blockTime *big.Int, functionSelector []byte, checkRet []byte, chainId uint32, chainURL string) (bool, bool) { 618 switch chainId { 619 case 0: 620 return ProvePoW(sender, blockTime, functionSelector, checkRet, "btc", chainURL) 621 case 1: 622 return ProvePoW(sender, blockTime, functionSelector, checkRet, "ltc", chainURL) 623 case 2: 624 return ProvePoW(sender, blockTime, functionSelector, checkRet, "dog", chainURL) 625 case 3: 626 return ProveXRP(sender, blockTime, functionSelector, checkRet, chainURL) 627 case 4: 628 return ProveALGO(sender, blockTime, functionSelector, checkRet, chainURL) 629 default: 630 return false, true 631 } 632 } 633 634 func ReadChain(sender common.Address, blockTime *big.Int, functionSelector []byte, checkRet []byte) bool { 635 chainId := binary.BigEndian.Uint32(checkRet[28:32]) 636 var chainURLs string 637 switch chainId { 638 case 0: 639 chainURLs = os.Getenv("BTC_APIs") 640 case 1: 641 chainURLs = os.Getenv("LTC_APIs") 642 case 2: 643 chainURLs = os.Getenv("DOGE_APIs") 644 case 3: 645 chainURLs = os.Getenv("XRP_APIs") 646 case 4: 647 chainURLs = os.Getenv("ALGO_APIs") 648 } 649 if chainURLs == "" { 650 return false 651 } 652 for i := 0; i < apiRetries; i++ { 653 for _, chainURL := range strings.Split(chainURLs, ",") { 654 if chainURL == "" { 655 continue 656 } 657 verified, err := ProveChain(sender, blockTime, functionSelector, checkRet, chainId, chainURL) 658 if !verified && err { 659 continue 660 } 661 return verified 662 } 663 time.Sleep(apiRetryDelay) 664 } 665 return false 666 } 667 668 func GetVerificationPaths(functionSelector []byte, checkRet []byte) (string, string) { 669 prefix := "cache/" 670 acceptedPrefix := "ACCEPTED" 671 rejectedPrefix := "REJECTED" 672 functionHash := hex.EncodeToString(functionSelector[:]) 673 verificationHash := hex.EncodeToString(crypto.Keccak256(checkRet[0:64], checkRet[96:128])) 674 suffix := "_" + functionHash + "_" + verificationHash 675 return prefix + acceptedPrefix + suffix, prefix + rejectedPrefix + suffix 676 } 677 678 // Verify proof against underlying chain 679 func StateConnectorCall(sender common.Address, blockTime *big.Int, functionSelector []byte, checkRet []byte) bool { 680 if binary.BigEndian.Uint64(checkRet[88:96]) > 0 { 681 go func() { 682 acceptedPath, rejectedPath := GetVerificationPaths(functionSelector, checkRet) 683 _, errACCEPTED := os.Stat(acceptedPath) 684 _, errREJECTED := os.Stat(rejectedPath) 685 if errACCEPTED != nil && errREJECTED != nil { 686 if ReadChain(sender, blockTime, functionSelector, checkRet) { 687 verificationHashStore, err := os.Create(acceptedPath) 688 verificationHashStore.Close() 689 if err != nil { 690 // Permissions problem 691 panic(err) 692 } 693 } else { 694 verificationHashStore, err := os.Create(rejectedPath) 695 verificationHashStore.Close() 696 if err != nil { 697 // Permissions problem 698 panic(err) 699 } 700 } 701 } 702 }() 703 return true 704 } else { 705 acceptedPath, rejectedPath := GetVerificationPaths(functionSelector, checkRet) 706 _, errACCEPTED := os.Stat(acceptedPath) 707 _, errREJECTED := os.Stat(rejectedPath) 708 if errACCEPTED != nil && errREJECTED != nil { 709 for i := 0; i < 2*apiRetries; i++ { 710 _, errACCEPTED = os.Stat(acceptedPath) 711 _, errREJECTED = os.Stat(rejectedPath) 712 if errACCEPTED == nil || errREJECTED == nil { 713 break 714 } 715 time.Sleep(apiRetryDelay) 716 } 717 } 718 go func() { 719 removeFulfilledAPIRequests := os.Getenv("REMOVE_FULFILLED_API_REQUESTS") 720 if removeFulfilledAPIRequests == "1" { 721 errDeleteACCEPTED := os.Remove(acceptedPath) 722 errDeleteREJECTED := os.Remove(rejectedPath) 723 if errDeleteACCEPTED != nil && errDeleteREJECTED != nil { 724 // Permissions problem 725 panic(fmt.Sprintf("%s\n%s", errDeleteACCEPTED, errDeleteREJECTED)) 726 } 727 } 728 }() 729 return errACCEPTED == nil 730 } 731 }