github.com/ZuluSpl0it/Sia@v1.3.7/node/api/consensus.go (about) 1 package api 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "github.com/NebulousLabs/Sia/crypto" 9 "github.com/NebulousLabs/Sia/types" 10 11 "github.com/julienschmidt/httprouter" 12 ) 13 14 // ConsensusGET contains general information about the consensus set, with tags 15 // to support idiomatic json encodings. 16 type ConsensusGET struct { 17 Synced bool `json:"synced"` 18 Height types.BlockHeight `json:"height"` 19 CurrentBlock types.BlockID `json:"currentblock"` 20 Target types.Target `json:"target"` 21 Difficulty types.Currency `json:"difficulty"` 22 } 23 24 // ConsensusHeadersGET contains information from a blocks header. 25 type ConsensusHeadersGET struct { 26 BlockID types.BlockID `json:"blockid"` 27 } 28 29 // ConsensusBlocksGet contains all fields of a types.Block and additional 30 // fields for ID and Height. 31 type ConsensusBlocksGet struct { 32 ID types.BlockID `json:"id"` 33 Height types.BlockHeight `json:"height"` 34 ParentID types.BlockID `json:"parentid"` 35 Nonce types.BlockNonce `json:"nonce"` 36 Timestamp types.Timestamp `json:"timestamp"` 37 MinerPayouts []types.SiacoinOutput `json:"minerpayouts"` 38 Transactions []ConsensusBlocksGetTxn `json:"transactions"` 39 } 40 41 // ConsensusBlocksGetTxn contains all fields of a types.Transaction and an 42 // additional ID field. 43 type ConsensusBlocksGetTxn struct { 44 ID types.TransactionID `json:"id"` 45 SiacoinInputs []types.SiacoinInput `json:"siacoininputs"` 46 SiacoinOutputs []ConsensusBlocksGetSiacoinOutput `json:"siacoinoutputs"` 47 FileContracts []ConsensusBlocksGetFileContract `json:"filecontracts"` 48 FileContractRevisions []types.FileContractRevision `json:"filecontractrevisions"` 49 StorageProofs []types.StorageProof `json:"storageproofs"` 50 SiafundInputs []types.SiafundInput `json:"siafundinputs"` 51 SiafundOutputs []ConsensusBlocksGetSiafundOutput `json:"siafundoutputs"` 52 MinerFees []types.Currency `json:"minerfees"` 53 ArbitraryData [][]byte `json:"arbitrarydata"` 54 TransactionSignatures []types.TransactionSignature `json:"transactionsignatures"` 55 } 56 57 // ConsensusBlocksGetFileContract contains all fields of a types.FileContract 58 // and an additional ID field. 59 type ConsensusBlocksGetFileContract struct { 60 ID types.FileContractID `json:"id"` 61 FileSize uint64 `json:"filesize"` 62 FileMerkleRoot crypto.Hash `json:"filemerkleroot"` 63 WindowStart types.BlockHeight `json:"windowstart"` 64 WindowEnd types.BlockHeight `json:"windowend"` 65 Payout types.Currency `json:"payout"` 66 ValidProofOutputs []ConsensusBlocksGetSiacoinOutput `json:"validproofoutputs"` 67 MissedProofOutputs []ConsensusBlocksGetSiacoinOutput `json:"missedproofoutputs"` 68 UnlockHash types.UnlockHash `json:"unlockhash"` 69 RevisionNumber uint64 `json:"revisionnumber"` 70 } 71 72 // ConsensusBlocksGetSiacoinOutput contains all fields of a types.SiacoinOutput 73 // and an additional ID field. 74 type ConsensusBlocksGetSiacoinOutput struct { 75 ID types.SiacoinOutputID `json:"id"` 76 Value types.Currency `json:"value"` 77 UnlockHash types.UnlockHash `json:"unlockhash"` 78 } 79 80 // ConsensusBlocksGetSiafundOutput contains all fields of a types.SiafundOutput 81 // and an additional ID field. 82 type ConsensusBlocksGetSiafundOutput struct { 83 ID types.SiafundOutputID `json:"id"` 84 Value types.Currency `json:"value"` 85 UnlockHash types.UnlockHash `json:"unlockhash"` 86 } 87 88 // ConsensusBlocksGetFromBlock is a helper method that uses a types.Block and 89 // types.BlockHeight to create a ConsensusBlocksGet object. 90 func consensusBlocksGetFromBlock(b types.Block, h types.BlockHeight) ConsensusBlocksGet { 91 txns := make([]ConsensusBlocksGetTxn, 0, len(b.Transactions)) 92 for _, t := range b.Transactions { 93 // Get the transaction's SiacoinOutputs. 94 scos := make([]ConsensusBlocksGetSiacoinOutput, 0, len(t.SiacoinOutputs)) 95 for i, sco := range t.SiacoinOutputs { 96 scos = append(scos, ConsensusBlocksGetSiacoinOutput{ 97 ID: t.SiacoinOutputID(uint64(i)), 98 Value: sco.Value, 99 UnlockHash: sco.UnlockHash, 100 }) 101 } 102 // Get the transaction's SiafundOutputs. 103 sfos := make([]ConsensusBlocksGetSiafundOutput, 0, len(t.SiafundOutputs)) 104 for i, sfo := range t.SiafundOutputs { 105 sfos = append(sfos, ConsensusBlocksGetSiafundOutput{ 106 ID: t.SiafundOutputID(uint64(i)), 107 Value: sfo.Value, 108 UnlockHash: sfo.UnlockHash, 109 }) 110 } 111 // Get the transaction's FileContracts. 112 fcos := make([]ConsensusBlocksGetFileContract, 0, len(t.FileContracts)) 113 for i, fc := range t.FileContracts { 114 // Get the FileContract's valid proof outputs. 115 fcid := t.FileContractID(uint64(i)) 116 vpos := make([]ConsensusBlocksGetSiacoinOutput, 0, len(fc.ValidProofOutputs)) 117 for j, vpo := range fc.ValidProofOutputs { 118 vpos = append(vpos, ConsensusBlocksGetSiacoinOutput{ 119 ID: fcid.StorageProofOutputID(types.ProofValid, uint64(j)), 120 Value: vpo.Value, 121 UnlockHash: vpo.UnlockHash, 122 }) 123 } 124 // Get the FileContract's missed proof outputs. 125 mpos := make([]ConsensusBlocksGetSiacoinOutput, 0, len(fc.MissedProofOutputs)) 126 for j, mpo := range fc.MissedProofOutputs { 127 mpos = append(mpos, ConsensusBlocksGetSiacoinOutput{ 128 ID: fcid.StorageProofOutputID(types.ProofMissed, uint64(j)), 129 Value: mpo.Value, 130 UnlockHash: mpo.UnlockHash, 131 }) 132 } 133 fcos = append(fcos, ConsensusBlocksGetFileContract{ 134 ID: fcid, 135 FileSize: fc.FileSize, 136 FileMerkleRoot: fc.FileMerkleRoot, 137 WindowStart: fc.WindowStart, 138 WindowEnd: fc.WindowEnd, 139 Payout: fc.Payout, 140 ValidProofOutputs: vpos, 141 MissedProofOutputs: mpos, 142 UnlockHash: fc.UnlockHash, 143 RevisionNumber: fc.RevisionNumber, 144 }) 145 } 146 txns = append(txns, ConsensusBlocksGetTxn{ 147 ID: t.ID(), 148 SiacoinInputs: t.SiacoinInputs, 149 SiacoinOutputs: scos, 150 FileContracts: fcos, 151 FileContractRevisions: t.FileContractRevisions, 152 StorageProofs: t.StorageProofs, 153 SiafundInputs: t.SiafundInputs, 154 SiafundOutputs: sfos, 155 MinerFees: t.MinerFees, 156 ArbitraryData: t.ArbitraryData, 157 TransactionSignatures: t.TransactionSignatures, 158 }) 159 } 160 return ConsensusBlocksGet{ 161 ID: b.ID(), 162 Height: h, 163 ParentID: b.ParentID, 164 Nonce: b.Nonce, 165 Timestamp: b.Timestamp, 166 MinerPayouts: b.MinerPayouts, 167 Transactions: txns, 168 } 169 } 170 171 // consensusHandler handles the API calls to /consensus. 172 func (api *API) consensusHandler(w http.ResponseWriter, req *http.Request, _ httprouter.Params) { 173 cbid := api.cs.CurrentBlock().ID() 174 currentTarget, _ := api.cs.ChildTarget(cbid) 175 WriteJSON(w, ConsensusGET{ 176 Synced: api.cs.Synced(), 177 Height: api.cs.Height(), 178 CurrentBlock: cbid, 179 Target: currentTarget, 180 Difficulty: currentTarget.Difficulty(), 181 }) 182 } 183 184 // consensusBlocksIDHandler handles the API calls to /consensus/blocks 185 // endpoint. 186 func (api *API) consensusBlocksHandler(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { 187 // Get query params and check them. 188 id, height := req.FormValue("id"), req.FormValue("height") 189 if id != "" && height != "" { 190 WriteError(w, Error{"can't specify both id and height"}, http.StatusBadRequest) 191 } 192 if id == "" && height == "" { 193 WriteError(w, Error{"either id or height has to be provided"}, http.StatusBadRequest) 194 } 195 196 var b types.Block 197 var h types.BlockHeight 198 var exists bool 199 200 // Handle request by id 201 if id != "" { 202 var bid types.BlockID 203 if err := bid.LoadString(id); err != nil { 204 WriteError(w, Error{"failed to unmarshal blockid"}, http.StatusBadRequest) 205 return 206 } 207 b, h, exists = api.cs.BlockByID(bid) 208 } 209 // Handle request by height 210 if height != "" { 211 if _, err := fmt.Sscan(height, &h); err != nil { 212 WriteError(w, Error{"failed to parse block height"}, http.StatusBadRequest) 213 return 214 } 215 b, exists = api.cs.BlockAtHeight(types.BlockHeight(h)) 216 } 217 // Check if block was found 218 if !exists { 219 WriteError(w, Error{"block doesn't exist"}, http.StatusBadRequest) 220 return 221 } 222 // Write response 223 WriteJSON(w, consensusBlocksGetFromBlock(b, h)) 224 } 225 226 // consensusValidateTransactionsetHandler handles the API calls to 227 // /consensus/validate/transactionset. 228 func (api *API) consensusValidateTransactionsetHandler(w http.ResponseWriter, req *http.Request, _ httprouter.Params) { 229 var txnset []types.Transaction 230 err := json.NewDecoder(req.Body).Decode(&txnset) 231 if err != nil { 232 WriteError(w, Error{"could not decode transaction set: " + err.Error()}, http.StatusBadRequest) 233 return 234 } 235 _, err = api.cs.TryTransactionSet(txnset) 236 if err != nil { 237 WriteError(w, Error{"transaction set validation failed: " + err.Error()}, http.StatusBadRequest) 238 return 239 } 240 WriteSuccess(w) 241 }