agent-backend/contracts/Incentives/Incentives.yjs
2021-09-26 12:49:24 +08:00

359 lines
12 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import "loadResource.yjs"
@LogType("Arg")
contract Incentives{
export function getMainFrame(arg){
return "/html/main.html";
}
function onCreate(arg) {
Global.owner = requester;
Global.bids = [];
Global.asks = [];
Global.listFinal = [];
Global.status = "Bidding";
}
export function getOwner(arg) {
return Global.owner;
}
export function isOwner(arg) {
return requester==Global.owner;
}
export function getStatus(arg) {
return Global.status;
}
export function getAskListRW(arg) {
var retList = [];
for (var i = 0; i < Global.asks.length; i++) {
var ask = {};
ask["item"] = Global.asks[i]["item"];
if (Global.asks[i]["seller"] == requester) {
ask["seller"] = Global.asks[i]["seller"];
ask["price"] = Global.asks[i]["price"];
} else {
ask["seller"] = "Anonymous";
ask["price"] = "Unknown";
}
retList.push(ask);
}
return JSON.stringify(retList);
}
export function getAskListRO(arg) {
if (requester != Global.owner) {
return "Access Denied";
}
return JSON.stringify(Global.asks);
}
export function getBidListAll(arg) {
if (requester != Global.owner) {
return "Access Denied";
}
return JSON.stringify(Global.bids);
}
export function getBidListPrivate(arg) {
var retList = [];
for (var i = 0; i < Global.bids.length; i++) {
if (Global.bids[i]["bidder"]==requester) {
retList.push(Global.bids[i]);
}
}
return JSON.stringify(retList);
}
export function bid(arg) {//每个args的格式是{"bidder":"","item":""} item资源编号bidder买方
var args = JSON.parse(arg);
args["bidder"] = requester; //从外界引入bidder的编号
return bidHelper(args);
}
function bidHelper(args){
if (Global.status != "Bidding") {
return "Not in bidding status!";
}
var asks = findAllElements(Global.asks, "item", args["item"]);
if (asks.length == 0) {
return "No such item exists!";
}
for (var i = 0; i< Global.bids.length; i++) {
if (Global.bids[i]["bidder"]==args["bidder"] && Global.bids[i]["item"]==args["item"]) {
return "A valid bid already exists"; //这个已经存在买方购买该资源的信息
}
}
Global.bids.push(args); //没有已存在就可以将这个信息加入global.bids
return "Success";
}
export function ask(arg) { //每个args的格式是{"seller":"","item":""} item资源编号seller卖方
var args = JSON.parse(arg);
args["seller"] = requester;
return askHelper(args);
}
function askHelper(args){
if (Global.status != "Bidding") {
return "Not in bidding status";
}
for (var i = 0; i< Global.asks.length; i++) {
if (Global.asks[i]["item"]==args["item"]) {
return "A valid ask already exists"; //已经存在卖方提供该资源的信息
}
}
Global.asks.push(args); //没有已存在就可以将这个信息加入Global.asks
return "Success";
}
export function match(arg) {
if (Global.status != "Bidding") {
return "Not in bidding status";
}
if (requester != Global.owner) {
return "Access Denied";
}
if (Global.bids.length == 0 || Global.asks.length == 0) {
return "Must have at least 1 resource and 1 bid!";
}
// Algorithm 2 winning candidates determination
// sort bids and asks
sortObjectArray(Global.bids,"price",false); //买方按照价格降序跑列
sortObjectArray(Global.asks,"price",true); //卖方升序排列
// calculate threshold value
var thrPos = Math.ceil((Global.asks.length+1.0)/2.0); //取中位数beta
var askThrValue = Global.asks[thrPos-1]["price"]; //卖方的阈值
// get candidates according to the threshold value
var candidateBidsTmp = [];
for (var i = 0; i < Global.bids.length; i++) {
if (Global.bids[i]["price"] >= askThrValue) { //取大于等于卖方阈值的所有买方价格
candidateBidsTmp.push(Global.bids[i]); //candidateBidsTmp大于等于卖方阈值价格的买方价格
} else {
break;
}
}
var bidThrValue = candidateBidsTmp[candidateBidsTmp.length-1]["price"]; //取买方的阈值最低价
// get rid of impossible candidates踢出不可能的candidates
var candidateAsks = [];
var candidateBids = [];
for (var i=0; i<candidateBidsTmp.length; i++) {
var askList = findAllElements(Global.asks, "item", candidateBidsTmp[i]["item"]);
//在global.asks中的找到提供该资源的所有卖方
if (askList.length == 1 && askList[0]["price"] < askThrValue) {
//如果只有一个卖方提供该资源且卖方提供的资源价格小于卖方阈值
candidateBids.push(candidateBidsTmp[i]); //那么这个买方就可能可以拥有这个资源匹配加入candidateBids插入顺序也是按照价格降序排列的
var cAskList = findAllElements(candidateAsks, "item", candidateBidsTmp[i]["item"]);
//在candidateAsks中找到提供这个资源的所有卖方
if (cAskList.length == 0) {
//如果还没有加入提供该资源的卖方那么就加入candidateAsks就是说这个卖方可能可以卖出这个资源
candidateAsks.push(askList[0]);
}
}
}
// Algorithm 3 assignment and pricing
var matchedList = [];
for (var i=0; i<candidateAsks.length; i++) {
var record = {};
record["used"] = false;
record["result"] = "N/A";
record["item"] = candidateAsks[i]["item"];
record["seller"] = candidateAsks[i]["seller"];
record["sellerPrice"] = askThrValue;
var bids = findAllElements(candidateBids, "item", candidateAsks[i]["item"]);
//在匹配的买方中找到给该资源报价的所有买方
record["bidder"] = bids[0]["bidder"];
if (bids.length == 1) {
//如果只有一个买方报价
record["bidderPrice"] = bidThrValue;
//将成交价格设定为买方的阈值价格
} else {
record["bidderPrice"] = bids[1]["price"];
//如果有至少两个报价,那么按照次价格设定成交价
}
matchedList.push(record);
}
// Algorithm 4 winner elimination
var listFinal = [];
for (var i=0; i<matchedList.length; i++) {
var finalRecordList = findAllElements(listFinal, "bidder", matchedList[i]["bidder"]);
if (finalRecordList.length != 0) {
break; //如果listFinal中已经存在这个买方了就break
}
var matches = findAllElements(matchedList, "bidder", matchedList[i]["bidder"]);
//找到和同个买方的所有情况
if (matches.length == 1) { //没有同个买方多个匹配结果直接加入listFinal
listFinal.push(matches[0]);
} else {
//如果有同个买方多个匹配结果
var utilities = [];
for (var j = 0; j < matches.length; j++) {
var bidPrice = findAllElements(
findAllElements(Global.bids, "bidder", matches[j]["bidder"]),
"item", matches[j]["item"])[0]["price"];
//同个买方同个资源的最初报价
var finalPrice = matches[j]["bidderPrice"]; //成交报价
utilities.push(bidPrice-finalPrice); //效用
}
var maxU = Number.MIN_VALUE;
var maxUIndex = -1;
for (var j = 0; j < utilities.length; j++) {
if (utilities[j] > maxU) {
maxU = utilities[j];
maxUIndex = j;
}
}
listFinal.push(matches[maxUIndex]);
}
}
Global.listFinal = listFinal;
Global.status = "Finalized";
return "Success";
}
@Cost({"countGas":true,"extraGas":"getFinalPrice"})
export function execute(arg) {
if (Global.status != "Finalized") {
return "Bidding has not been finalized!"
}
var args = JSON.parse(arg);
var winningBid = false;
for (var i=0; i < Global.listFinal.length; i++) {
if (Global.listFinal[i]["used"]) {
continue;
}
if (Global.listFinal[i]["item"]==args["item"] && Global.listFinal[i]["bidder"]==requester) {
winningBid = true;
Global.listFinal[i]["used"] = true;
Global.listFinal[i]["result"] = "Success";
break;
}
}
if (!winningBid) {
return "Access Denied";
}
print(args["item"] + " used by " + requester);
return "Success";
}
export function getFinalPrice(arg) {
var args = JSON.parse(arg);
var winningPrice = 0;
for (var i=0; i < Global.listFinal.length; i++) {
if (Global.listFinal[i]["item"]==args["item"] && Global.listFinal[i]["bidder"]==requester) {
winningPrice = Global.listFinal[i]["bidderPrice"];
break;
}
}
return winningPrice;
}
export function resetStatus(arg) {
if (requester != Global.owner) {
return "Access Denied"
}
Global.bids = [];
Global.asks = [];
Global.listFinal = [];
Global.status = "Bidding";
return "Success";
}
function sortObjectArray(arr, prop, isAsc) {
//数组arr按照属性prp的值升序/降序排列
if (isAsc) {
for (var a=0; a < arr.length; a++) {
for (var b=0; b < arr.length-1-a; b++) {
if (arr[b][prop] > arr[b+1][prop]) {
var tmp = arr[b];
arr[b] = arr[b+1];
arr[b+1] = tmp;
}
}
}
} else {
for (var a=0; a < arr.length; a++) {
for (var b=0; b < arr.length-1-a; b++) {
if (arr[b][prop] < arr[b+1][prop]) {
var tmp = arr[b];
arr[b] = arr[b+1];
arr[b+1] = tmp;
}
}
}
}
return arr;
}
function findAllElements(arr, prop, value) {
//找到arr的prop属性等于value的所有元素
var newArr = [];
for (var a = 0; a < arr.length; a++) {
if (arr[a][prop] == value) {
newArr.push(arr[a]);
}
}
return newArr;
}
export function getFinalListOwner(arg) {
if (requester != Global.owner) {
return "Access Denied";
}
var retList = [];
for (var i = 0; i < Global.listFinal.length; i++) {
var fin = {};
fin["item"] = Global.listFinal[i]["item"];
fin["seller"] = Global.listFinal[i]["seller"];
fin["bidder"] = Global.listFinal[i]["bidder"];
fin["sellerPrice"] = Global.listFinal[i]["sellerPrice"];
fin["bidderPrice"] = Global.listFinal[i]["bidderPrice"];
fin["used"] = Global.listFinal[i]["used"];
fin["result"] = "Unknown";
retList.push(fin);
}
return JSON.stringify(retList);
}
export function getFinalListPrivate(arg) {
var retList = [];
for (var i = 0; i < Global.listFinal.length; i++) {
var fin = {};
fin["item"] = Global.listFinal[i]["item"];
fin["used"] = Global.listFinal[i]["used"];
if (Global.bids[i]["bidder"]==requester && Global.bids[i]["seller"]==requester) {
fin["seller"] = Global.listFinal[i]["seller"];
fin["bidder"] = Global.listFinal[i]["bidder"];
fin["sellerPrice"] = Global.listFinal[i]["sellerPrice"];
fin["bidderPrice"] = Global.listFinal[i]["bidderPrice"];
fin["result"] = Global.listFinal[i]["result"];
fin["canExecute"] = true;
retList.push(fin);
fin["result"] = Global.listFinal[i]["result"];
} else if (Global.bids[i]["bidder"]==requester) {
fin["seller"] = "Anonymous";
fin["bidder"] = Global.listFinal[i]["bidder"];
fin["sellerPrice"] = "Unknown";
fin["bidderPrice"] = Global.listFinal[i]["bidderPrice"];
fin["result"] = Global.listFinal[i]["result"];
fin["canExecute"] = true;
retList.push(fin);
} else if (Global.bids[i]["seller"]==requester) {
fin["seller"] = Global.listFinal[i]["seller"];
fin["bidder"] = "Anonymous";
fin["sellerPrice"] = Global.listFinal[i]["sellerPrice"];
fin["bidderPrice"] = "Unknown";
fin["result"] = "Unknown";
fin["canExecute"] = false;
retList.push(fin);
}
}
return JSON.stringify(retList);
}
}