code.vegaprotocol.io/vega@v0.79.0/core/datasource/external/openoracle/openoracle.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package openoracle 17 18 import ( 19 "encoding/hex" 20 "encoding/json" 21 "fmt" 22 "strings" 23 24 "github.com/ethereum/go-ethereum/accounts" 25 "github.com/ethereum/go-ethereum/accounts/abi" 26 "github.com/ethereum/go-ethereum/crypto" 27 ) 28 29 type OracleResponse struct { 30 Timestamp string `json:"timestamp"` 31 Messages []string `json:"messages"` 32 Signatures []string `json:"signatures"` 33 Prices map[string]string `json:"prices"` 34 } 35 36 // UnmarshalVerify will unmarshal a json raw payload 37 // into and OracleResponse 38 // if the unmarshal is successful then the content is verified. 39 func UnmarshalVerify(payload []byte, address string) (*OracleResponse, error) { 40 oresp, err := Unmarshal(payload) 41 if err != nil { 42 return nil, err 43 } 44 45 _, _, err = Verify(*oresp) 46 return oresp, err 47 } 48 49 func Unmarshal(payload []byte) (*OracleResponse, error) { 50 oresp := OracleResponse{} 51 err := json.Unmarshal(payload, &oresp) 52 if err != nil { 53 return nil, err 54 } 55 return &oresp, nil 56 } 57 58 func Verify(oresp OracleResponse) ([]string, map[string]string, error) { 59 typString, err := abi.NewType("string", "", nil) 60 if err != nil { 61 return nil, nil, err 62 } 63 64 typUint64, err := abi.NewType("uint64", "", nil) 65 if err != nil { 66 return nil, nil, err 67 } 68 69 args := abi.Arguments([]abi.Argument{ 70 { 71 Name: "kind", 72 Type: typString, 73 }, 74 { 75 Name: "timestamp", 76 Type: typUint64, 77 }, 78 { 79 Name: "key", 80 Type: typString, 81 }, 82 { 83 Name: "value", 84 Type: typUint64, 85 }, 86 }) 87 88 // ensure we have as much signature than messages 89 if len(oresp.Messages) != len(oresp.Signatures) { 90 return nil, nil, fmt.Errorf("got %v signatures, but have %v messages", len(oresp.Signatures), len(oresp.Messages)) 91 } 92 93 addresses := map[string]struct{}{} 94 keyValues := map[string]string{} 95 96 for i := 0; i < len(oresp.Messages); i++ { 97 sigBytes, err := hex.DecodeString(strings.TrimPrefix(oresp.Signatures[i], "0x")) 98 if err != nil { 99 return nil, nil, err 100 } 101 msgBytes, err := hex.DecodeString(strings.TrimPrefix(oresp.Messages[i], "0x")) 102 if err != nil { 103 return nil, nil, err 104 } 105 hashDecoded := crypto.Keccak256Hash(msgBytes) 106 hashDecodedPadded := accounts.TextHash(hashDecoded.Bytes()) 107 108 if len(sigBytes) > 65 { 109 sigBytes[64] = sigBytes[len(sigBytes)-1] 110 sigBytes = sigBytes[:65] 111 } 112 sigBytes[64] = sigBytes[64] - 27 113 114 // SigToPub actually goes through the verification of the signature 115 // before returning the pubkey that we can use to retrieve the address later 116 // on. so no need for extra steps in verifying the signature later on. 117 sigPublicKeyECDSA, err := crypto.SigToPub(hashDecodedPadded, sigBytes) 118 if err != nil { 119 return nil, nil, err 120 } 121 122 addrHex := crypto.PubkeyToAddress(*sigPublicKeyECDSA).Hex() 123 addresses[addrHex] = struct{}{} 124 125 m := map[string]interface{}{} 126 err = args.UnpackIntoMap(m, msgBytes) 127 if err != nil { 128 return nil, nil, err 129 } 130 131 keyValues[fmt.Sprintf("%v.%v.value", m["kind"], m["key"])] = fmt.Sprintf("%v", m["value"]) 132 keyValues[fmt.Sprintf("%v.%v.timestamp", m["kind"], m["key"])] = fmt.Sprintf("%v", m["timestamp"]) 133 } 134 135 addressesSlice := make([]string, 0, len(addresses)) 136 for k := range addresses { 137 addressesSlice = append(addressesSlice, k) 138 } 139 140 return addressesSlice, keyValues, nil 141 }