]> Git Repo - VerusCoin.git/blob - src/cc/CCassetsCore.cpp
Ensure export finalization edge case
[VerusCoin.git] / src / cc / CCassetsCore.cpp
1 /******************************************************************************
2  * Copyright © 2014-2018 The SuperNET Developers.                             *
3  *                                                                            *
4  * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at                  *
5  * the top-level directory of this distribution for the individual copyright  *
6  * holder information and the developer policies on copyright and licensing.  *
7  *                                                                            *
8  * Unless otherwise agreed in a custom licensing agreement, no part of the    *
9  * SuperNET software, including this file may be copied, modified, propagated *
10  * or distributed except according to the terms contained in the LICENSE file *
11  *                                                                            *
12  * Removal or modification of this copyright notice is prohibited.            *
13  *                                                                            *
14  ******************************************************************************/
15
16 #include "CCassets.h"
17
18 /*
19  The SetAssetFillamounts() and ValidateAssetRemainder() work in tandem to calculate the vouts for a fill and to validate the vouts, respectively.
20  
21  This pair of functions are critical to make sure the trading is correct and is the trickiest part of the assets contract.
22  
23  //vin.0: normal input
24  //vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
25  //vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue
26  //vout.0: remaining amount of bid to unspendable
27  //vout.1: vin.1 value to signer of vin.2
28  //vout.2: vin.2 assetoshis to original pubkey
29  //vout.3: CC output for assetoshis change (if any)
30  //vout.4: normal output for change (if any)
31  //vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
32     ValidateAssetRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits);
33  
34  Yes, this is quite confusing...
35  
36  In ValudateAssetRemainder the naming convention is nValue is the coin/asset with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or assets, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits.
37  
38  We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it.
39 */
40
41 bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidunits,int64_t totalunits)
42 {
43     int64_t unitprice,recvunitprice,newunitprice=0;
44     if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
45     {
46         fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
47         return(false);
48     }
49     else if ( totalunits != (remaining_units + paidunits) )
50     {
51         fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_units %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_units + paidunits),(long long)remaining_units,(long long)paidunits);
52         return(false);
53     }
54     else if ( orig_nValue != (remaining_nValue + received_nValue) )
55     {
56         fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
57         return(false);
58     }
59     else
60     {
61         //unitprice = (orig_nValue * COIN) / totalunits;
62         //recvunitprice = (received_nValue * COIN) / paidunits;
63         //if ( remaining_units != 0 )
64         //    newunitprice = (remaining_nValue * COIN) / remaining_units;
65         unitprice = (orig_nValue / totalunits);
66         recvunitprice = (received_nValue / paidunits);
67         if ( remaining_units != 0 )
68             newunitprice = (remaining_nValue / remaining_units);
69         if ( recvunitprice < unitprice )
70         {
71             fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
72             return(false);
73         }
74         fprintf(stderr,"orig %llu total %llu, recv %llu paid %llu,recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(long long)orig_nValue,(long long)totalunits,(long long)received_nValue,(long long)paidunits,(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
75     }
76     return(true);
77 }
78
79 bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t orig_nValue,int64_t &paidunits,int64_t totalunits)
80 {
81     int64_t remaining_nValue,unitprice; double dprice;
82     if ( totalunits == 0 )
83     {
84         received_nValue = remaining_units = paidunits = 0;
85         return(false);
86     }
87     if ( paidunits >= totalunits )
88     {
89         paidunits = totalunits;
90         received_nValue = orig_nValue;
91         remaining_units = 0;
92         fprintf(stderr,"totally filled!\n");
93         return(true);
94     }
95     remaining_units = (totalunits - paidunits);
96     //unitprice = (orig_nValue * COIN) / totalunits;
97     //received_nValue = (paidunits * unitprice) / COIN;
98     unitprice = (orig_nValue / totalunits);
99     received_nValue = (paidunits * unitprice);
100     if ( unitprice > 0 && received_nValue > 0 && received_nValue <= orig_nValue )
101     {
102         remaining_nValue = (orig_nValue - received_nValue);
103         printf("total.%llu - paid.%llu, remaining %llu <- %llu (%llu - %llu)\n",(long long)totalunits,(long long)paidunits,(long long)remaining_nValue,(long long)(orig_nValue - received_nValue),(long long)orig_nValue,(long long)received_nValue);
104         return(ValidateBidRemainder(remaining_units,remaining_nValue,orig_nValue,received_nValue,paidunits,totalunits));
105     } else return(false);
106 }
107
108 bool SetAskFillamounts(int64_t &received_assetoshis,int64_t &remaining_nValue,int64_t orig_assetoshis,int64_t &paid_nValue,int64_t total_nValue)
109 {
110     int64_t remaining_assetoshis; double dunitprice;
111     if ( total_nValue == 0 )
112     {
113         received_assetoshis = remaining_nValue = paid_nValue = 0;
114         return(false);
115     }
116     if ( paid_nValue >= total_nValue )
117     {
118         paid_nValue = total_nValue;
119         received_assetoshis = orig_assetoshis;
120         remaining_nValue = 0;
121         fprintf(stderr,"totally filled!\n");
122         return(true);
123     }
124     remaining_nValue = (total_nValue - paid_nValue);
125     dunitprice = ((double)total_nValue / orig_assetoshis);
126     received_assetoshis = (paid_nValue / dunitprice);
127     fprintf(stderr,"remaining_nValue %.8f (%.8f - %.8f)\n",(double)remaining_nValue/COIN,(double)total_nValue/COIN,(double)paid_nValue/COIN);
128     fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
129     if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
130     {
131         remaining_assetoshis = (orig_assetoshis - received_assetoshis);
132         return(ValidateAskRemainder(remaining_nValue,remaining_assetoshis,orig_assetoshis,received_assetoshis,paid_nValue,total_nValue));
133     } else return(false);
134 }
135
136 bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,int64_t orig_assetoshis,int64_t received_assetoshis,int64_t paid_nValue,int64_t total_nValue)
137 {
138     int64_t unitprice,recvunitprice,newunitprice=0;
139     if ( orig_assetoshis == 0 || received_assetoshis == 0 || paid_nValue == 0 || total_nValue == 0 )
140     {
141         fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis == %llu || received_assetoshis == %llu || paid_nValue == %llu || total_nValue == %llu\n",(long long)orig_assetoshis,(long long)received_assetoshis,(long long)paid_nValue,(long long)total_nValue);
142         return(false);
143     }
144     else if ( total_nValue != (remaining_nValue + paid_nValue) )
145     {
146         fprintf(stderr,"ValidateAssetRemainder: total_nValue %llu != %llu (remaining_nValue %llu + %llu paid_nValue)\n",(long long)total_nValue,(long long)(remaining_nValue + paid_nValue),(long long)remaining_nValue,(long long)paid_nValue);
147         return(false);
148     }
149     else if ( orig_assetoshis != (remaining_assetoshis + received_assetoshis) )
150     {
151         fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_assetoshis,(long long)(remaining_assetoshis - received_assetoshis),(long long)remaining_assetoshis,(long long)received_assetoshis);
152         return(false);
153     }
154     else
155     {
156         unitprice = (total_nValue / orig_assetoshis);
157         recvunitprice = (paid_nValue / received_assetoshis);
158         if ( remaining_nValue != 0 )
159             newunitprice = (remaining_nValue / remaining_assetoshis);
160         if ( recvunitprice < unitprice )
161         {
162             fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
163             return(false);
164         }
165         fprintf(stderr,"got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
166     }
167     return(true);
168 }
169
170 bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetoshis2,int64_t orig_assetoshis,int64_t &paid_assetoshis2,int64_t total_assetoshis2)
171 {
172     int64_t remaining_assetoshis; double dunitprice;
173     if ( total_assetoshis2 == 0 )
174     {
175         fprintf(stderr,"total_assetoshis2.0 origsatoshis.%llu paid_assetoshis2.%llu\n",(long long)orig_assetoshis,(long long)paid_assetoshis2);
176         received_assetoshis = remaining_assetoshis2 = paid_assetoshis2 = 0;
177         return(false);
178     }
179     if ( paid_assetoshis2 >= total_assetoshis2 )
180     {
181         paid_assetoshis2 = total_assetoshis2;
182         received_assetoshis = orig_assetoshis;
183         remaining_assetoshis2 = 0;
184         fprintf(stderr,"totally filled!\n");
185         return(true);
186     }
187     remaining_assetoshis2 = (total_assetoshis2 - paid_assetoshis2);
188     dunitprice = ((double)total_assetoshis2 / orig_assetoshis);
189     received_assetoshis = (paid_assetoshis2 / dunitprice);
190     fprintf(stderr,"remaining_assetoshis2 %llu (%llu - %llu)\n",(long long)remaining_assetoshis2/COIN,(long long)total_assetoshis2/COIN,(long long)paid_assetoshis2/COIN);
191     fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
192     if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
193     {
194         remaining_assetoshis = (orig_assetoshis - received_assetoshis);
195         return(ValidateAskRemainder(remaining_assetoshis2,remaining_assetoshis,orig_assetoshis,received_assetoshis,paid_assetoshis2,total_assetoshis2));
196     } else return(false);
197 }
198
199 bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidunits,int64_t totalunits)
200 {
201     int64_t unitprice,recvunitprice,newunitprice=0;
202     if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
203     {
204         fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
205         return(false);
206     }
207     else if ( totalunits != (remaining_price + paidunits) )
208     {
209         fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_price %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_price + paidunits),(long long)remaining_price,(long long)paidunits);
210         return(false);
211     }
212     else if ( orig_nValue != (remaining_nValue + received_nValue) )
213     {
214         fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
215         return(false);
216     }
217     else
218     {
219         unitprice = (orig_nValue * COIN) / totalunits;
220         recvunitprice = (received_nValue * COIN) / paidunits;
221         if ( remaining_price != 0 )
222             newunitprice = (remaining_nValue * COIN) / remaining_price;
223         if ( recvunitprice < unitprice )
224         {
225             fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
226             return(false);
227         }
228         fprintf(stderr,"recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
229     }
230     return(true);
231 }
232
233 CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description)
234 {
235     CScript opret; uint8_t evalcode = EVAL_ASSETS;
236     opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description);
237     return(opret);
238 }
239
240 CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey)
241 {
242     CScript opret; uint8_t evalcode = EVAL_ASSETS;
243     assetid = revuint256(assetid);
244     switch ( funcid )
245     {
246         case 't':  case 'x': case 'o':
247             opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid);
248             break;
249         case 's': case 'b': case 'S': case 'B':
250             opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << price << origpubkey);
251             break;
252         case 'E': case 'e':
253             assetid2 = revuint256(assetid2);
254             opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << assetid2 << price << origpubkey);
255             break;
256         default:
257             fprintf(stderr,"EncodeOpRet: illegal funcid.%02x\n",funcid);
258             opret << OP_RETURN;
259             break;
260     }
261     return(opret);
262 }
263
264 bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description)
265 {
266     std::vector<uint8_t> vopret; uint8_t evalcode,funcid,*script;
267     GetOpReturnData(scriptPubKey, vopret);
268     script = (uint8_t *)vopret.data();
269     if ( script != 0 && vopret.size() > 2 && script[0] == EVAL_ASSETS && script[1] == 'c' )
270     {
271         if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description) != 0 )
272             return(true);
273     }
274     return(0);
275 }
276
277 uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey)
278 {
279     std::vector<uint8_t> vopret; uint8_t funcid=0,*script,e,f;
280     GetOpReturnData(scriptPubKey, vopret);
281     script = (uint8_t *)vopret.data();
282     memset(&assetid,0,sizeof(assetid));
283     memset(&assetid2,0,sizeof(assetid2));
284     price = 0;
285     if ( script != 0 && script[0] == EVAL_ASSETS )
286     {
287         funcid = script[1];
288         //fprintf(stderr,"decode.[%c]\n",funcid);
289         switch ( funcid )
290         {
291             case 'c': return(funcid);
292                 break;
293             case 't':  case 'x': case 'o':
294                 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid) != 0 )
295                 {
296                     assetid = revuint256(assetid);
297                     return(funcid);
298                 }
299                 break;
300             case 's': case 'b': case 'S': case 'B':
301                 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> price; ss >> origpubkey) != 0 )
302                 {
303                     assetid = revuint256(assetid);
304                     //fprintf(stderr,"got price %llu\n",(long long)price);
305                     return(funcid);
306                 }
307                 break;
308             case 'E': case 'e':
309                 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
310                 {
311                     //fprintf(stderr,"got price %llu\n",(long long)price);
312                     assetid = revuint256(assetid);
313                     assetid2 = revuint256(assetid2);
314                     return(funcid);
315                 }
316                 break;
317             default:
318                 fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n",funcid);
319                 funcid = 0;
320                 break;
321         }
322     }
323     return(funcid);
324 }
325
326 bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx)
327 {
328     uint256 assetid,assetid2;
329     if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 )
330         return(true);
331     else return(false);
332 }
333            
334 bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx)
335 {
336     uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector<uint8_t> origpubkey; CScript script;
337     n = tx.vout.size();
338     if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
339         return(false);
340     if ( GetCCaddress(cp,CCaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 )
341         return(true);
342     else return(false);
343 }
344
345 int64_t IsAssetvout(int64_t &price,std::vector<uint8_t> &origpubkey,const CTransaction& tx,int32_t v,uint256 refassetid)
346 {
347     uint256 assetid,assetid2; int64_t nValue=0; int32_t n; uint8_t funcid;
348     if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) // maybe check address too?
349     {
350         n = tx.vout.size();
351         nValue = tx.vout[v].nValue;
352         //fprintf(stderr,"CC vout v.%d of n.%d %.8f\n",v,n,(double)nValue/COIN);
353         if ( v >= n-1 )
354             return(0);
355         if ( (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
356         {
357             fprintf(stderr,"null decodeopret v.%d\n",v);
358             return(0);
359         }
360         else if ( funcid == 'c' )
361         {
362             if ( refassetid == tx.GetHash() && v == 0 )
363                 return(nValue);
364         }
365         else if ( (funcid == 'b' || funcid == 'B') && v == 0 ) // critical! 'b'/'B' vout0 is NOT asset
366             return(0);
367         else if ( funcid != 'E' )
368         {
369             if ( assetid == refassetid )
370                 return(nValue);
371         }
372         else if ( funcid == 'E' )
373         {
374             if ( v < 2 && assetid == refassetid )
375                 return(nValue);
376             else if ( v == 2 && assetid2 == refassetid )
377                 return(nValue);
378         }
379     }
380     //fprintf(stderr,"Isassetvout: normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
381     return(0);
382 }
383
384 int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
385 {
386     uint256 hashBlock; char destaddr[64];
387     origaddr[0] = destaddr[0] = CCaddr[0] = 0;
388     if ( tx.vin.size() < 2 )
389         return eval->Invalid("not enough for CC vins");
390     else if ( tx.vin[vini].prevout.n != 0 )
391         return eval->Invalid("vin1 needs to be buyvin.vout[0]");
392     else if ( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash,vinTx,hashBlock) == 0 )
393     {
394         int32_t z;
395         for (z=31; z>=0; z--)
396             fprintf(stderr,"%02x",((uint8_t *)&tx.vin[vini].prevout.hash)[z]);
397         fprintf(stderr," vini.%d\n",vini);
398         return eval->Invalid("always should find CCvin, but didnt");
399     }
400     else if ( Getscriptaddress(destaddr,vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 )
401     {
402         fprintf(stderr,"%s vs %s\n",destaddr,(char *)cp->unspendableCCaddr);
403         return eval->Invalid("invalid vin AssetsCCaddr");
404     }
405     //else if ( vinTx.vout[0].nValue < 10000 )
406     //    return eval->Invalid("invalid dust for buyvin");
407     else if ( GetAssetorigaddrs(cp,CCaddr,origaddr,vinTx) == 0 )
408         return eval->Invalid("couldnt get origaddr for buyvin");
409     fprintf(stderr,"Got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
410     if ( vinTx.vout[0].nValue == 0 )
411         return eval->Invalid("null value CCvin");
412     return(vinTx.vout[0].nValue);
413 }
414
415 int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid)
416 {
417     CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid;
418     CCaddr[0] = origaddr[0] = 0;
419     if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
420         return(0);
421     else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
422         return eval->Invalid("invalid normal vout0 for buyvin");
423     else
424     {
425         //fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr);
426         if ( vinTx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,assetid,assetid2,tmpprice,tmporigpubkey)) != 'b' && funcid != 'B' )
427             return eval->Invalid("invalid opreturn for buyvin");
428         else if ( refassetid != assetid )
429             return eval->Invalid("invalid assetid for buyvin");
430         //int32_t i; for (i=31; i>=0; i--)
431         //    fprintf(stderr,"%02x",((uint8_t *)&assetid)[i]);
432         //fprintf(stderr," AssetValidateBuyvin assetid for %s\n",origaddr);
433     }
434     return(nValue);
435 }
436
437 int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid)
438 {
439     CTransaction vinTx; int64_t nValue,assetoshis;
440     fprintf(stderr,"AssetValidateSellvin\n");
441     if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
442         return(0);
443     if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,0,assetid)) == 0 )
444         return eval->Invalid("invalid missing CC vout0 for sellvin");
445     else return(assetoshis);
446 }
447
448 bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid)
449 {
450     CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
451     numvins = tx.vin.size();
452     numvouts = tx.vout.size();
453     inputs = outputs = 0;
454     for (i=starti; i<numvins; i++)
455     {
456         if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
457         {
458             if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
459             {
460                 fprintf(stderr,"i.%d starti.%d numvins.%d\n",i,starti,numvins);
461                 return eval->Invalid("always should find vin, but didnt");
462             }
463             else if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 )
464             {
465                 fprintf(stderr,"vin%d %llu, ",i,(long long)assetoshis);
466                 inputs += assetoshis;
467             }
468         }
469     }
470     for (i=0; i<numvouts; i++)
471     {
472         if ( (assetoshis= IsAssetvout(tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
473         {
474             fprintf(stderr,"vout%d %llu, ",i,(long long)assetoshis);
475             outputs += assetoshis;
476         }
477     }
478     if ( inputs != outputs )
479     {
480         fprintf(stderr,"inputs %.8f vs %.8f outputs\n",(double)inputs/COIN,(double)outputs/COIN);
481         return(false);
482     }
483     else return(true);
484 }
This page took 0.087964 seconds and 4 git commands to generate.