-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathblockchain-transaction.service.ts
115 lines (106 loc) · 5.86 KB
/
blockchain-transaction.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {Injectable, OnInit} from '@angular/core';
import {P2PBid} from './data-types/P2PBid';
import {BCTransaction} from './data-types/BCTransaction';
import { Subject} from 'rxjs';
import {TimeService} from './time.service';
import {P2PMarketDesign} from './data-types/P2PMarketDesign';
import {MockEDMService} from './mock-edm.service';
import {DataProvisionService} from './data-provision.service';
import {ExperimentStateService} from './experiment-state.service';
import {BidValidationService} from './bid-validation.service';
import {TransactionClearingService} from './transaction-clearing.service';
import {ProsumerInstance} from './data-types/ProsumerInstance';
@Injectable({
providedIn: 'root'
})
/**
* The service facilitate the transactions for the blockchain.
* Represents the binding element of the Angular/UI world and the blockchain it uses.
* Encapsulates all functionality related with the blockchain layer within the LabChain project
*/
export class BlockchainTransactionService {
/** Variable to keep track of the ID for the next free bid to avoid ID collisions */
private freeBidId = 5;
/** Variable to track the bids that an other actor committed to */
private committedBids: P2PBid[] = [];
/** Variable to track the bids no actor committed to yet */
private openBids: P2PBid[];
/** Subject to emit the committed bids once their state changes in order to update the observers */
public committedBidSubject: Subject<P2PBid> = new Subject<P2PBid>();
/** Subject to emit the open bids once their state changes in order to update the observers */
public openBidSubject: Subject<P2PBid[]> = new Subject<P2PBid[]>();
/** Array to keep track of all transactions sent to the blockchain layer as the respective data type */
private transactions: BCTransaction[] = [];
/** Reference to the respective market design of the context the service is used in */
private p2pMarketDesign: P2PMarketDesign;
constructor(private timeService: TimeService,
private edmService: MockEDMService,
private state: ExperimentStateService,
private data: DataProvisionService,
private bvs: BidValidationService,
private tcs: TransactionClearingService) {
// TODO remove mock bids from this
this.openBids = this.data.getMockBids();
// subscribe to the time service and filter out the expired bid after every update
this.timeService.timeEmitter.subscribe(currentTime => {
// Filter out expired bids
this.openBids = this.openBids.filter(currentBid => ((this.timeService.getCurrentTime() + this.p2pMarketDesign.bidClosure) > currentBid.deliveryTime));
// After updating the open bids, inform the oberservers about the remaining open bids
this.openBidSubject.next(this.openBids);
});
// Set the P2PMarketDesign as soon as it is available
DataProvisionService.getP2PMarketDescription(state.experimentID).subscribe(p2pMarketDesign => this.p2pMarketDesign = p2pMarketDesign);
}
/**
* Method to commit to (accept) an open bid by an interested actor.
* Adds the respective transaction to the blockchain, and does the respective housekeeping updating the open and committed bids stored in this service as well as informing the respective observers
*
* @param buyer The prosumer that committed to the bid
* @param timeOfPurchase The point in the simulation that the prosumer purchased the electricity / committed to the bid
* @param committedBid The bid the buyer is committing to
* @returns true if this was successful, false if anything out of the ordinary happened, and the bid could not be committed to
*/
public commitToP2PBid(buyer: ProsumerInstance, timeOfPurchase: number, committedBid: P2PBid): boolean {
this.transactions.push({author: buyer, p2pbid: committedBid, timestamp: timeOfPurchase});
this.committedBids.push(committedBid);
this.committedBidSubject.next(committedBid);
console.log(this.openBids.length);
this.openBids = (this.openBids.slice(0, this.openBids.indexOf(committedBid)).concat(this.openBids.slice(this.openBids.indexOf(committedBid) + 1, this.openBids.length)));
console.log(this.openBids.length);
this.openBidSubject.next(this.openBids);
console.log(this.transactions);
console.log(this.committedBids);
// TODO Think about whether this should be timed somewhere else
this.tcs.clearBidCommitment(buyer, timeOfPurchase, committedBid, this.p2pMarketDesign.feeAmount);
// TODO think about what could go wrong
return true;
}
public getCommitedBids(): P2PBid[] { return this.committedBids; }
public getOpenBids(): P2PBid[] { return this.openBids; }
/**
* Returns the latest unused free bid and increases it for the next bid (in linear fashion) beting able to be used
*
* @returns a probably unused bidID, as long as bid IDs are assigned linearly; will not check whether the returned ID is already used by another bid
*/
getUnusedBidId(): number {
return ++this.freeBidId;
}
// TODO think about whether this should check whether the prosumer could in theory provide the energy (e.g. via the residual load information) or whether extensive trading is allowed (and what happens upon non-delivery)
/**
* Method to submit a bid to the blockchain layer as an open bid.
* Requires the bid to not have been committed before (i.e. not be in the list of open or committed bids) and to be valid.
* Will otherwise not be successful.
*
* @param bid The bid to be committed to the blockchain
* @returns Returns true if the bid has not been committed before and to be valid
*/
submitBid(bid: P2PBid): boolean {
if (((this.openBids.indexOf(bid) === - 1) && (this.committedBids.indexOf(bid) === - 1)) && this.bvs.checkBidValidity(bid)) {
this.openBids.push(bid);
this.openBidSubject.next(this.openBids);
return true;
} else {
return false;
}
}
}