Skip to content

Commit

Permalink
Merge pull request swanchain#15 from swanchain/feature/new-provider-p…
Browse files Browse the repository at this point in the history
…ayments

Feature/new provider payments
  • Loading branch information
PlutoNbai authored Feb 5, 2024
2 parents 531c463 + 783188d commit b1e90e7
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 38 deletions.
6 changes: 6 additions & 0 deletions backend/model/provider_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def create_provider_payment(
def get_by_owner_address(wallet_address):
return ProviderPayment.query.filter_by(
provider_owner_address=wallet_address
).order_by(ProviderPayment.provider_owner_address.desc()).all()

def get_all_provider_payments():
return ProviderPayment.query.filter_by(
status="pending_reward"
).all()

def get_by_order_id(order_id):
Expand All @@ -96,5 +101,6 @@ def get_by_job_and_wallet(wallet_address, job_id):
def mark_claimed(payment, tx_hash=None):
payment.transaction_hash = tx_hash
payment.claimed = True
payment.status = "rewardSet"

return update_record(payment, db.session)
3 changes: 2 additions & 1 deletion backend/model/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Task(db.Model):
end_at = db.Column(db.String(64))
created_at = db.Column(db.String(64))
updated_at = db.Column(db.String(64))
refund_wallet = db.Column(db.String(255))

def to_dict(self):
return {
Expand All @@ -28,7 +29,7 @@ def to_dict(self):
"task_detail_cid": self.task_detail_cid,
"created_at": self.created_at,
"updated_at": self.updated_at,
"end_at": self.end_at,
"end_at": self.end_at
}

def get_task_by_uuid(uuid):
Expand Down
4 changes: 3 additions & 1 deletion backend/router/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ def login():
if signer == public_address:

user: User = User.get_user_by_address(public_address)
api_token = None
if user:
logging.info("[+] Found user " + user.public_address)
api_token = ApiToken.query.filter_by(user_id=user.id).first()
else:
user = User(public_address=public_address)
db.session.add(user)
Expand All @@ -50,7 +52,7 @@ def login():

access_token = create_access_token(identity=public_address)

resp = jsonify(access_token=access_token)
resp = jsonify(access_token=access_token, api_token=api_token.token if api_token else None)
return resp, 200


Expand Down
4 changes: 2 additions & 2 deletions backend/router/deploy_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ def deploy_with_space_url():
response.status = constant.STATUS_SUCCESS
return jsonify(response.to_dict()), HTTPStatus.OK
except Exception as err:
# Return Internal Error if any issue comesup
# Return Internal Error if any issue comes up
# TODO: FIX
logging.info(
f"Error during Task generation Error: {str(err)} {traceback.format_exc()}"
)
response.message = "Error during task_uuid generation."
response.status = "error"
response.status = constant.STATUS_FAILED
return jsonify(response.to_dict()), HTTPStatus.INTERNAL_SERVER_ERROR


Expand Down
28 changes: 16 additions & 12 deletions backend/router/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from http import HTTPStatus

from flask import jsonify, Blueprint, request
from flask_jwt_extended import jwt_required

from backend.middleware.token_service import jwt_or_api_token_required, get_jwt_identity
from backend.middleware.token_service import jwt_or_api_token_required, get_jwt_identity, jwt_or_api_token_required2
from backend.model.response import Response
from backend.model.user import User
from backend.service import user_service
Expand Down Expand Up @@ -59,8 +60,8 @@ def claim_provider_payment():


@user_bp.route("/provider/payments", methods=["GET"])
@jwt_or_api_token_required
def check_provider_payment():
@jwt_or_api_token_required2
def check_provider_payment(user):
"""
Claim a provider payment associated with the user.
Expand All @@ -72,30 +73,33 @@ def check_provider_payment():
"""
response = Response(constant.STATUS_FAILED)
response.data = {"payments": []}
limit = 10
if request.args.get("limit") is not None and request.args.get("limit").isdigit():
limit = int(request.args.get("limit"))

offset = 0
if request.args.get("offset") is not None and request.args.get("offset").isdigit():
offset = int(request.args.get("offset"))
user = User.get_user_by_address(get_jwt_identity())
# limit = 10
# if request.args.get("limit") is not None and request.args.get("limit").isdigit():
# limit = int(request.args.get("limit"))
#
# offset = 0
# if request.args.get("offset") is not None and request.args.get("offset").isdigit():
# offset = int(request.args.get("offset"))
if user is None:
response.message = "User not found"
response.status = constant.STATUS_FAILED
return jsonify(response.to_dict()), 200
payments = user_service.get_user_provider_payments(user, limit, offset)
# payments = user_service.get_user_provider_payments(user, limit, offset)
payments = user_service.get_user_provider_payment_after_saturn(user)
if payments is None:
response.message = "No payments found"
response.status = constant.SUCCESS
return jsonify(response.to_dict()), 200
else:
for payment in payments:
response.data["payments"].append(payment.to_dict())
# 倒叙返回response.data["payments"]
response.data["payments"] = response.data["payments"][::-1]
response.message = "successfully retrieved payments"
response.status = constant.STATUS_SUCCESS
return jsonify(response.to_dict()), 200


@user_bp.route("/jwt_info", methods=["GET"])
@jwt_or_api_token_required
def check_wallet_address():
Expand Down
33 changes: 27 additions & 6 deletions backend/router/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from flask import jsonify, Blueprint, request
from sqlalchemy.exc import DatabaseError, OperationalError

from backend.middleware.token_service import jwt_or_api_token_required
from backend.middleware.token_service import jwt_or_api_token_required, jwt_or_api_token_required2
from backend.model import db
from backend.model.common import update_record
from backend.model.computing_provider import ComputingProvider
Expand All @@ -20,7 +20,8 @@
from backend.service import space_service
# Internal models
from backend.service.space_service import get_payment_info
from backend.service.computing_provider_service import get_balance, get_task_collateral_balance
from backend.service.computing_provider_service import get_balance, get_task_collateral_balance, get_contract_end_time
from backend.service.user_service import get_user_by_address
from backend.utils import constant

validate_bp = Blueprint("validate_bp", __name__)
Expand Down Expand Up @@ -184,12 +185,12 @@ def claim_review():

@validate_bp.route("/terminate_task", methods=["POST"])
@jwt_or_api_token_required
def task_refund():
def task_termination():
"""
Desc:
Post request which takes in form data:
task_uuid(str): The task which is being terminated
refund_wallet(str): which user will receieve the refund
refund_wallet(str): which user will receive the refund
Returns:
Success/failed if the termination of the task succeeded or not
"""
Expand Down Expand Up @@ -224,6 +225,10 @@ def task_refund():
response.message = "Task is not started yet"
return jsonify(response.to_dict()), 200

# Update task refund wallet
task.refund_wallet = refund_wallet
task = update_record(task, db.session)

# check if jobs are CANCELLED OR CANCELLED FAILED
jobs = Job.get_all_jobs_by_task_uuid(task_uuid)
cancel_status = None
Expand All @@ -247,9 +252,19 @@ def task_refund():
if cancel_status:
# First time try release collateral
try:
# Set User
txn_hash = space_service.set_user(refund_wallet, task_uuid)
if txn_hash is None:
task.status = constant.SET_USER_FAILED
task = update_record(task, db.session)
response.message = "Set user failed on contract side"
response.status = constant.SUCCESS
return jsonify(response.to_dict()), 200
# Update end_time on contract side
txn_hash = space_service.update_end_time(task_uuid, task.end_at)
if txn_hash is None:
task.status = constant.UPDATE_END_TIME_FAILED
task = update_record(task, db.session)
response.message = (
"Task has been terminate on CP side, but the Txn hash is None, update end time failed "
"on contract side")
Expand All @@ -259,6 +274,8 @@ def task_refund():

txn_hash = space_service.unlock_collateral(task_uuid)
if txn_hash is None:
task.status = constant.COLLATERAL_NOT_RELEASED
task = update_record(task, db.session)
response.message = ("Txn hash is None, unlock collateral failed "
"on contract side")
response.status = constant.SUCCESS
Expand All @@ -271,9 +288,13 @@ def task_refund():

# Update status for scheduler if collateral balance is not released
collateral_balance = get_task_collateral_balance(task_uuid)
logging.info(f"Collateral balance for task {task_uuid} is {collateral_balance}, {collateral_balance == 0}")
if collateral_balance == 0:
task.status = constant.CAN_BE_CLAIMED
task.status = constant.COLLATERAL_RELEASED
end_at_time = get_contract_end_time(task_uuid)
if end_at_time != 0:
task.status = constant.CAN_BE_CLAIMED
else:
task.status = constant.UPDATE_END_TIME_FAILED
else:
task.status = constant.COLLATERAL_NOT_RELEASED
task = update_record(task, db.session)
Expand Down
11 changes: 11 additions & 0 deletions backend/service/computing_provider_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,17 @@ def get_task_collateral_balance(task_uuid):
return balance


def get_contract_end_time(task_uuid):
chain_id = "2024"
try:
w3, task_contract_address, task_contract, tx_config = verify_task_contract_address(chain_id, task_uuid)
except Exception as e:
logging.error(f"Error occurred when getting task contact: {str(e)}")
return None
end_time = task_contract.functions.endTime().call()
return end_time


def extend_job(duration, bidder_id, task_uuid, job):
cp = ComputingProvider.query.filter_by(node_id=bidder_id).first()
uri = multiaddress_to_url(cp.multi_address, constant.EXTEND_JOB)
Expand Down
31 changes: 17 additions & 14 deletions backend/service/space_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,20 +291,6 @@ def check_space_deployment_requests(space):
logging.error(error_msg)


# def cancel_all_spaces_running_jobs(space):
# if space.task_uuid is None:
# Exception("Cancelling a space that is not currently running")
#
# jobs = Job.get_all_jobs_by_task_uuid(space.task_uuid)
# for job in jobs:
# if job.status != constant.JOB_RUNNING:
# continue
# job = cancel_space_job_and_task(job, space)
# # Job is now complete
# if job.status == constant.JOB_CANCELLED:
# Job.complete_job(job)


def save_space_config_order(config, duration, region, start_in, order_type=None):
cfg = ConfigOrder.create_config_order(
config.id, duration, region, start_in, order_type
Expand Down Expand Up @@ -645,6 +631,23 @@ def unlock_collateral(task_uuid):
return tx_hash.hex()


def set_user(wallet_address, task_uuid):
logging.info("--------------------setting user-------------------")
chain_id = "2024"
try:
w3, task_contract_address, task_contract, tx_config = verify_task_contract_address(chain_id, task_uuid)
except Exception as e:
logging.error(f"Error occurred when getting task contact: {str(e)}")
return None
tx = task_contract.functions.setUser(wallet_address).build_transaction(
tx_config
)
signed_tx = w3.eth.account.sign_transaction(tx, PRIVATE_ADDRESS)
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
return tx_hash.hex()


def get_leading_cp(task_uuid):
chain_id = "2024"
try:
Expand Down
11 changes: 9 additions & 2 deletions backend/service/user_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@ def user_has_role(user, role_name):
return role_name in roles


def get_user_provider_payments(user, limit, offset):
return ProviderPayment.get_by_owner_address(user.public_address).limit(limit).offset(offset).all()
def get_user_provider_payments(user):
return ProviderPayment.get_by_owner_address(user.public_address)


def get_user_provider_payment_after_saturn(user):
return ProviderPayment.query.filter(
ProviderPayment.provider_owner_address == user.public_address,
ProviderPayment.created_at > 1705986000
).order_by(ProviderPayment.provider_owner_address.desc()).all()


def mark_payment_as_refunded(tx_hash, chain_id, user):
Expand Down
3 changes: 3 additions & 0 deletions backend/utils/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@
COLLATERAL_RELEASED = "collateral_released"
CAN_BE_CLAIMED = "can_be_claimed"
TASK_CANCEL_FAILED = "cancel_failed"
SET_USER_FAILED = "set_user_failed"
UPDATE_END_TIME_FAILED = "update_end_time_failed"


# Refund status
NON_REFUNDABLE = "Non-refundable"
Expand Down
13 changes: 13 additions & 0 deletions contracts/abi/Task.json
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "userAddress",
"type": "address"
}
],
"name": "setUser",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "startTime",
Expand Down
Loading

0 comments on commit b1e90e7

Please sign in to comment.