Skip to content

Commit 8b71361

Browse files
authored
Merge pull request #151 from livepeer/yf/transcoder-self-bonded
Enforce transcoders to be self-bonded
2 parents fa776b1 + dd0c9d4 commit 8b71361

File tree

4 files changed

+59
-63
lines changed

4 files changed

+59
-63
lines changed

contracts/bonding/BondingManager.sol

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,17 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {
170170
// Fee share must be a valid percentage
171171
require(MathUtils.validPerc(_feeShare));
172172

173+
Delegator storage del = delegators[msg.sender];
174+
175+
// Must have a non-zero amount bonded to self
176+
require(del.delegateAddress == msg.sender && del.bondedAmount > 0);
177+
173178
Transcoder storage t = transcoders[msg.sender];
174179
t.pendingBlockRewardCut = _blockRewardCut;
175180
t.pendingFeeShare = _feeShare;
176181
t.pendingPricePerSegment = _pricePerSegment;
177182

178-
uint256 delegatedAmount = delegators[msg.sender].delegatedAmount;
183+
uint256 delegatedAmount = del.delegatedAmount;
179184

180185
// Check if transcoder is not already registered
181186
if (transcoderStatus(msg.sender) == TranscoderStatus.NotRegistered) {
@@ -197,29 +202,6 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {
197202
TranscoderUpdate(msg.sender, _blockRewardCut, _feeShare, _pricePerSegment);
198203
}
199204

200-
/*
201-
* @dev Remove the sender as a transcoder
202-
*/
203-
function resignAsTranscoder()
204-
external
205-
whenSystemNotPaused
206-
currentRoundInitialized
207-
{
208-
// Sender must be registered transcoder
209-
require(transcoderStatus(msg.sender) == TranscoderStatus.Registered);
210-
211-
uint256 currentRound = roundsManager().currentRound();
212-
if (activeTranscoderSet[currentRound].isActive[msg.sender]) {
213-
// If transcoder is active for the round set it as inactive
214-
activeTranscoderSet[currentRound].isActive[msg.sender] = false;
215-
}
216-
217-
// Remove transcoder from pools
218-
transcoderPool.remove(msg.sender);
219-
220-
TranscoderResigned(msg.sender);
221-
}
222-
223205
/**
224206
* @dev Delegate stake towards a specific address.
225207
* @param _amount The amount of LPT to stake.
@@ -316,12 +298,18 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {
316298
transcoderPool.updateKey(del.delegateAddress, transcoderPool.getKey(del.delegateAddress).sub(del.bondedAmount), address(0), address(0));
317299
}
318300

319-
Unbond(del.delegateAddress, msg.sender);
320-
321301
// Delegator no longer bonded to anyone
322302
del.delegateAddress = address(0);
323303
// Unbonding delegator does not have a start round
324304
del.startRound = 0;
305+
306+
// If caller is a registered transcoder, resign
307+
// In the future, with partial unbonding there would be a check for 0 bonded stake as well
308+
if (transcoderStatus(msg.sender) == TranscoderStatus.Registered) {
309+
resignTranscoder(msg.sender);
310+
}
311+
312+
Unbond(del.delegateAddress, msg.sender);
325313
}
326314

327315
/**
@@ -804,6 +792,22 @@ contract BondingManager is ManagerProxyTarget, IBondingManager {
804792
return activeTranscoderSet[_round].isActive[_transcoder];
805793
}
806794

795+
/*
796+
* @dev Remove transcoder
797+
*/
798+
function resignTranscoder(address _transcoder) internal {
799+
uint256 currentRound = roundsManager().currentRound();
800+
if (activeTranscoderSet[currentRound].isActive[_transcoder]) {
801+
// If transcoder is active for the round set it as inactive
802+
activeTranscoderSet[currentRound].isActive[_transcoder] = false;
803+
}
804+
805+
// Remove transcoder from pools
806+
transcoderPool.remove(_transcoder);
807+
808+
TranscoderResigned(_transcoder);
809+
}
810+
807811
/*
808812
* @dev Update a transcoder with rewards
809813
* @param _transcoder Address of transcoder

contracts/jobs/JobsManager.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,6 @@ contract JobsManager is ManagerProxyTarget, IVerifiable, IJobsManager {
391391
// Sender must be elected transcoder
392392
require(job.transcoderAddress == msg.sender);
393393

394-
uint256 blockNum = roundsManager().blockNum();
395394
uint256 challengeBlock = claim.claimBlock + 1;
396395
// Segment must be eligible for verification
397396
// roundsManager().blockHash() ensures that the challenge block is within the last 256 blocks from the current block

contracts/test/GenericMock.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ contract GenericMock {
2525
* @param _data Transaction data to be used to call the target contract
2626
*/
2727
function execute(address _target, bytes _data) external returns (bool) {
28-
// solium-disable security/no-low-level-calls
28+
// solium-disable-next-line security/no-low-level-calls
2929
return _target.call(_data);
3030
}
3131

test/unit/BondingManager.js

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,18 @@ contract("BondingManager", accounts => {
5757
await expectThrow(bondingManager.transcoder(blockRewardCut, feeShare, pricePerSegment), {from: tAddr})
5858
})
5959

60-
it("should fail with zero delegated amount", async () => {
60+
it("should fail if transcoder is not bonded to self", async () => {
61+
await fixture.token.setApproved(true)
62+
await bondingManager.bond(2000, tAddr, {from: accounts[2]})
63+
64+
// Fails because transcoder has non zero delegated stake but is not bonded to self
65+
await expectThrow(bondingManager.transcoder(blockRewardCut, feeShare, pricePerSegment), {from: tAddr})
66+
})
67+
68+
it("should fail if transcoder does not have a non-zero amount bonded to self", async () => {
69+
await bondingManager.bond(0, tAddr, {from: tAddr})
70+
71+
// Fails because transcoder is delegated to self but has zero bonded stake
6172
await expectThrow(bondingManager.transcoder(blockRewardCut, feeShare, pricePerSegment), {from: tAddr})
6273
})
6374

@@ -105,38 +116,6 @@ contract("BondingManager", accounts => {
105116
})
106117
})
107118

108-
describe("resignAsTranscoder", () => {
109-
const tAddr = accounts[1]
110-
111-
beforeEach(async () => {
112-
const blockRewardCut = 10 * PERC_MULTIPLIER
113-
const feeShare = 5 * PERC_MULTIPLIER
114-
const pricePerSegment = 100
115-
116-
await bondingManager.setParameters(UNBONDING_PERIOD, NUM_TRANSCODERS, NUM_ACTIVE_TRANSCODERS)
117-
118-
await fixture.roundsManager.setCurrentRoundInitialized(true)
119-
await fixture.token.setApproved(true)
120-
await bondingManager.bond(2000, tAddr, {from: tAddr})
121-
await bondingManager.transcoder(blockRewardCut, feeShare, pricePerSegment, {from: tAddr})
122-
})
123-
124-
it("should throw if transcoder is not registered", async () => {
125-
await expectThrow(bondingManager.resignAsTranscoder({from: accounts[2]}))
126-
})
127-
128-
it("should remove the transcoder from the transcoder pools", async () => {
129-
await bondingManager.resignAsTranscoder({from: tAddr})
130-
assert.equal(await bondingManager.transcoderStatus(tAddr), 0, "transcoder not removed from pool")
131-
})
132-
133-
it("should set a transcoder as not registered", async () => {
134-
await bondingManager.resignAsTranscoder({from: tAddr})
135-
const transcoderStatus = await bondingManager.transcoderStatus(tAddr)
136-
assert.equal(transcoderStatus, 0, "transcoder is not not registered")
137-
})
138-
})
139-
140119
describe("bond", () => {
141120
const tAddr0 = accounts[1]
142121
const tAddr1 = accounts[2]
@@ -599,10 +578,10 @@ contract("BondingManager", accounts => {
599578
// Delegator bonds to transcoder
600579
await bondingManager.bond(2000, tAddr, {from: dAddr})
601580

602-
// Set active transcoders
603-
await fixture.roundsManager.initializeRound()
604581
// Set current round so delegator is bonded
605582
await fixture.roundsManager.setCurrentRound(currentRound)
583+
// Set active transcoders
584+
await fixture.roundsManager.initializeRound()
606585
})
607586

608587
it("should set withdraw round to current block + unbonding period", async () => {
@@ -642,6 +621,20 @@ contract("BondingManager", accounts => {
642621

643622
assert.equal(startDelegatedAmount.sub(endDelegatedAmount), 2000, "delegate's delegated amount did not decrease by bonded amount")
644623
})
624+
625+
it("should resign transcoder if caller is a registered transcoder", async () => {
626+
await bondingManager.unbond({from: tAddr})
627+
628+
assert.equal(await bondingManager.transcoderStatus(tAddr), 0, "transcoder not removed from pool")
629+
})
630+
631+
it("should set transcoder as inactive for the current round if caller is a registered transcoder", async () => {
632+
assert.isOk(await bondingManager.isActiveTranscoder(tAddr, currentRound), "transcoder should be active")
633+
634+
await bondingManager.unbond({from: tAddr})
635+
636+
assert.isNotOk(await bondingManager.isActiveTranscoder(tAddr, currentRound), "transcoder should be inactive")
637+
})
645638
})
646639

647640
describe("withdrawStake", () => {

0 commit comments

Comments
 (0)